]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - lib/test_kasan.c
Merge remote-tracking branch 'remotes/stable/linux-4.4.y' into karo-tx6-mainline
[karo-tx-linux.git] / lib / test_kasan.c
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
20 static 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
36 static 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
52 static 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
68 static noinline void __init kmalloc_large_oob_right(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
84 static 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
103 static 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[size2] = 'x';
118         kfree(ptr2);
119 }
120
121 static 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
141 static noinline void __init kmalloc_oob_memset_2(void)
142 {
143         char *ptr;
144         size_t size = 8;
145
146         pr_info("out-of-bounds in memset2\n");
147         ptr = kmalloc(size, GFP_KERNEL);
148         if (!ptr) {
149                 pr_err("Allocation failed\n");
150                 return;
151         }
152
153         memset(ptr+7, 0, 2);
154         kfree(ptr);
155 }
156
157 static noinline void __init kmalloc_oob_memset_4(void)
158 {
159         char *ptr;
160         size_t size = 8;
161
162         pr_info("out-of-bounds in memset4\n");
163         ptr = kmalloc(size, GFP_KERNEL);
164         if (!ptr) {
165                 pr_err("Allocation failed\n");
166                 return;
167         }
168
169         memset(ptr+5, 0, 4);
170         kfree(ptr);
171 }
172
173
174 static noinline void __init kmalloc_oob_memset_8(void)
175 {
176         char *ptr;
177         size_t size = 8;
178
179         pr_info("out-of-bounds in memset8\n");
180         ptr = kmalloc(size, GFP_KERNEL);
181         if (!ptr) {
182                 pr_err("Allocation failed\n");
183                 return;
184         }
185
186         memset(ptr+1, 0, 8);
187         kfree(ptr);
188 }
189
190 static noinline void __init kmalloc_oob_memset_16(void)
191 {
192         char *ptr;
193         size_t size = 16;
194
195         pr_info("out-of-bounds in memset16\n");
196         ptr = kmalloc(size, GFP_KERNEL);
197         if (!ptr) {
198                 pr_err("Allocation failed\n");
199                 return;
200         }
201
202         memset(ptr+1, 0, 16);
203         kfree(ptr);
204 }
205
206 static noinline void __init kmalloc_oob_in_memset(void)
207 {
208         char *ptr;
209         size_t size = 666;
210
211         pr_info("out-of-bounds in memset\n");
212         ptr = kmalloc(size, GFP_KERNEL);
213         if (!ptr) {
214                 pr_err("Allocation failed\n");
215                 return;
216         }
217
218         memset(ptr, 0, size+5);
219         kfree(ptr);
220 }
221
222 static noinline void __init kmalloc_uaf(void)
223 {
224         char *ptr;
225         size_t size = 10;
226
227         pr_info("use-after-free\n");
228         ptr = kmalloc(size, GFP_KERNEL);
229         if (!ptr) {
230                 pr_err("Allocation failed\n");
231                 return;
232         }
233
234         kfree(ptr);
235         *(ptr + 8) = 'x';
236 }
237
238 static noinline void __init kmalloc_uaf_memset(void)
239 {
240         char *ptr;
241         size_t size = 33;
242
243         pr_info("use-after-free in memset\n");
244         ptr = kmalloc(size, GFP_KERNEL);
245         if (!ptr) {
246                 pr_err("Allocation failed\n");
247                 return;
248         }
249
250         kfree(ptr);
251         memset(ptr, 0, size);
252 }
253
254 static noinline void __init kmalloc_uaf2(void)
255 {
256         char *ptr1, *ptr2;
257         size_t size = 43;
258
259         pr_info("use-after-free after another kmalloc\n");
260         ptr1 = kmalloc(size, GFP_KERNEL);
261         if (!ptr1) {
262                 pr_err("Allocation failed\n");
263                 return;
264         }
265
266         kfree(ptr1);
267         ptr2 = kmalloc(size, GFP_KERNEL);
268         if (!ptr2) {
269                 pr_err("Allocation failed\n");
270                 return;
271         }
272
273         ptr1[40] = 'x';
274         kfree(ptr2);
275 }
276
277 static noinline void __init kmem_cache_oob(void)
278 {
279         char *p;
280         size_t size = 200;
281         struct kmem_cache *cache = kmem_cache_create("test_cache",
282                                                 size, 0,
283                                                 0, NULL);
284         if (!cache) {
285                 pr_err("Cache allocation failed\n");
286                 return;
287         }
288         pr_info("out-of-bounds in kmem_cache_alloc\n");
289         p = kmem_cache_alloc(cache, GFP_KERNEL);
290         if (!p) {
291                 pr_err("Allocation failed\n");
292                 kmem_cache_destroy(cache);
293                 return;
294         }
295
296         *p = p[size];
297         kmem_cache_free(cache, p);
298         kmem_cache_destroy(cache);
299 }
300
301 static char global_array[10];
302
303 static noinline void __init kasan_global_oob(void)
304 {
305         volatile int i = 3;
306         char *p = &global_array[ARRAY_SIZE(global_array) + i];
307
308         pr_info("out-of-bounds global variable\n");
309         *(volatile char *)p;
310 }
311
312 static noinline void __init kasan_stack_oob(void)
313 {
314         char stack_array[10];
315         volatile int i = 0;
316         char *p = &stack_array[ARRAY_SIZE(stack_array) + i];
317
318         pr_info("out-of-bounds on stack\n");
319         *(volatile char *)p;
320 }
321
322 static int __init kmalloc_tests_init(void)
323 {
324         kmalloc_oob_right();
325         kmalloc_oob_left();
326         kmalloc_node_oob_right();
327         kmalloc_large_oob_right();
328         kmalloc_oob_krealloc_more();
329         kmalloc_oob_krealloc_less();
330         kmalloc_oob_16();
331         kmalloc_oob_in_memset();
332         kmalloc_oob_memset_2();
333         kmalloc_oob_memset_4();
334         kmalloc_oob_memset_8();
335         kmalloc_oob_memset_16();
336         kmalloc_uaf();
337         kmalloc_uaf_memset();
338         kmalloc_uaf2();
339         kmem_cache_oob();
340         kasan_stack_oob();
341         kasan_global_oob();
342         return -EAGAIN;
343 }
344
345 module_init(kmalloc_tests_init);
346 MODULE_LICENSE("GPL");