aboutsummaryrefslogtreecommitdiffstats
path: root/lib/test_kasan.c
diff options
context:
space:
mode:
authorAndrey Ryabinin <a.ryabinin@samsung.com>2015-02-13 17:39:53 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-14 00:21:41 -0500
commit3f15801cdc2379ca4bf507f48bffd788f9e508ae (patch)
treec68cb1fca11e009d293d3784d49125f8bf1a77b6 /lib/test_kasan.c
parente79ed2f13faab8fc9d4ad76d5f5a241724e45836 (diff)
lib: add kasan test module
This is a test module doing various nasty things like out of bounds accesses, use after free. It is useful for testing kernel debugging features like kernel address sanitizer. It mostly concentrates on testing of slab allocator, but we might want to add more different stuff here in future (like stack/global variables out of bounds accesses and so on). Signed-off-by: Andrey Ryabinin <a.ryabinin@samsung.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Konstantin Serebryany <kcc@google.com> Cc: Dmitry Chernenkov <dmitryc@google.com> Signed-off-by: Andrey Konovalov <adech.fo@gmail.com> Cc: Yuri Gribov <tetra2005@gmail.com> Cc: Konstantin Khlebnikov <koct9i@gmail.com> Cc: Sasha Levin <sasha.levin@oracle.com> Cc: Christoph Lameter <cl@linux.com> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Christoph Lameter <cl@linux.com> Cc: Pekka Enberg <penberg@kernel.org> Cc: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib/test_kasan.c')
-rw-r--r--lib/test_kasan.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/lib/test_kasan.c b/lib/test_kasan.c
new file mode 100644
index 000000000000..098c08eddfab
--- /dev/null
+++ b/lib/test_kasan.c
@@ -0,0 +1,277 @@
1/*
2 *
3 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#define pr_fmt(fmt) "kasan test: %s " fmt, __func__
13
14#include <linux/kernel.h>
15#include <linux/printk.h>
16#include <linux/slab.h>
17#include <linux/string.h>
18#include <linux/module.h>
19
20static noinline void __init kmalloc_oob_right(void)
21{
22 char *ptr;
23 size_t size = 123;
24
25 pr_info("out-of-bounds to right\n");
26 ptr = kmalloc(size, GFP_KERNEL);
27 if (!ptr) {
28 pr_err("Allocation failed\n");
29 return;
30 }
31
32 ptr[size] = 'x';
33 kfree(ptr);
34}
35
36static noinline void __init kmalloc_oob_left(void)
37{
38 char *ptr;
39 size_t size = 15;
40
41 pr_info("out-of-bounds to left\n");
42 ptr = kmalloc(size, GFP_KERNEL);
43 if (!ptr) {
44 pr_err("Allocation failed\n");
45 return;
46 }
47
48 *ptr = *(ptr - 1);
49 kfree(ptr);
50}
51
52static noinline void __init kmalloc_node_oob_right(void)
53{
54 char *ptr;
55 size_t size = 4096;
56
57 pr_info("kmalloc_node(): out-of-bounds to right\n");
58 ptr = kmalloc_node(size, GFP_KERNEL, 0);
59 if (!ptr) {
60 pr_err("Allocation failed\n");
61 return;
62 }
63
64 ptr[size] = 0;
65 kfree(ptr);
66}
67
68static noinline void __init kmalloc_large_oob_rigth(void)
69{
70 char *ptr;
71 size_t size = KMALLOC_MAX_CACHE_SIZE + 10;
72
73 pr_info("kmalloc large allocation: out-of-bounds to right\n");
74 ptr = kmalloc(size, GFP_KERNEL);
75 if (!ptr) {
76 pr_err("Allocation failed\n");
77 return;
78 }
79
80 ptr[size] = 0;
81 kfree(ptr);
82}
83
84static noinline void __init kmalloc_oob_krealloc_more(void)
85{
86 char *ptr1, *ptr2;
87 size_t size1 = 17;
88 size_t size2 = 19;
89
90 pr_info("out-of-bounds after krealloc more\n");
91 ptr1 = kmalloc(size1, GFP_KERNEL);
92 ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
93 if (!ptr1 || !ptr2) {
94 pr_err("Allocation failed\n");
95 kfree(ptr1);
96 return;
97 }
98
99 ptr2[size2] = 'x';
100 kfree(ptr2);
101}
102
103static noinline void __init kmalloc_oob_krealloc_less(void)
104{
105 char *ptr1, *ptr2;
106 size_t size1 = 17;
107 size_t size2 = 15;
108
109 pr_info("out-of-bounds after krealloc less\n");
110 ptr1 = kmalloc(size1, GFP_KERNEL);
111 ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
112 if (!ptr1 || !ptr2) {
113 pr_err("Allocation failed\n");
114 kfree(ptr1);
115 return;
116 }
117 ptr2[size1] = 'x';
118 kfree(ptr2);
119}
120
121static noinline void __init kmalloc_oob_16(void)
122{
123 struct {
124 u64 words[2];
125 } *ptr1, *ptr2;
126
127 pr_info("kmalloc out-of-bounds for 16-bytes access\n");
128 ptr1 = kmalloc(sizeof(*ptr1) - 3, GFP_KERNEL);
129 ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL);
130 if (!ptr1 || !ptr2) {
131 pr_err("Allocation failed\n");
132 kfree(ptr1);
133 kfree(ptr2);
134 return;
135 }
136 *ptr1 = *ptr2;
137 kfree(ptr1);
138 kfree(ptr2);
139}
140
141static noinline void __init kmalloc_oob_in_memset(void)
142{
143 char *ptr;
144 size_t size = 666;
145
146 pr_info("out-of-bounds in memset\n");
147 ptr = kmalloc(size, GFP_KERNEL);
148 if (!ptr) {
149 pr_err("Allocation failed\n");
150 return;
151 }
152
153 memset(ptr, 0, size+5);
154 kfree(ptr);
155}
156
157static noinline void __init kmalloc_uaf(void)
158{
159 char *ptr;
160 size_t size = 10;
161
162 pr_info("use-after-free\n");
163 ptr = kmalloc(size, GFP_KERNEL);
164 if (!ptr) {
165 pr_err("Allocation failed\n");
166 return;
167 }
168
169 kfree(ptr);
170 *(ptr + 8) = 'x';
171}
172
173static noinline void __init kmalloc_uaf_memset(void)
174{
175 char *ptr;
176 size_t size = 33;
177
178 pr_info("use-after-free in memset\n");
179 ptr = kmalloc(size, GFP_KERNEL);
180 if (!ptr) {
181 pr_err("Allocation failed\n");
182 return;
183 }
184
185 kfree(ptr);
186 memset(ptr, 0, size);
187}
188
189static noinline void __init kmalloc_uaf2(void)
190{
191 char *ptr1, *ptr2;
192 size_t size = 43;
193
194 pr_info("use-after-free after another kmalloc\n");
195 ptr1 = kmalloc(size, GFP_KERNEL);
196 if (!ptr1) {
197 pr_err("Allocation failed\n");
198 return;
199 }
200
201 kfree(ptr1);
202 ptr2 = kmalloc(size, GFP_KERNEL);
203 if (!ptr2) {
204 pr_err("Allocation failed\n");
205 return;
206 }
207
208 ptr1[40] = 'x';
209 kfree(ptr2);
210}
211
212static noinline void __init kmem_cache_oob(void)
213{
214 char *p;
215 size_t size = 200;
216 struct kmem_cache *cache = kmem_cache_create("test_cache",
217 size, 0,
218 0, NULL);
219 if (!cache) {
220 pr_err("Cache allocation failed\n");
221 return;
222 }
223 pr_info("out-of-bounds in kmem_cache_alloc\n");
224 p = kmem_cache_alloc(cache, GFP_KERNEL);
225 if (!p) {
226 pr_err("Allocation failed\n");
227 kmem_cache_destroy(cache);
228 return;
229 }
230
231 *p = p[size];
232 kmem_cache_free(cache, p);
233 kmem_cache_destroy(cache);
234}
235
236static char global_array[10];
237
238static noinline void __init kasan_global_oob(void)
239{
240 volatile int i = 3;
241 char *p = &global_array[ARRAY_SIZE(global_array) + i];
242
243 pr_info("out-of-bounds global variable\n");
244 *(volatile char *)p;
245}
246
247static noinline void __init kasan_stack_oob(void)
248{
249 char stack_array[10];
250 volatile int i = 0;
251 char *p = &stack_array[ARRAY_SIZE(stack_array) + i];
252
253 pr_info("out-of-bounds on stack\n");
254 *(volatile char *)p;
255}
256
257static int __init kmalloc_tests_init(void)
258{
259 kmalloc_oob_right();
260 kmalloc_oob_left();
261 kmalloc_node_oob_right();
262 kmalloc_large_oob_rigth();
263 kmalloc_oob_krealloc_more();
264 kmalloc_oob_krealloc_less();
265 kmalloc_oob_16();
266 kmalloc_oob_in_memset();
267 kmalloc_uaf();
268 kmalloc_uaf_memset();
269 kmalloc_uaf2();
270 kmem_cache_oob();
271 kasan_stack_oob();
272 kasan_global_oob();
273 return -EAGAIN;
274}
275
276module_init(kmalloc_tests_init);
277MODULE_LICENSE("GPL");