Message ID | 20241001-arm64-gcs-v13-4-222b78d87eee@kernel.org |
---|---|
State | Accepted |
Commit | 91e102e79740ae43ded050ccac71aa3371db4f33 |
Headers | show |
Series | arm64/gcs: Provide support for GCS in userspace | expand |
On Tue, Oct 01, 2024 at 11:58:43PM +0100, Mark Brown 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. > >Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org> >Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> >Acked-by: Yury Khrustalev <yury.khrustalev@arm.com> >Signed-off-by: Mark Brown <broonie@kernel.org> >--- > include/linux/mm.h | 4 ++++ > include/uapi/linux/prctl.h | 22 ++++++++++++++++++++++ > kernel/sys.c | 30 ++++++++++++++++++++++++++++++ > 3 files changed, 56 insertions(+) Reviewed-by: Deepak Gupta <debug@rivosinc.com> >
diff --git a/include/linux/mm.h b/include/linux/mm.h index 182bad0c55df..56654306a832 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -4221,4 +4221,8 @@ static inline void pgalloc_tag_copy(struct folio *new, struct folio *old) } #endif /* CONFIG_MEM_ALLOC_PROFILING */ +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 35791791a879..557a3d2ac1d4 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -328,4 +328,26 @@ struct prctl_mm_map { # define PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC 0x10 /* Clear the aspect on exec */ # define PR_PPC_DEXCR_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 74 + +/* + * 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 75 +# define PR_SHADOW_STACK_ENABLE (1UL << 0) +# 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. + */ +#define PR_LOCK_SHADOW_STACK_STATUS 76 + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/sys.c b/kernel/sys.c index 4da31f28fda8..3d38a9c7c5c9 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2324,6 +2324,21 @@ int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which, return -EINVAL; } +int __weak arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status) +{ + return -EINVAL; +} + +int __weak arch_set_shadow_stack_status(struct task_struct *t, unsigned long status) +{ + return -EINVAL; +} + +int __weak arch_lock_shadow_stack_status(struct task_struct *t, unsigned long status) +{ + return -EINVAL; +} + #define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LOCAL_THROTTLE) #ifdef CONFIG_ANON_VMA_NAME @@ -2784,6 +2799,21 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, case PR_RISCV_SET_ICACHE_FLUSH_CTX: error = RISCV_SET_ICACHE_FLUSH_CTX(arg2, arg3); break; + case PR_GET_SHADOW_STACK_STATUS: + if (arg3 || arg4 || arg5) + return -EINVAL; + error = arch_get_shadow_stack_status(me, (unsigned long __user *) arg2); + break; + case PR_SET_SHADOW_STACK_STATUS: + if (arg3 || arg4 || arg5) + return -EINVAL; + error = arch_set_shadow_stack_status(me, arg2); + break; + case PR_LOCK_SHADOW_STACK_STATUS: + if (arg3 || arg4 || arg5) + return -EINVAL; + error = arch_lock_shadow_stack_status(me, arg2); + break; default: error = -EINVAL; break;