On Wed, Nov 22, 2023 at 1:43 AM Mark Brown <broonie@xxxxxxxxxx> wrote: > > Three architectures (x86, aarch64, riscv) have announced support for > shadow stacks with fairly similar functionality. While x86 is using > arch_prctl() to control the functionality neither arm64 nor riscv uses > that interface so this patch adds arch-agnostic prctl() support to > get and set status of shadow stacks and lock the current configuation to > prevent further changes, with support for turning on and off individual > subfeatures so applications can limit their exposure to features that > they do not need. The features are: > > - PR_SHADOW_STACK_ENABLE: Tracking and enforcement of shadow stacks, > including allocation of a shadow stack if one is not already > allocated. > - PR_SHADOW_STACK_WRITE: Writes to specific addresses in the shadow > stack. > - PR_SHADOW_STACK_PUSH: Push additional values onto the shadow stack. > > These features are expected to be inherited by new threads and cleared > on exec(), unknown features should be rejected for enable but accepted > for locking (in order to allow for future proofing). > > This is based on a patch originally written by Deepak Gupta but modified > fairly heavily, support for indirect landing pads is removed, additional > modes added and the locking interface reworked. The set status prctl() > is also reworked to just set flags, if setting/reading the shadow stack > pointer is required this could be a separate prctl. > > Signed-off-by: Mark Brown <broonie@xxxxxxxxxx> > --- > include/linux/mm.h | 4 ++++ > include/uapi/linux/prctl.h | 22 ++++++++++++++++++++++ > kernel/sys.c | 30 ++++++++++++++++++++++++++++++ > 3 files changed, 56 insertions(+) > > diff --git a/include/linux/mm.h b/include/linux/mm.h > index 10462f354614..8b28483b4afa 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -4143,4 +4143,8 @@ static inline bool pfn_is_unaccepted_memory(unsigned long pfn) > return range_contains_unaccepted_memory(paddr, paddr + PAGE_SIZE); > } > > +int arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status); > +int arch_set_shadow_stack_status(struct task_struct *t, unsigned long status); > +int arch_lock_shadow_stack_status(struct task_struct *t, unsigned long status); > + > #endif /* _LINUX_MM_H */ > diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h > index 370ed14b1ae0..3c66ed8f46d8 100644 > --- a/include/uapi/linux/prctl.h > +++ b/include/uapi/linux/prctl.h > @@ -306,4 +306,26 @@ struct prctl_mm_map { > # define PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 0xc > # define PR_RISCV_V_VSTATE_CTRL_MASK 0x1f > > +/* > + * Get the current shadow stack configuration for the current thread, > + * this will be the value configured via PR_SET_SHADOW_STACK_STATUS. > + */ > +#define PR_GET_SHADOW_STACK_STATUS 71 > + > +/* > + * Set the current shadow stack configuration. Enabling the shadow > + * stack will cause a shadow stack to be allocated for the thread. > + */ > +#define PR_SET_SHADOW_STACK_STATUS 72 > +# define PR_SHADOW_STACK_ENABLE (1UL << 0) Other architecture may require disabling shadow stack if glibc tunables is set to permissive mode. In permissive mode, if glibc encounters `dlopen` on an object which doesn't support shadow stack, glibc should be able to issue PR_SHADOW_STACK_DISABLE. Architectures can choose to implement or not but I think arch agnostic code should enumerate this. > +# define PR_SHADOW_STACK_WRITE (1UL << 1) > +# define PR_SHADOW_STACK_PUSH (1UL << 2) > + > +/* > + * Prevent further changes to the specified shadow stack > + * configuration. All bits may be locked via this call, including > + * undefined bits. > + */