PCuABI enablement entails providing support for userspace capability pointers which are 128-bit long instead of 64-bit.
This commit implements the support for the futex_waitv syscall while maintaining the 64-bit compatibility.
Signed-off-by: Luca Vizzarro Luca.Vizzarro@arm.com --- Hello!
Submitting a patch resolving the following issue: https://git.morello-project.org/morello/kernel/linux/-/issues/48
You can find the commit on the following branch: https://git.morello-project.org/Sevenarth/linux/-/commits/morello/futex_wait...
Best, --- include/uapi/linux/futex.h | 2 +- kernel/futex/syscalls.c | 38 ++++++++++++++++++++++++++++++++++++-- kernel/futex/waitwake.c | 4 ++-- 3 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h index 71a5df8d2689..93f701d89401 100644 --- a/include/uapi/linux/futex.h +++ b/include/uapi/linux/futex.h @@ -63,7 +63,7 @@ */ struct futex_waitv { __u64 val; - __u64 uaddr; + __kernel_uintptr_t uaddr; __u32 flags; __u32 __reserved; }; diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c index ad4ae797bb84..6b389b16df16 100644 --- a/kernel/futex/syscalls.c +++ b/kernel/futex/syscalls.c @@ -190,6 +190,34 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, /* Mask of available flags for each futex in futex_waitv list */ #define FUTEXV_WAITER_MASK (FUTEX_32 | FUTEX_PRIVATE_FLAG)
+struct compat_futex_waitv { + __u64 val; + __u64 uaddr; + __u32 flags; + __u32 __reserved; +}; + +static int get_compat_futex_waitv(struct futex_waitv *waitv, + const struct futex_waitv __user *uwaitv) +{ + struct compat_futex_waitv compat_waitv; + + if (unlikely(copy_from_user(&compat_waitv, uwaitv, sizeof(compat_waitv)))) + return -EFAULT; + + waitv->val = compat_waitv.val; + waitv->uaddr = (__kernel_uintcap_t)compat_ptr(compat_waitv.uaddr); + waitv->flags = compat_waitv.flags; + waitv->__reserved = compat_waitv.__reserved; + + return 0; +} + +static inline bool in_compat64(void) +{ + return IS_ENABLED(CONFIG_COMPAT64) && in_compat_syscall(); +} + /** * futex_parse_waitv - Parse a waitv array from userspace * @futexv: Kernel side list of waiters to be filled @@ -204,10 +232,16 @@ static int futex_parse_waitv(struct futex_vector *futexv, { struct futex_waitv aux; unsigned int i; + bool compat = in_compat64();
for (i = 0; i < nr_futexes; i++) { - if (copy_from_user(&aux, &uwaitv[i], sizeof(aux))) - return -EFAULT; + if (compat) { + if (get_compat_futex_waitv(&aux, &uwaitv[i])) + return -EFAULT; + } else { + if (copy_from_user(&aux, &uwaitv[i], sizeof(aux))) + return -EFAULT; + }
if ((aux.flags & ~FUTEXV_WAITER_MASK) || aux.__reserved) return -EINVAL; diff --git a/kernel/futex/waitwake.c b/kernel/futex/waitwake.c index 1ab5640e7f84..d6b050356f81 100644 --- a/kernel/futex/waitwake.c +++ b/kernel/futex/waitwake.c @@ -422,7 +422,7 @@ static int futex_wait_multiple_setup(struct futex_vector *vs, int count, int *wo if ((vs[i].w.flags & FUTEX_PRIVATE_FLAG) && retry) continue;
- ret = get_futex_key(u64_to_user_ptr(vs[i].w.uaddr), + ret = get_futex_key((u32 __user *)vs[i].w.uaddr, !(vs[i].w.flags & FUTEX_PRIVATE_FLAG), &vs[i].q.key, FUTEX_READ);
@@ -433,7 +433,7 @@ static int futex_wait_multiple_setup(struct futex_vector *vs, int count, int *wo set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
for (i = 0; i < count; i++) { - u32 __user *uaddr = uaddr_to_user_ptr(vs[i].w.uaddr); + u32 __user *uaddr = (u32 __user *)vs[i].w.uaddr; struct futex_q *q = &vs[i].q; u32 val = (u32)vs[i].w.val;