On Tue, 2026-07-14 at 10:47 -0500, Bill Roberts wrote: > Historically, managing the user-space shadow stack state on x86 has > been handled exclusively through the arch_prctl() interface via the > ARCH_SHSTK_* operations. However, other architectures (such as arm64 and > riscv) do not implement arch_prctl() and instead utilize the newer, > arch-agnostic, prctl() interface (i.e. PR_GET_SHADOW_STACK_STATUS and > PR_SET_SHADOW_STACK_STATUS). > > To provide language runtimes, toolchains, and libc implementations with a > consistent, cross-architecture interface for managing control-flow > integrity, wire up the generic shadow stack prctl handlers for x86.
I think glibc doesn't handles this in arch code, right? So the point of this is only your SE Linux patches. Or is there other cross-arch code that wants to handle shadow stack? BTW, for non security module people, can you explain why it needs this design? > > Map the generic PR_SHADOW_STACK_ENABLE, PR_SHADOW_STACK_DISABLE, and > PR_SHADOW_STACK_LOCK operations onto the underlying x86 internal CET helper > routines. This allows portable userspace applications to toggle or query > shadow stack states without relying on architecture-specific system calls, > while maintaining backward compatibility with existing arch_prctl() calls. Can you explain why not to include ARCH_SHSTK_UNLOCK? https://lore.kernel.org/lkml/[email protected]/ > > Signed-off-by: Bill Roberts <[email protected]> > --- > arch/x86/kernel/shstk.c | 35 +++++++++++++++++++++++++++++++++++ > 1 file changed, 35 insertions(+) > > diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c > index 0ca64900192f..ef3db94eec6a 100644 > --- a/arch/x86/kernel/shstk.c > +++ b/arch/x86/kernel/shstk.c > @@ -18,6 +18,7 @@ > #include <linux/sizes.h> > #include <linux/user.h> > #include <linux/syscalls.h> > +#include <linux/prctl.h> > #include <asm/msr.h> > #include <asm/fpu/xstate.h> > #include <asm/fpu/types.h> > @@ -630,3 +631,37 @@ bool shstk_is_enabled(void) > { > return features_enabled(ARCH_SHSTK_SHSTK); > } > + > +/* We assume the prctl() feature bits line up with the arch_prctl() specific > ones. */ > +static_assert(PR_SHADOW_STACK_ENABLE == ARCH_SHSTK_SHSTK); > +static_assert(PR_SHADOW_STACK_WRITE == ARCH_SHSTK_WRSS); This is only needed for arch_get_shadow_stack_status()? So can we put it near by and explain why? > + > +/* Handles the generic prctl interface for PR_SET_SHADOW_STACK_STATUS and its > feature bits */ > +int arch_set_shadow_stack_status(struct task_struct *t, unsigned long status) > +{ > + int rc; It needs to reject invalid options for status. > + > + /* x86 arch_prctl is single bit at a time, so handle these one at > time */ > + if (!status & PR_SHADOW_STACK_ENABLE) > + return shstk_prctl(t, ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK); > + > + rc = shstk_prctl(t, ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK); > + if (rc) > + return rc; > + > + if (status & PR_SHADOW_STACK_WRITE) > + return shstk_prctl(t, ARCH_SHSTK_ENABLE, ARCH_SHSTK_WRSS); > + > + return shstk_prctl(t, ARCH_SHSTK_DISABLE, ARCH_SHSTK_WRSS); > +} > + > +/* Handles the generic prctl interface for PR_LOCK_SHADOW_STACK_STATUS and > its feature bits */ > +int arch_lock_shadow_stack_status(struct task_struct *t, unsigned long > status) > +{ > + return shstk_prctl(t, ARCH_SHSTK_LOCK, status); > +} > + > +int arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user > *status) > +{ > + return shstk_prctl(t, ARCH_SHSTK_STATUS, (unsigned long)status); > +}

