Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 9beccca

Browse files
ardbiesheuvelwilldeacon
authored andcommitted
scs: add support for dynamic shadow call stacks
In order to allow arches to use code patching to conditionally emit the shadow stack pushes and pops, rather than always taking the performance hit even on CPUs that implement alternatives such as stack pointer authentication on arm64, add a Kconfig symbol that can be set by the arch to omit the SCS codegen itself, without otherwise affecting how support code for SCS and compiler options (for register reservation, for instance) are emitted. Also, add a static key and some plumbing to omit the allocation of shadow call stack for dynamic SCS configurations if SCS is disabled at runtime. Signed-off-by: Ard Biesheuvel <[email protected]> Reviewed-by: Nick Desaulniers <[email protected]> Reviewed-by: Kees Cook <[email protected]> Reviewed-by: Sami Tolvanen <[email protected]> Tested-by: Sami Tolvanen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 68c76ad commit 9beccca

File tree

4 files changed

+39
-2
lines changed

4 files changed

+39
-2
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,8 +966,10 @@ LDFLAGS_vmlinux += --gc-sections
966966
endif
967967

968968
ifdef CONFIG_SHADOW_CALL_STACK
969+
ifndef CONFIG_DYNAMIC_SCS
969970
CC_FLAGS_SCS := -fsanitize=shadow-call-stack
970971
KBUILD_CFLAGS += $(CC_FLAGS_SCS)
972+
endif
971973
export CC_FLAGS_SCS
972974
endif
973975

arch/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,13 @@ config SHADOW_CALL_STACK
651651
reading and writing arbitrary memory may be able to locate them
652652
and hijack control flow by modifying the stacks.
653653

654+
config DYNAMIC_SCS
655+
bool
656+
help
657+
Set by the arch code if it relies on code patching to insert the
658+
shadow call stack push and pop instructions rather than on the
659+
compiler.
660+
654661
config LTO
655662
bool
656663
help

include/linux/scs.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,22 @@ static inline bool task_scs_end_corrupted(struct task_struct *tsk)
5353
return sz >= SCS_SIZE - 1 || READ_ONCE_NOCHECK(*magic) != SCS_END_MAGIC;
5454
}
5555

56+
DECLARE_STATIC_KEY_FALSE(dynamic_scs_enabled);
57+
58+
static inline bool scs_is_dynamic(void)
59+
{
60+
if (!IS_ENABLED(CONFIG_DYNAMIC_SCS))
61+
return false;
62+
return static_branch_likely(&dynamic_scs_enabled);
63+
}
64+
65+
static inline bool scs_is_enabled(void)
66+
{
67+
if (!IS_ENABLED(CONFIG_DYNAMIC_SCS))
68+
return true;
69+
return scs_is_dynamic();
70+
}
71+
5672
#else /* CONFIG_SHADOW_CALL_STACK */
5773

5874
static inline void *scs_alloc(int node) { return NULL; }
@@ -62,6 +78,8 @@ static inline void scs_task_reset(struct task_struct *tsk) {}
6278
static inline int scs_prepare(struct task_struct *tsk, int node) { return 0; }
6379
static inline void scs_release(struct task_struct *tsk) {}
6480
static inline bool task_scs_end_corrupted(struct task_struct *tsk) { return false; }
81+
static inline bool scs_is_enabled(void) { return false; }
82+
static inline bool scs_is_dynamic(void) { return false; }
6583

6684
#endif /* CONFIG_SHADOW_CALL_STACK */
6785

kernel/scs.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
#include <linux/vmalloc.h>
1313
#include <linux/vmstat.h>
1414

15+
#ifdef CONFIG_DYNAMIC_SCS
16+
DEFINE_STATIC_KEY_FALSE(dynamic_scs_enabled);
17+
#endif
18+
1519
static void __scs_account(void *s, int account)
1620
{
1721
struct page *scs_page = vmalloc_to_page(s);
@@ -101,14 +105,20 @@ static int scs_cleanup(unsigned int cpu)
101105

102106
void __init scs_init(void)
103107
{
108+
if (!scs_is_enabled())
109+
return;
104110
cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "scs:scs_cache", NULL,
105111
scs_cleanup);
106112
}
107113

108114
int scs_prepare(struct task_struct *tsk, int node)
109115
{
110-
void *s = scs_alloc(node);
116+
void *s;
111117

118+
if (!scs_is_enabled())
119+
return 0;
120+
121+
s = scs_alloc(node);
112122
if (!s)
113123
return -ENOMEM;
114124

@@ -148,7 +158,7 @@ void scs_release(struct task_struct *tsk)
148158
{
149159
void *s = task_scs(tsk);
150160

151-
if (!s)
161+
if (!scs_is_enabled() || !s)
152162
return;
153163

154164
WARN(task_scs_end_corrupted(tsk),

0 commit comments

Comments
 (0)