diff options
author | Kees Cook <keescook@chromium.org> | 2019-07-11 23:53:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-12 14:05:41 -0400 |
commit | 966fede8e4be15bcc08e3c390080d3f9072a5367 (patch) | |
tree | 93fcad54232f4e760a1d5bd6ae6ecf1ba1e5a7f7 /drivers/misc | |
parent | a64b53780ec35b77daf817210c88aa42d172c98f (diff) |
lkdtm/heap: add tests for freelist hardening
This adds tests for double free and cross-cache freeing, which should both
be caught by CONFIG_SLAB_FREELIST_HARDENED.
Link: http://lkml.kernel.org/r/20190530045017.15252-4-keescook@chromium.org
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Alexander Popov <alex.popov@linux.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Pekka Enberg <penberg@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/lkdtm/core.c | 5 | ||||
-rw-r--r-- | drivers/misc/lkdtm/heap.c | 72 | ||||
-rw-r--r-- | drivers/misc/lkdtm/lkdtm.h | 5 |
3 files changed, 82 insertions, 0 deletions
diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index bba49abb6750..c7a507482051 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c | |||
@@ -120,6 +120,9 @@ static const struct crashtype crashtypes[] = { | |||
120 | CRASHTYPE(READ_AFTER_FREE), | 120 | CRASHTYPE(READ_AFTER_FREE), |
121 | CRASHTYPE(WRITE_BUDDY_AFTER_FREE), | 121 | CRASHTYPE(WRITE_BUDDY_AFTER_FREE), |
122 | CRASHTYPE(READ_BUDDY_AFTER_FREE), | 122 | CRASHTYPE(READ_BUDDY_AFTER_FREE), |
123 | CRASHTYPE(SLAB_FREE_DOUBLE), | ||
124 | CRASHTYPE(SLAB_FREE_CROSS), | ||
125 | CRASHTYPE(SLAB_FREE_PAGE), | ||
123 | CRASHTYPE(SOFTLOCKUP), | 126 | CRASHTYPE(SOFTLOCKUP), |
124 | CRASHTYPE(HARDLOCKUP), | 127 | CRASHTYPE(HARDLOCKUP), |
125 | CRASHTYPE(SPINLOCKUP), | 128 | CRASHTYPE(SPINLOCKUP), |
@@ -426,6 +429,7 @@ static int __init lkdtm_module_init(void) | |||
426 | lkdtm_bugs_init(&recur_count); | 429 | lkdtm_bugs_init(&recur_count); |
427 | lkdtm_perms_init(); | 430 | lkdtm_perms_init(); |
428 | lkdtm_usercopy_init(); | 431 | lkdtm_usercopy_init(); |
432 | lkdtm_heap_init(); | ||
429 | 433 | ||
430 | /* Register debugfs interface */ | 434 | /* Register debugfs interface */ |
431 | lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); | 435 | lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); |
@@ -472,6 +476,7 @@ static void __exit lkdtm_module_exit(void) | |||
472 | debugfs_remove_recursive(lkdtm_debugfs_root); | 476 | debugfs_remove_recursive(lkdtm_debugfs_root); |
473 | 477 | ||
474 | /* Handle test-specific clean-up. */ | 478 | /* Handle test-specific clean-up. */ |
479 | lkdtm_heap_exit(); | ||
475 | lkdtm_usercopy_exit(); | 480 | lkdtm_usercopy_exit(); |
476 | 481 | ||
477 | if (lkdtm_kprobe != NULL) | 482 | if (lkdtm_kprobe != NULL) |
diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c index 65026d7de130..3c5cec85edce 100644 --- a/drivers/misc/lkdtm/heap.c +++ b/drivers/misc/lkdtm/heap.c | |||
@@ -7,6 +7,10 @@ | |||
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | #include <linux/sched.h> | 8 | #include <linux/sched.h> |
9 | 9 | ||
10 | static struct kmem_cache *double_free_cache; | ||
11 | static struct kmem_cache *a_cache; | ||
12 | static struct kmem_cache *b_cache; | ||
13 | |||
10 | /* | 14 | /* |
11 | * This tries to stay within the next largest power-of-2 kmalloc cache | 15 | * This tries to stay within the next largest power-of-2 kmalloc cache |
12 | * to avoid actually overwriting anything important if it's not detected | 16 | * to avoid actually overwriting anything important if it's not detected |
@@ -146,3 +150,71 @@ void lkdtm_READ_BUDDY_AFTER_FREE(void) | |||
146 | 150 | ||
147 | kfree(val); | 151 | kfree(val); |
148 | } | 152 | } |
153 | |||
154 | void lkdtm_SLAB_FREE_DOUBLE(void) | ||
155 | { | ||
156 | int *val; | ||
157 | |||
158 | val = kmem_cache_alloc(double_free_cache, GFP_KERNEL); | ||
159 | if (!val) { | ||
160 | pr_info("Unable to allocate double_free_cache memory.\n"); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | /* Just make sure we got real memory. */ | ||
165 | *val = 0x12345678; | ||
166 | pr_info("Attempting double slab free ...\n"); | ||
167 | kmem_cache_free(double_free_cache, val); | ||
168 | kmem_cache_free(double_free_cache, val); | ||
169 | } | ||
170 | |||
171 | void lkdtm_SLAB_FREE_CROSS(void) | ||
172 | { | ||
173 | int *val; | ||
174 | |||
175 | val = kmem_cache_alloc(a_cache, GFP_KERNEL); | ||
176 | if (!val) { | ||
177 | pr_info("Unable to allocate a_cache memory.\n"); | ||
178 | return; | ||
179 | } | ||
180 | |||
181 | /* Just make sure we got real memory. */ | ||
182 | *val = 0x12345679; | ||
183 | pr_info("Attempting cross-cache slab free ...\n"); | ||
184 | kmem_cache_free(b_cache, val); | ||
185 | } | ||
186 | |||
187 | void lkdtm_SLAB_FREE_PAGE(void) | ||
188 | { | ||
189 | unsigned long p = __get_free_page(GFP_KERNEL); | ||
190 | |||
191 | pr_info("Attempting non-Slab slab free ...\n"); | ||
192 | kmem_cache_free(NULL, (void *)p); | ||
193 | free_page(p); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * We have constructors to keep the caches distinctly separated without | ||
198 | * needing to boot with "slab_nomerge". | ||
199 | */ | ||
200 | static void ctor_double_free(void *region) | ||
201 | { } | ||
202 | static void ctor_a(void *region) | ||
203 | { } | ||
204 | static void ctor_b(void *region) | ||
205 | { } | ||
206 | |||
207 | void __init lkdtm_heap_init(void) | ||
208 | { | ||
209 | double_free_cache = kmem_cache_create("lkdtm-heap-double_free", | ||
210 | 64, 0, 0, ctor_double_free); | ||
211 | a_cache = kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a); | ||
212 | b_cache = kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b); | ||
213 | } | ||
214 | |||
215 | void __exit lkdtm_heap_exit(void) | ||
216 | { | ||
217 | kmem_cache_destroy(double_free_cache); | ||
218 | kmem_cache_destroy(a_cache); | ||
219 | kmem_cache_destroy(b_cache); | ||
220 | } | ||
diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index 23dc565b4307..c5ae0b37587d 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h | |||
@@ -28,11 +28,16 @@ void lkdtm_STACK_GUARD_PAGE_LEADING(void); | |||
28 | void lkdtm_STACK_GUARD_PAGE_TRAILING(void); | 28 | void lkdtm_STACK_GUARD_PAGE_TRAILING(void); |
29 | 29 | ||
30 | /* lkdtm_heap.c */ | 30 | /* lkdtm_heap.c */ |
31 | void __init lkdtm_heap_init(void); | ||
32 | void __exit lkdtm_heap_exit(void); | ||
31 | void lkdtm_OVERWRITE_ALLOCATION(void); | 33 | void lkdtm_OVERWRITE_ALLOCATION(void); |
32 | void lkdtm_WRITE_AFTER_FREE(void); | 34 | void lkdtm_WRITE_AFTER_FREE(void); |
33 | void lkdtm_READ_AFTER_FREE(void); | 35 | void lkdtm_READ_AFTER_FREE(void); |
34 | void lkdtm_WRITE_BUDDY_AFTER_FREE(void); | 36 | void lkdtm_WRITE_BUDDY_AFTER_FREE(void); |
35 | void lkdtm_READ_BUDDY_AFTER_FREE(void); | 37 | void lkdtm_READ_BUDDY_AFTER_FREE(void); |
38 | void lkdtm_SLAB_FREE_DOUBLE(void); | ||
39 | void lkdtm_SLAB_FREE_CROSS(void); | ||
40 | void lkdtm_SLAB_FREE_PAGE(void); | ||
36 | 41 | ||
37 | /* lkdtm_perms.c */ | 42 | /* lkdtm_perms.c */ |
38 | void __init lkdtm_perms_init(void); | 43 | void __init lkdtm_perms_init(void); |