Changeset View
Changeset View
Standalone View
Standalone View
sys/compat/linux/linux_futex.c
Show First 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | struct linux_futex_args { | ||||
uint32_t val; | uint32_t val; | ||||
struct timespec *ts; | struct timespec *ts; | ||||
uint32_t *uaddr2; | uint32_t *uaddr2; | ||||
uint32_t val3; | uint32_t val3; | ||||
bool val3_compare; | bool val3_compare; | ||||
struct timespec kts; | struct timespec kts; | ||||
}; | }; | ||||
static inline int futex_key_get(const void *, int, int, struct umtx_key *); | |||||
static void linux_umtx_abs_timeout_init(struct umtx_abs_timeout *, | static void linux_umtx_abs_timeout_init(struct umtx_abs_timeout *, | ||||
struct linux_futex_args *); | struct linux_futex_args *); | ||||
static int linux_futex(struct thread *, struct linux_futex_args *); | static int linux_futex(struct thread *, struct linux_futex_args *); | ||||
static int linux_futex_wait(struct thread *, struct linux_futex_args *); | static int linux_futex_wait(struct thread *, struct linux_futex_args *); | ||||
static int linux_futex_wake(struct thread *, struct linux_futex_args *); | static int linux_futex_wake(struct thread *, struct linux_futex_args *); | ||||
static int linux_futex_requeue(struct thread *, struct linux_futex_args *); | static int linux_futex_requeue(struct thread *, struct linux_futex_args *); | ||||
static int linux_futex_wakeop(struct thread *, struct linux_futex_args *); | static int linux_futex_wakeop(struct thread *, struct linux_futex_args *); | ||||
static int linux_futex_lock_pi(struct thread *, bool, struct linux_futex_args *); | static int linux_futex_lock_pi(struct thread *, bool, struct linux_futex_args *); | ||||
static int linux_futex_unlock_pi(struct thread *, bool, | static int linux_futex_unlock_pi(struct thread *, bool, | ||||
struct linux_futex_args *); | struct linux_futex_args *); | ||||
static int futex_wake_pi(struct thread *, uint32_t *, bool); | static int futex_wake_pi(struct thread *, uint32_t *, bool); | ||||
static int | |||||
futex_key_get(const void *uaddr, int type, int share, struct umtx_key *key) | |||||
{ | |||||
/* Check that futex address is a 32bit aligned. */ | |||||
if (!__is_aligned(uaddr, sizeof(uint32_t))) | |||||
return (EINVAL); | |||||
return (umtx_key_get(uaddr, type, share, key)); | |||||
} | |||||
int | int | ||||
futex_wake(struct thread *td, uint32_t *uaddr, int val, bool shared) | futex_wake(struct thread *td, uint32_t *uaddr, int val, bool shared) | ||||
{ | { | ||||
struct linux_futex_args args; | struct linux_futex_args args; | ||||
bzero(&args, sizeof(args)); | bzero(&args, sizeof(args)); | ||||
args.op = LINUX_FUTEX_WAKE; | args.op = LINUX_FUTEX_WAKE; | ||||
args.uaddr = uaddr; | args.uaddr = uaddr; | ||||
▲ Show 20 Lines • Show All 251 Lines • ▼ Show 20 Lines | linux_futex_lock_pi(struct thread *td, bool try, struct linux_futex_args *args) | ||||
struct umtx_pi *pi, *new_pi; | struct umtx_pi *pi, *new_pi; | ||||
struct thread *td1; | struct thread *td1; | ||||
struct umtx_q *uq; | struct umtx_q *uq; | ||||
int error, rv; | int error, rv; | ||||
uint32_t owner, old_owner; | uint32_t owner, old_owner; | ||||
em = em_find(td); | em = em_find(td); | ||||
uq = td->td_umtxq; | uq = td->td_umtxq; | ||||
error = umtx_key_get(args->uaddr, TYPE_PI_FUTEX, GET_SHARED(args), | error = futex_key_get(args->uaddr, TYPE_PI_FUTEX, GET_SHARED(args), | ||||
&uq->uq_key); | &uq->uq_key); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
if (args->ts != NULL) | if (args->ts != NULL) | ||||
linux_umtx_abs_timeout_init(&timo, args); | linux_umtx_abs_timeout_init(&timo, args); | ||||
umtxq_lock(&uq->uq_key); | umtxq_lock(&uq->uq_key); | ||||
pi = umtx_pi_lookup(&uq->uq_key); | pi = umtx_pi_lookup(&uq->uq_key); | ||||
▲ Show 20 Lines • Show All 190 Lines • ▼ Show 20 Lines | linux_futex_unlock_pi(struct thread *td, bool rb, struct linux_futex_args *args) | ||||
* Make sure we own this mtx. | * Make sure we own this mtx. | ||||
*/ | */ | ||||
error = fueword32(args->uaddr, &owner); | error = fueword32(args->uaddr, &owner); | ||||
if (error == -1) | if (error == -1) | ||||
return (EFAULT); | return (EFAULT); | ||||
if (!rb && (owner & FUTEX_TID_MASK) != em->em_tid) | if (!rb && (owner & FUTEX_TID_MASK) != em->em_tid) | ||||
return (EPERM); | return (EPERM); | ||||
error = umtx_key_get(args->uaddr, TYPE_PI_FUTEX, GET_SHARED(args), &key); | error = futex_key_get(args->uaddr, TYPE_PI_FUTEX, GET_SHARED(args), &key); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
umtxq_lock(&key); | umtxq_lock(&key); | ||||
umtxq_busy(&key); | umtxq_busy(&key); | ||||
error = umtx_pi_drop(td, &key, rb, &count); | error = umtx_pi_drop(td, &key, rb, &count); | ||||
if (error != 0 || rb) { | if (error != 0 || rb) { | ||||
umtxq_unbusy(&key); | umtxq_unbusy(&key); | ||||
umtxq_unlock(&key); | umtxq_unlock(&key); | ||||
Show All 33 Lines | |||||
{ | { | ||||
struct umtx_key key, key2; | struct umtx_key key, key2; | ||||
int nrwake, op_ret, ret; | int nrwake, op_ret, ret; | ||||
int error, count; | int error, count; | ||||
if (args->uaddr == args->uaddr2) | if (args->uaddr == args->uaddr2) | ||||
return (EINVAL); | return (EINVAL); | ||||
error = umtx_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); | error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
error = umtx_key_get(args->uaddr2, TYPE_FUTEX, GET_SHARED(args), &key2); | error = futex_key_get(args->uaddr2, TYPE_FUTEX, GET_SHARED(args), &key2); | ||||
if (error != 0) { | if (error != 0) { | ||||
umtx_key_release(&key); | umtx_key_release(&key); | ||||
return (error); | return (error); | ||||
} | } | ||||
umtxq_lock(&key); | umtxq_lock(&key); | ||||
umtxq_busy(&key); | umtxq_busy(&key); | ||||
umtxq_unlock(&key); | umtxq_unlock(&key); | ||||
op_ret = futex_atomic_op(td, args->val3, args->uaddr2); | op_ret = futex_atomic_op(td, args->val3, args->uaddr2); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | linux_futex_requeue(struct thread *td, struct linux_futex_args *args) | ||||
nrwake = args->val; | nrwake = args->val; | ||||
/* | /* | ||||
* Sanity check to prevent signed integer overflow, | * Sanity check to prevent signed integer overflow, | ||||
* see Linux CVE-2018-6927 | * see Linux CVE-2018-6927 | ||||
*/ | */ | ||||
if (nrwake < 0 || nrrequeue < 0) | if (nrwake < 0 || nrrequeue < 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
error = umtx_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); | error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
error = umtx_key_get(args->uaddr2, TYPE_FUTEX, GET_SHARED(args), &key2); | error = futex_key_get(args->uaddr2, TYPE_FUTEX, GET_SHARED(args), &key2); | ||||
if (error != 0) { | if (error != 0) { | ||||
umtx_key_release(&key); | umtx_key_release(&key); | ||||
return (error); | return (error); | ||||
} | } | ||||
umtxq_lock(&key); | umtxq_lock(&key); | ||||
umtxq_busy(&key); | umtxq_busy(&key); | ||||
umtxq_unlock(&key); | umtxq_unlock(&key); | ||||
error = fueword32(args->uaddr, &uval); | error = fueword32(args->uaddr, &uval); | ||||
Show All 18 Lines | |||||
linux_futex_wake(struct thread *td, struct linux_futex_args *args) | linux_futex_wake(struct thread *td, struct linux_futex_args *args) | ||||
{ | { | ||||
struct umtx_key key; | struct umtx_key key; | ||||
int error; | int error; | ||||
if (args->val3 == 0) | if (args->val3 == 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
error = umtx_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); | error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
umtxq_lock(&key); | umtxq_lock(&key); | ||||
td->td_retval[0] = umtxq_signal_mask(&key, args->val, args->val3); | td->td_retval[0] = umtxq_signal_mask(&key, args->val, args->val3); | ||||
umtxq_unlock(&key); | umtxq_unlock(&key); | ||||
umtx_key_release(&key); | umtx_key_release(&key); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
linux_futex_wait(struct thread *td, struct linux_futex_args *args) | linux_futex_wait(struct thread *td, struct linux_futex_args *args) | ||||
{ | { | ||||
struct umtx_abs_timeout timo; | struct umtx_abs_timeout timo; | ||||
struct umtx_q *uq; | struct umtx_q *uq; | ||||
uint32_t uval; | uint32_t uval; | ||||
int error; | int error; | ||||
if (args->val3 == 0) | if (args->val3 == 0) | ||||
error = EINVAL; | error = EINVAL; | ||||
uq = td->td_umtxq; | uq = td->td_umtxq; | ||||
error = umtx_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), | error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), | ||||
&uq->uq_key); | &uq->uq_key); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
if (args->ts != NULL) | if (args->ts != NULL) | ||||
linux_umtx_abs_timeout_init(&timo, args); | linux_umtx_abs_timeout_init(&timo, args); | ||||
umtxq_lock(&uq->uq_key); | umtxq_lock(&uq->uq_key); | ||||
umtxq_busy(&uq->uq_key); | umtxq_busy(&uq->uq_key); | ||||
uq->uq_bitset = args->val3; | uq->uq_bitset = args->val3; | ||||
▲ Show 20 Lines • Show All 295 Lines • Show Last 20 Lines |