History

scs: switch to vmapped shadow stacks

The kernel currently uses kmem_cache to allocate shadow call stacks, which means an overflows may not be immediately detected and can potentially result in another task's shadow stack to be overwritten. This change switches SCS to use virtually mapped shadow stacks for tasks, which increases shadow stack size to a full page and provides more robust overflow detection, similarly to VMAP_STACK.

Sami Tolvanen committed 5 years ago

Commit a2abe7c1 parent f8394f22 files · +66 −17Browse files

Showing the changes to kernel (1 of 2 files). Show all

Unified · Split

kernel/scs.c+60−11
@@ -5,26 +5,49 @@ · 4 unmodified lines
55 * Copyright (C) 2019 Google LLC
66 */
77
8+#include <linux/cpuhotplug.h>
89 #include <linux/kasan.h>
910 #include <linux/mm.h>
1011 #include <linux/scs.h>
11−#include <linux/slab.h>
12+#include <linux/vmalloc.h>
1213 #include <linux/vmstat.h>
1314
14−static struct kmem_cache *scs_cache;
15−
1615 static void __scs_account(void *s, int account)
1716 {
18− struct page *scs_page = virt_to_page(s);
17+ struct page *scs_page = vmalloc_to_page(s);
1918
2019 mod_node_page_state(page_pgdat(scs_page), NR_KERNEL_SCS_KB,
2120 account * (SCS_SIZE / SZ_1K));
2221 }
2322
24−static void *scs_alloc(int node)
23+/* Matches NR_CACHED_STACKS for VMAP_STACK */
24+#define NR_CACHED_SCS 2
25+static DEFINE_PER_CPU(void *, scs_cache[NR_CACHED_SCS]);
26+
27+static void *__scs_alloc(int node)
2528 {
26− void *s = kmem_cache_alloc_node(scs_cache, GFP_SCS, node);
29+ int i;
30+ void *s;
31+
32+ for (i = 0; i < NR_CACHED_SCS; i++) {
33+ s = this_cpu_xchg(scs_cache[i], NULL);
34+ if (s) {
35+ kasan_unpoison_vmalloc(s, SCS_SIZE);
36+ memset(s, 0, SCS_SIZE);
37+ return s;
38+ }
39+ }
40+
41+ return __vmalloc_node_range(SCS_SIZE, 1, VMALLOC_START, VMALLOC_END,
42+ GFP_SCS, PAGE_KERNEL, 0, node,
43+ __builtin_return_address(0));
44+}
2745
46+void *scs_alloc(int node)
47+{
48+ void *s;
49+
50+ s = __scs_alloc(node);
2851 if (!s)
2952 return NULL;
3053
@@ -34,21 +57,47 @@ static void *scs_alloc(int node) · 3 unmodified lines
3457 * Poison the allocation to catch unintentional accesses to
3558 * the shadow stack when KASAN is enabled.
3659 */
37− kasan_poison_object_data(scs_cache, s);
60+ kasan_poison_vmalloc(s, SCS_SIZE);
3861 __scs_account(s, 1);
3962 return s;
4063 }
4164
42−static void scs_free(void *s)
65+void scs_free(void *s)
4366 {
67+ int i;
68+
4469 __scs_account(s, -1);
45− kasan_unpoison_object_data(scs_cache, s);
46− kmem_cache_free(scs_cache, s);
70+
71+ /*
72+ * We cannot sleep as this can be called in interrupt context,
73+ * so use this_cpu_cmpxchg to update the cache, and vfree_atomic
74+ * to free the stack.
75+ */
76+
77+ for (i = 0; i < NR_CACHED_SCS; i++)
78+ if (this_cpu_cmpxchg(scs_cache[i], 0, s) == NULL)
79+ return;
80+
81+ vfree_atomic(s);
82+}
83+
84+static int scs_cleanup(unsigned int cpu)
85+{
86+ int i;
87+ void **cache = per_cpu_ptr(scs_cache, cpu);
88+
89+ for (i = 0; i < NR_CACHED_SCS; i++) {
90+ vfree(cache[i]);
91+ cache[i] = NULL;
92+ }
93+
94+ return 0;
4795 }
4896
4997 void __init scs_init(void)
5098 {
51− scs_cache = kmem_cache_create("scs_cache", SCS_SIZE, 0, 0, NULL);
99+ cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "scs:scs_cache", NULL,
100+ scs_cleanup);
52101 }
53102
54103 int scs_prepare(struct task_struct *tsk, int node)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t