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 v3 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.
v3: - updated the copy_from_user function to copy_from_user_with_ptr for purecap 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..771cfb51a38d 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_with_ptr(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 21/07/2023 15:51, 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 v3 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.
Applied on next, thanks! The kernel headers indeed need to be updated, for now I cancelled the pipeline. I will retrigger it once they are regenerated.
Kevin
v3:
- updated the copy_from_user function to copy_from_user_with_ptr for purecap
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..771cfb51a38d 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_with_ptr(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);
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