diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h --- a/include/uapi/linux/futex.h +++ b/include/uapi/linux/futex.h @@ -134,7 +134,7 @@ * @bitset: Bitset for the optional bitmasked wakeup */ struct futex_wait_block { - __u32 __user *uaddr; + __aligned_u64 uaddr; __u32 val; __u32 bitset; }; diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c --- a/kernel/futex/syscalls.c +++ b/kernel/futex/syscalls.c @@ -198,7 +198,8 @@ * initialize the fields) and then, for each futex_wait_block element from * userspace, fill a futex_q element with proper values. */ -static inline struct futex_vector *futex_read_wait_block(u32 __user *uaddr, u32 count) +static inline struct futex_vector *futex_read_wait_block(u32 __user *uaddr, u32 count, + unsigned int flags) { unsigned int i; struct futex_vector *futexv; @@ -219,10 +220,17 @@ return ERR_PTR(-EFAULT); } - futexv[i].w.flags = FUTEX_32; + if (!fwb.bitset) { + kfree(futexv); + return ERR_PTR(-EINVAL); + } + + futexv[i].w.flags = flags; futexv[i].w.val = fwb.val; - futexv[i].w.uaddr = (uintptr_t) (fwb.uaddr); + futexv[i].w.uaddr = fwb.uaddr; futexv[i].q = futex_q_init; + futexv[i].q.bitset = fwb.bitset; + futexv[i].q.wake = futex_wake_mark; } return futexv; @@ -231,17 +239,21 @@ int futex_wait_multiple(struct futex_vector *vs, unsigned int count, struct hrtimer_sleeper *to); -static int futex_opcode_31(ktime_t *abs_time, u32 __user *uaddr, int count) +static int futex_opcode_31(ktime_t *abs_time, u32 __user *uaddr, int count, int op) { int ret; struct futex_vector *vs; struct hrtimer_sleeper *to = NULL, timeout; + unsigned int flags = futex_to_flags(op); + + if (flags & FLAGS_CLOCKRT) + return -ENOSYS; - vs = futex_read_wait_block(uaddr, count); + vs = futex_read_wait_block(uaddr, count, flags); if (IS_ERR(vs)) return PTR_ERR(vs); - to = futex_setup_timer(abs_time, &timeout, 0, 0); + to = futex_setup_timer(abs_time, &timeout, flags, current->timer_slack_ns); ret = futex_wait_multiple(vs, count, abs_time ? to : NULL); kfree(vs); @@ -274,7 +286,7 @@ } if (cmd == FUTEX_WAIT_MULTIPLE) - return futex_opcode_31(tp, uaddr, val); + return futex_opcode_31(tp, uaddr, val, op); return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3); } @@ -591,7 +603,7 @@ } if (cmd == FUTEX_WAIT_MULTIPLE) - return futex_opcode_31(tp, uaddr, val); + return futex_opcode_31(tp, uaddr, val, op); return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3); }