In PCuABI, ptrace(PTRACE_SETREGSET, REGSET_TLS) currently sets the capability thread pointer (CTPIDR) to a 64-bit value, zeroing any existing capability. This is unlikely to be the desired behaviour, and is inconsistent with the register merging principle, which the other ptrace operations obey. For instance, setting a new value for SP using ptrace(PTRACE_SETREGSET, REGSET_GPR) does not zero CSP, but instead sets its address to the provided value.
Unlike other capability registers like CSP, CTPIDR is stored only as a capability (in tp_value). We therefore need to perform the X/C register merging manually. The corresponding function from morello.c is exposed in asm/morello.h for that purpose.
Signed-off-by: Kevin Brodsky kevin.brodsky@arm.com --- arch/arm64/include/asm/morello.h | 6 ++++++ arch/arm64/kernel/morello.c | 20 ++++++++++---------- arch/arm64/kernel/ptrace.c | 6 +++++- 3 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/arch/arm64/include/asm/morello.h b/arch/arm64/include/asm/morello.h index da198622b35e..8281e1aaf37f 100644 --- a/arch/arm64/include/asm/morello.h +++ b/arch/arm64/include/asm/morello.h @@ -25,6 +25,12 @@ struct morello_state {
void morello_cap_get_val_tag(uintcap_t cap, __uint128_t *val, u8 *tag);
+/* + * Merge a 64-bit value into a capability (typically an X register into a C + * register). + */ +void morello_merge_cap_xval(uintcap_t *creg, u64 xreg); + /* * Builds a user capability from a 128-bit pattern + tag. The capability will * be derived from cheri_user_root_allperms_cap and the object type will be diff --git a/arch/arm64/kernel/morello.c b/arch/arm64/kernel/morello.c index 7e14ff42db68..6e18fdb22646 100644 --- a/arch/arm64/kernel/morello.c +++ b/arch/arm64/kernel/morello.c @@ -36,12 +36,6 @@ static void cap_lo_hi_tag(uintcap_t cap, u64 *lo_val, u64 *hi_val, *tag = cheri_tag_get(cap); }
-static void merge_c_x(uintcap_t *creg, u64 xreg) -{ - if (cheri_address_get(*creg) != xreg) - *creg = cheri_address_set(*creg, xreg); -} - static bool cap_has_executive(uintcap_t cap) { return cheri_perms_get(cap) & ARM_CAP_PERMISSION_EXECUTIVE; @@ -71,6 +65,12 @@ void morello_cap_get_val_tag(uintcap_t cap, __uint128_t *val, u8 *tag) *tag = cheri_tag_get(cap); }
+void morello_merge_cap_xval(uintcap_t *creg, u64 xreg) +{ + if (cheri_address_get(*creg) != xreg) + *creg = cheri_address_set(*creg, xreg); +} + uintcap_t morello_build_any_user_cap(const __uint128_t *val, u8 tag) { uintcap_t cap = *((uintcap_t *)val); @@ -194,7 +194,7 @@ void morello_task_restore_user_tls(struct task_struct *tsk, #ifdef CONFIG_CHERI_PURECAP_UABI *active_ctpidr = *tp_ptr; #else - merge_c_x(active_ctpidr, *tp_ptr); + morello_merge_cap_xval(active_ctpidr, *tp_ptr); #endif
write_cap_sysreg(morello_state->ctpidr, ctpidr_el0); @@ -370,10 +370,10 @@ void morello_merge_cap_regs(struct pt_regs *regs) active_csp = ®s->rcsp;
for (i = 0; i < ARRAY_SIZE(regs->cregs); i++) - merge_c_x(®s->cregs[i], regs->regs[i]); + morello_merge_cap_xval(®s->cregs[i], regs->regs[i]);
- merge_c_x(active_csp, regs->sp); - merge_c_x(®s->pcc, regs->pc); + morello_merge_cap_xval(active_csp, regs->sp); + morello_merge_cap_xval(®s->pcc, regs->pc); }
void morello_flush_cap_regs_to_64_regs(struct task_struct *tsk) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index c7c8e43eacbe..be1faed4908e 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -691,7 +691,11 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset, if (ret) return ret;
- target->thread.uw.tp_value = (user_uintptr_t)tls[0]; +#ifdef CONFIG_CHERI_PURECAP_UABI + morello_merge_cap_xval(&target->thread.uw.tp_value, tls[0]); +#else + target->thread.uw.tp_value = tls[0]; +#endif if (system_supports_tpidr2()) target->thread.tpidr2_el0 = tls[1];
On 12/04/2024 13:59, Kevin Brodsky wrote:
In PCuABI, ptrace(PTRACE_SETREGSET, REGSET_TLS) currently sets the capability thread pointer (CTPIDR) to a 64-bit value, zeroing any existing capability. This is unlikely to be the desired behaviour, and is inconsistent with the register merging principle, which the other ptrace operations obey. For instance, setting a new value for SP using ptrace(PTRACE_SETREGSET, REGSET_GPR) does not zero CSP, but instead sets its address to the provided value.
Unlike other capability registers like CSP, CTPIDR is stored only as a capability (in tp_value). We therefore need to perform the X/C register merging manually. The corresponding function from morello.c is exposed in asm/morello.h for that purpose.
Signed-off-by: Kevin Brodsky kevin.brodsky@arm.com
arch/arm64/include/asm/morello.h | 6 ++++++ arch/arm64/kernel/morello.c | 20 ++++++++++---------- arch/arm64/kernel/ptrace.c | 6 +++++- 3 files changed, 21 insertions(+), 11 deletions(-)
Applied on next.
Kevin
diff --git a/arch/arm64/include/asm/morello.h b/arch/arm64/include/asm/morello.h index da198622b35e..8281e1aaf37f 100644 --- a/arch/arm64/include/asm/morello.h +++ b/arch/arm64/include/asm/morello.h @@ -25,6 +25,12 @@ struct morello_state { void morello_cap_get_val_tag(uintcap_t cap, __uint128_t *val, u8 *tag); +/*
- Merge a 64-bit value into a capability (typically an X register into a C
- register).
- */
+void morello_merge_cap_xval(uintcap_t *creg, u64 xreg);
/*
- Builds a user capability from a 128-bit pattern + tag. The capability will
- be derived from cheri_user_root_allperms_cap and the object type will be
diff --git a/arch/arm64/kernel/morello.c b/arch/arm64/kernel/morello.c index 7e14ff42db68..6e18fdb22646 100644 --- a/arch/arm64/kernel/morello.c +++ b/arch/arm64/kernel/morello.c @@ -36,12 +36,6 @@ static void cap_lo_hi_tag(uintcap_t cap, u64 *lo_val, u64 *hi_val, *tag = cheri_tag_get(cap); } -static void merge_c_x(uintcap_t *creg, u64 xreg) -{
- if (cheri_address_get(*creg) != xreg)
*creg = cheri_address_set(*creg, xreg);
-}
static bool cap_has_executive(uintcap_t cap) { return cheri_perms_get(cap) & ARM_CAP_PERMISSION_EXECUTIVE; @@ -71,6 +65,12 @@ void morello_cap_get_val_tag(uintcap_t cap, __uint128_t *val, u8 *tag) *tag = cheri_tag_get(cap); } +void morello_merge_cap_xval(uintcap_t *creg, u64 xreg) +{
- if (cheri_address_get(*creg) != xreg)
*creg = cheri_address_set(*creg, xreg);
+}
uintcap_t morello_build_any_user_cap(const __uint128_t *val, u8 tag) { uintcap_t cap = *((uintcap_t *)val); @@ -194,7 +194,7 @@ void morello_task_restore_user_tls(struct task_struct *tsk, #ifdef CONFIG_CHERI_PURECAP_UABI *active_ctpidr = *tp_ptr; #else
- merge_c_x(active_ctpidr, *tp_ptr);
- morello_merge_cap_xval(active_ctpidr, *tp_ptr);
#endif write_cap_sysreg(morello_state->ctpidr, ctpidr_el0); @@ -370,10 +370,10 @@ void morello_merge_cap_regs(struct pt_regs *regs) active_csp = ®s->rcsp; for (i = 0; i < ARRAY_SIZE(regs->cregs); i++)
merge_c_x(®s->cregs[i], regs->regs[i]);
morello_merge_cap_xval(®s->cregs[i], regs->regs[i]);
- merge_c_x(active_csp, regs->sp);
- merge_c_x(®s->pcc, regs->pc);
- morello_merge_cap_xval(active_csp, regs->sp);
- morello_merge_cap_xval(®s->pcc, regs->pc);
} void morello_flush_cap_regs_to_64_regs(struct task_struct *tsk) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index c7c8e43eacbe..be1faed4908e 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -691,7 +691,11 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset, if (ret) return ret;
- target->thread.uw.tp_value = (user_uintptr_t)tls[0];
+#ifdef CONFIG_CHERI_PURECAP_UABI
- morello_merge_cap_xval(&target->thread.uw.tp_value, tls[0]);
+#else
- target->thread.uw.tp_value = tls[0];
+#endif if (system_supports_tpidr2()) target->thread.tpidr2_el0 = tls[1];
linux-morello@op-lists.linaro.org