Skip to content

Commit 91e102e

Browse files
brooniectmarinas
authored andcommitted
prctl: arch-agnostic prctl for shadow stack
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 <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Acked-by: Yury Khrustalev <[email protected]> Signed-off-by: Mark Brown <[email protected]> Reviewed-by: Deepak Gupta <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent f645e88 commit 91e102e

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

include/linux/mm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4221,4 +4221,8 @@ static inline void pgalloc_tag_copy(struct folio *new, struct folio *old)
42214221
}
42224222
#endif /* CONFIG_MEM_ALLOC_PROFILING */
42234223

4224+
int arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status);
4225+
int arch_set_shadow_stack_status(struct task_struct *t, unsigned long status);
4226+
int arch_lock_shadow_stack_status(struct task_struct *t, unsigned long status);
4227+
42244228
#endif /* _LINUX_MM_H */

include/uapi/linux/prctl.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,4 +328,26 @@ struct prctl_mm_map {
328328
# define PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC 0x10 /* Clear the aspect on exec */
329329
# define PR_PPC_DEXCR_CTRL_MASK 0x1f
330330

331+
/*
332+
* Get the current shadow stack configuration for the current thread,
333+
* this will be the value configured via PR_SET_SHADOW_STACK_STATUS.
334+
*/
335+
#define PR_GET_SHADOW_STACK_STATUS 74
336+
337+
/*
338+
* Set the current shadow stack configuration. Enabling the shadow
339+
* stack will cause a shadow stack to be allocated for the thread.
340+
*/
341+
#define PR_SET_SHADOW_STACK_STATUS 75
342+
# define PR_SHADOW_STACK_ENABLE (1UL << 0)
343+
# define PR_SHADOW_STACK_WRITE (1UL << 1)
344+
# define PR_SHADOW_STACK_PUSH (1UL << 2)
345+
346+
/*
347+
* Prevent further changes to the specified shadow stack
348+
* configuration. All bits may be locked via this call, including
349+
* undefined bits.
350+
*/
351+
#define PR_LOCK_SHADOW_STACK_STATUS 76
352+
331353
#endif /* _LINUX_PRCTL_H */

kernel/sys.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2324,6 +2324,21 @@ int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which,
23242324
return -EINVAL;
23252325
}
23262326

2327+
int __weak arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status)
2328+
{
2329+
return -EINVAL;
2330+
}
2331+
2332+
int __weak arch_set_shadow_stack_status(struct task_struct *t, unsigned long status)
2333+
{
2334+
return -EINVAL;
2335+
}
2336+
2337+
int __weak arch_lock_shadow_stack_status(struct task_struct *t, unsigned long status)
2338+
{
2339+
return -EINVAL;
2340+
}
2341+
23272342
#define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LOCAL_THROTTLE)
23282343

23292344
#ifdef CONFIG_ANON_VMA_NAME
@@ -2784,6 +2799,21 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
27842799
case PR_RISCV_SET_ICACHE_FLUSH_CTX:
27852800
error = RISCV_SET_ICACHE_FLUSH_CTX(arg2, arg3);
27862801
break;
2802+
case PR_GET_SHADOW_STACK_STATUS:
2803+
if (arg3 || arg4 || arg5)
2804+
return -EINVAL;
2805+
error = arch_get_shadow_stack_status(me, (unsigned long __user *) arg2);
2806+
break;
2807+
case PR_SET_SHADOW_STACK_STATUS:
2808+
if (arg3 || arg4 || arg5)
2809+
return -EINVAL;
2810+
error = arch_set_shadow_stack_status(me, arg2);
2811+
break;
2812+
case PR_LOCK_SHADOW_STACK_STATUS:
2813+
if (arg3 || arg4 || arg5)
2814+
return -EINVAL;
2815+
error = arch_lock_shadow_stack_status(me, arg2);
2816+
break;
27872817
default:
27882818
error = -EINVAL;
27892819
break;

0 commit comments

Comments
 (0)