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!
Sending in patch v2 for issue #48: https://git.morello-project.org/morello/kernel/linux/-/issues/48
Here you can find a branch with this patch: https://git.morello-project.org/Sevenarth/linux/-/commits/morello/futex_wait...
LTP fully passes. For the CI this fails only on the purecap tests since there has been a change in the linux headers. Therefore LTP would need to be recompiled against this for it to work.
v2 changes: - fixes bug where the offset of the futex_waitv list was always dependent on the size of the purecap struct instead of adapting to the compat one accordingly. - fixes the pointer cast in compat appropriately. It was mistakenly using __kernel_uintcap_t instead of __kernel_uintptr_t.
Best, Luca --- include/uapi/linux/futex.h | 2 +- kernel/futex/syscalls.c | 32 +++++++++++++++++++++++++++++++- kernel/futex/waitwake.c | 4 ++-- 3 files changed, 34 insertions(+), 4 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..c2e4529083a3 100644 --- a/kernel/futex/syscalls.c +++ b/kernel/futex/syscalls.c @@ -190,6 +190,36 @@ 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 copy_futex_waitv_from_user(struct futex_waitv *aux, + const struct futex_waitv __user *uwaitv, + unsigned int i) +{ + if (IS_ENABLED(CONFIG_COMPAT64) && in_compat_syscall()) { + const struct compat_futex_waitv __user *compat_uwaitv = + (const struct compat_futex_waitv __user *)uwaitv; + struct compat_futex_waitv compat_aux; + + if (copy_from_user(&compat_aux, &compat_uwaitv[i], sizeof(compat_aux))) + return -EFAULT; + + aux->val = compat_aux.val; + aux->uaddr = (__kernel_uintptr_t)compat_ptr(compat_aux.uaddr); + aux->flags = compat_aux.flags; + aux->__reserved = compat_aux.__reserved; + + return 0; + } + + return copy_from_user(aux, &uwaitv[i], sizeof(*aux)); +} + /** * futex_parse_waitv - Parse a waitv array from userspace * @futexv: Kernel side list of waiters to be filled @@ -206,7 +236,7 @@ static int futex_parse_waitv(struct futex_vector *futexv, unsigned int i;
for (i = 0; i < nr_futexes; i++) { - if (copy_from_user(&aux, &uwaitv[i], sizeof(aux))) + if (copy_futex_waitv_from_user(&aux, uwaitv, i)) return -EFAULT;
if ((aux.flags & ~FUTEXV_WAITER_MASK) || aux.__reserved) 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;
On 20-07-2023 14:55, Luca Vizzarro wrote:
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!
Sending in patch v2 for issue #48: https://git.morello-project.org/morello/kernel/linux/-/issues/48
Here you can find a branch with this patch: https://git.morello-project.org/Sevenarth/linux/-/commits/morello/futex_wait...
LTP fully passes. For the CI this fails only on the purecap tests since there has been a change in the linux headers. Therefore LTP would need to be recompiled against this for it to work.
v2 changes:
- fixes bug where the offset of the futex_waitv list was always dependent on the size of the purecap struct instead of adapting to the compat one accordingly.
- fixes the pointer cast in compat appropriately. It was mistakenly using __kernel_uintcap_t instead of __kernel_uintptr_t.
Best, Luca
include/uapi/linux/futex.h | 2 +- kernel/futex/syscalls.c | 32 +++++++++++++++++++++++++++++++- kernel/futex/waitwake.c | 4 ++-- 3 files changed, 34 insertions(+), 4 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..c2e4529083a3 100644 --- a/kernel/futex/syscalls.c +++ b/kernel/futex/syscalls.c @@ -190,6 +190,36 @@ 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 copy_futex_waitv_from_user(struct futex_waitv *aux,
const struct futex_waitv __user *uwaitv,
unsigned int i)
+{
- if (IS_ENABLED(CONFIG_COMPAT64) && in_compat_syscall()) {
const struct compat_futex_waitv __user *compat_uwaitv =
(const struct compat_futex_waitv __user *)uwaitv;
struct compat_futex_waitv compat_aux;
if (copy_from_user(&compat_aux, &compat_uwaitv[i], sizeof(compat_aux)))
return -EFAULT;
aux->val = compat_aux.val;
aux->uaddr = (__kernel_uintptr_t)compat_ptr(compat_aux.uaddr);
aux->flags = compat_aux.flags;
aux->__reserved = compat_aux.__reserved;
return 0;
- }
- return copy_from_user(aux, &uwaitv[i], sizeof(*aux));
You probably want copy_from_user_with_ptr() here.
The rest looks good to me. Well done!
Tudor
+}
- /**
- futex_parse_waitv - Parse a waitv array from userspace
- @futexv: Kernel side list of waiters to be filled
@@ -206,7 +236,7 @@ static int futex_parse_waitv(struct futex_vector *futexv, unsigned int i; for (i = 0; i < nr_futexes; i++) {
if (copy_from_user(&aux, &uwaitv[i], sizeof(aux)))
if (copy_futex_waitv_from_user(&aux, uwaitv, i)) return -EFAULT;
if ((aux.flags & ~FUTEXV_WAITER_MASK) || aux.__reserved) 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);
struct futex_q *q = &vs[i].q; u32 val = (u32)vs[i].w.val;u32 __user *uaddr = (u32 __user *)vs[i].w.uaddr;
linux-morello@op-lists.linaro.org