Mark Brown <broonie@xxxxxxxxxx> writes: > Provide a new register type NT_ARM_GCS reporting the current GCS mode > and pointer for EL0. Due to the interactions with allocation and > deallocation of Guarded Control Stacks we do not permit any changes to > the GCS mode via ptrace, only GCSPR_EL0 may be changed. The code allows disabling GCS. Is that unintended? > Signed-off-by: Mark Brown <broonie@xxxxxxxxxx> > --- > arch/arm64/include/uapi/asm/ptrace.h | 8 +++++ > arch/arm64/kernel/ptrace.c | 59 ++++++++++++++++++++++++++++++++++++ > include/uapi/linux/elf.h | 1 + > 3 files changed, 68 insertions(+) > > diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h > index 7fa2f7036aa7..0f39ba4f3efd 100644 > --- a/arch/arm64/include/uapi/asm/ptrace.h > +++ b/arch/arm64/include/uapi/asm/ptrace.h > @@ -324,6 +324,14 @@ struct user_za_header { > #define ZA_PT_SIZE(vq) \ > (ZA_PT_ZA_OFFSET + ZA_PT_ZA_SIZE(vq)) > > +/* GCS state (NT_ARM_GCS) */ > + > +struct user_gcs { > + __u64 features_enabled; > + __u64 features_locked; > + __u64 gcspr_el0; > +}; If there's a reserved field in sigframe's gcs_context, isn't it worth it to have a reserved field here as well? > + > #endif /* __ASSEMBLY__ */ > > #endif /* _UAPI__ASM_PTRACE_H */ > diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c > index 20d7ef82de90..f15b8e33561e 100644 > --- a/arch/arm64/kernel/ptrace.c > +++ b/arch/arm64/kernel/ptrace.c > @@ -33,6 +33,7 @@ > #include <asm/cpufeature.h> > #include <asm/debug-monitors.h> > #include <asm/fpsimd.h> > +#include <asm/gcs.h> > #include <asm/mte.h> > #include <asm/pointer_auth.h> > #include <asm/stacktrace.h> > @@ -1409,6 +1410,51 @@ static int tagged_addr_ctrl_set(struct task_struct *target, const struct > } > #endif > > +#ifdef CONFIG_ARM64_GCS > +static int gcs_get(struct task_struct *target, > + const struct user_regset *regset, > + struct membuf to) > +{ > + struct user_gcs user_gcs; > + > + if (target == current) > + gcs_preserve_current_state(); > + > + user_gcs.features_enabled = target->thread.gcs_el0_mode; > + user_gcs.features_locked = target->thread.gcs_el0_locked; > + user_gcs.gcspr_el0 = target->thread.gcspr_el0; > + > + return membuf_write(&to, &user_gcs, sizeof(user_gcs)); > +} > + > +static int gcs_set(struct task_struct *target, const struct > + user_regset *regset, unsigned int pos, > + unsigned int count, const void *kbuf, const > + void __user *ubuf) > +{ > + int ret; > + struct user_gcs user_gcs; > + > + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &user_gcs, 0, -1); > + if (ret) > + return ret; > + > + if (user_gcs.features_enabled & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK) > + return -EINVAL; > + > + /* Do not allow enable via ptrace */ > + if ((user_gcs.features_enabled & PR_SHADOW_STACK_ENABLE) && > + !!(target->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE)) There should be only one '!' above. Though contrary to the patch description, this code allows disabling GCS. Shouldn't we require that (user_gcs.features_enabled & PR_SHADOW_STACK_ENABLE) == (target->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE) ? That would ensure that the GCS mode can't be changed. > + return -EBUSY; > + > + target->thread.gcs_el0_mode = user_gcs.features_enabled; > + target->thread.gcs_el0_locked = user_gcs.features_locked; > + target->thread.gcspr_el0 = user_gcs.gcspr_el0; > + > + return 0; > +} > +#endif -- Thiago