diff options
author | Alexander Popov <alex.popov@linux.com> | 2018-08-16 18:17:03 -0400 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2018-09-04 13:35:48 -0400 |
commit | 964c9dff0091893a9a74a88edf984c6da0b779f7 (patch) | |
tree | 162d45af3ac44401db524294e67e396ddee476f4 /kernel | |
parent | ed535a2dae1836d15c71e250475952881265d244 (diff) |
stackleak: Allow runtime disabling of kernel stack erasing
Introduce CONFIG_STACKLEAK_RUNTIME_DISABLE option, which provides
'stack_erasing' sysctl. It can be used in runtime to control kernel
stack erasing for kernels built with CONFIG_GCC_PLUGIN_STACKLEAK.
Suggested-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Alexander Popov <alex.popov@linux.com>
Tested-by: Laura Abbott <labbott@redhat.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/stackleak.c | 38 | ||||
-rw-r--r-- | kernel/sysctl.c | 15 |
2 files changed, 52 insertions, 1 deletions
diff --git a/kernel/stackleak.c b/kernel/stackleak.c index f66239572c89..e42892926244 100644 --- a/kernel/stackleak.c +++ b/kernel/stackleak.c | |||
@@ -12,6 +12,41 @@ | |||
12 | 12 | ||
13 | #include <linux/stackleak.h> | 13 | #include <linux/stackleak.h> |
14 | 14 | ||
15 | #ifdef CONFIG_STACKLEAK_RUNTIME_DISABLE | ||
16 | #include <linux/jump_label.h> | ||
17 | #include <linux/sysctl.h> | ||
18 | |||
19 | static DEFINE_STATIC_KEY_FALSE(stack_erasing_bypass); | ||
20 | |||
21 | int stack_erasing_sysctl(struct ctl_table *table, int write, | ||
22 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
23 | { | ||
24 | int ret = 0; | ||
25 | int state = !static_branch_unlikely(&stack_erasing_bypass); | ||
26 | int prev_state = state; | ||
27 | |||
28 | table->data = &state; | ||
29 | table->maxlen = sizeof(int); | ||
30 | ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | ||
31 | state = !!state; | ||
32 | if (ret || !write || state == prev_state) | ||
33 | return ret; | ||
34 | |||
35 | if (state) | ||
36 | static_branch_disable(&stack_erasing_bypass); | ||
37 | else | ||
38 | static_branch_enable(&stack_erasing_bypass); | ||
39 | |||
40 | pr_warn("stackleak: kernel stack erasing is %s\n", | ||
41 | state ? "enabled" : "disabled"); | ||
42 | return ret; | ||
43 | } | ||
44 | |||
45 | #define skip_erasing() static_branch_unlikely(&stack_erasing_bypass) | ||
46 | #else | ||
47 | #define skip_erasing() false | ||
48 | #endif /* CONFIG_STACKLEAK_RUNTIME_DISABLE */ | ||
49 | |||
15 | asmlinkage void stackleak_erase(void) | 50 | asmlinkage void stackleak_erase(void) |
16 | { | 51 | { |
17 | /* It would be nice not to have 'kstack_ptr' and 'boundary' on stack */ | 52 | /* It would be nice not to have 'kstack_ptr' and 'boundary' on stack */ |
@@ -20,6 +55,9 @@ asmlinkage void stackleak_erase(void) | |||
20 | unsigned int poison_count = 0; | 55 | unsigned int poison_count = 0; |
21 | const unsigned int depth = STACKLEAK_SEARCH_DEPTH / sizeof(unsigned long); | 56 | const unsigned int depth = STACKLEAK_SEARCH_DEPTH / sizeof(unsigned long); |
22 | 57 | ||
58 | if (skip_erasing()) | ||
59 | return; | ||
60 | |||
23 | /* Check that 'lowest_stack' value is sane */ | 61 | /* Check that 'lowest_stack' value is sane */ |
24 | if (unlikely(kstack_ptr - boundary >= THREAD_SIZE)) | 62 | if (unlikely(kstack_ptr - boundary >= THREAD_SIZE)) |
25 | kstack_ptr = boundary; | 63 | kstack_ptr = boundary; |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index cc02050fd0c4..3ae223f7b5df 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -91,7 +91,9 @@ | |||
91 | #ifdef CONFIG_CHR_DEV_SG | 91 | #ifdef CONFIG_CHR_DEV_SG |
92 | #include <scsi/sg.h> | 92 | #include <scsi/sg.h> |
93 | #endif | 93 | #endif |
94 | 94 | #ifdef CONFIG_STACKLEAK_RUNTIME_DISABLE | |
95 | #include <linux/stackleak.h> | ||
96 | #endif | ||
95 | #ifdef CONFIG_LOCKUP_DETECTOR | 97 | #ifdef CONFIG_LOCKUP_DETECTOR |
96 | #include <linux/nmi.h> | 98 | #include <linux/nmi.h> |
97 | #endif | 99 | #endif |
@@ -1233,6 +1235,17 @@ static struct ctl_table kern_table[] = { | |||
1233 | .extra2 = &one, | 1235 | .extra2 = &one, |
1234 | }, | 1236 | }, |
1235 | #endif | 1237 | #endif |
1238 | #ifdef CONFIG_STACKLEAK_RUNTIME_DISABLE | ||
1239 | { | ||
1240 | .procname = "stack_erasing", | ||
1241 | .data = NULL, | ||
1242 | .maxlen = sizeof(int), | ||
1243 | .mode = 0600, | ||
1244 | .proc_handler = stack_erasing_sysctl, | ||
1245 | .extra1 = &zero, | ||
1246 | .extra2 = &one, | ||
1247 | }, | ||
1248 | #endif | ||
1236 | { } | 1249 | { } |
1237 | }; | 1250 | }; |
1238 | 1251 | ||