netlink/diag: report flags for netlink sockets
[linux-2.6-block.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/delay.h>
15 #include <linux/kernel.h>
16 #include <linux/mman.h>
17 #include <linux/mm.h>
18 #include <linux/printk.h>
19 #include <linux/slab.h>
20 #include <linux/string.h>
21 #include <linux/uaccess.h>
22 #include <linux/module.h>
23
24 /*
25  * Note: test functions are marked noinline so that their names appear in
26  * reports.
27  */
28
29 static noinline void __init kmalloc_oob_right(void)
30 {
31         char *ptr;
32         size_t size = 123;
33
34         pr_info("out-of-bounds to right\n");
35         ptr = kmalloc(size, GFP_KERNEL);
36         if (!ptr) {
37                 pr_err("Allocation failed\n");
38                 return;
39         }
40
41         ptr[size] = 'x';
42         kfree(ptr);
43 }
44
45 static noinline void __init kmalloc_oob_left(void)
46 {
47         char *ptr;
48         size_t size = 15;
49
50         pr_info("out-of-bounds to left\n");
51         ptr = kmalloc(size, GFP_KERNEL);
52         if (!ptr) {
53                 pr_err("Allocation failed\n");
54                 return;
55         }
56
57         *ptr = *(ptr - 1);
58         kfree(ptr);
59 }
60
61 static noinline void __init kmalloc_node_oob_right(void)
62 {
63         char *ptr;
64         size_t size = 4096;
65
66         pr_info("kmalloc_node(): out-of-bounds to right\n");
67         ptr = kmalloc_node(size, GFP_KERNEL, 0);
68         if (!ptr) {
69                 pr_err("Allocation failed\n");
70                 return;
71         }
72
73         ptr[size] = 0;
74         kfree(ptr);
75 }
76
77 #ifdef CONFIG_SLUB
78 static noinline void __init kmalloc_pagealloc_oob_right(void)
79 {
80         char *ptr;
81         size_t size = KMALLOC_MAX_CACHE_SIZE + 10;
82
83         /* Allocate a chunk that does not fit into a SLUB cache to trigger
84          * the page allocator fallback.
85          */
86         pr_info("kmalloc pagealloc allocation: out-of-bounds to right\n");
87         ptr = kmalloc(size, GFP_KERNEL);
88         if (!ptr) {
89                 pr_err("Allocation failed\n");
90                 return;
91         }
92
93         ptr[size] = 0;
94         kfree(ptr);
95 }
96 #endif
97
98 static noinline void __init kmalloc_large_oob_right(void)
99 {
100         char *ptr;
101         size_t size = KMALLOC_MAX_CACHE_SIZE - 256;
102         /* Allocate a chunk that is large enough, but still fits into a slab
103          * and does not trigger the page allocator fallback in SLUB.
104          */
105         pr_info("kmalloc large allocation: out-of-bounds to right\n");
106         ptr = kmalloc(size, GFP_KERNEL);
107         if (!ptr) {
108                 pr_err("Allocation failed\n");
109                 return;
110         }
111
112         ptr[size] = 0;
113         kfree(ptr);
114 }
115
116 static noinline void __init kmalloc_oob_krealloc_more(void)
117 {
118         char *ptr1, *ptr2;
119         size_t size1 = 17;
120         size_t size2 = 19;
121
122         pr_info("out-of-bounds after krealloc more\n");
123         ptr1 = kmalloc(size1, GFP_KERNEL);
124         ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
125         if (!ptr1 || !ptr2) {
126                 pr_err("Allocation failed\n");
127                 kfree(ptr1);
128                 return;
129         }
130
131         ptr2[size2] = 'x';
132         kfree(ptr2);
133 }
134
135 static noinline void __init kmalloc_oob_krealloc_less(void)
136 {
137         char *ptr1, *ptr2;
138         size_t size1 = 17;
139         size_t size2 = 15;
140
141         pr_info("out-of-bounds after krealloc less\n");
142         ptr1 = kmalloc(size1, GFP_KERNEL);
143         ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
144         if (!ptr1 || !ptr2) {
145                 pr_err("Allocation failed\n");
146                 kfree(ptr1);
147                 return;
148         }
149         ptr2[size2] = 'x';
150         kfree(ptr2);
151 }
152
153 static noinline void __init kmalloc_oob_16(void)
154 {
155         struct {
156                 u64 words[2];
157         } *ptr1, *ptr2;
158
159         pr_info("kmalloc out-of-bounds for 16-bytes access\n");
160         ptr1 = kmalloc(sizeof(*ptr1) - 3, GFP_KERNEL);
161         ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL);
162         if (!ptr1 || !ptr2) {
163                 pr_err("Allocation failed\n");
164                 kfree(ptr1);
165                 kfree(ptr2);
166                 return;
167         }
168         *ptr1 = *ptr2;
169         kfree(ptr1);
170         kfree(ptr2);
171 }
172
173 static noinline void __init kmalloc_oob_memset_2(void)
174 {
175         char *ptr;
176         size_t size = 8;
177
178         pr_info("out-of-bounds in memset2\n");
179         ptr = kmalloc(size, GFP_KERNEL);
180         if (!ptr) {
181                 pr_err("Allocation failed\n");
182                 return;
183         }
184
185         memset(ptr+7, 0, 2);
186         kfree(ptr);
187 }
188
189 static noinline void __init kmalloc_oob_memset_4(void)
190 {
191         char *ptr;
192         size_t size = 8;
193
194         pr_info("out-of-bounds in memset4\n");
195         ptr = kmalloc(size, GFP_KERNEL);
196         if (!ptr) {
197                 pr_err("Allocation failed\n");
198                 return;
199         }
200
201         memset(ptr+5, 0, 4);
202         kfree(ptr);
203 }
204
205
206 static noinline void __init kmalloc_oob_memset_8(void)
207 {
208         char *ptr;
209         size_t size = 8;
210
211         pr_info("out-of-bounds in memset8\n");
212         ptr = kmalloc(size, GFP_KERNEL);
213         if (!ptr) {
214                 pr_err("Allocation failed\n");
215                 return;
216         }
217
218         memset(ptr+1, 0, 8);
219         kfree(ptr);
220 }
221
222 static noinline void __init kmalloc_oob_memset_16(void)
223 {
224         char *ptr;
225         size_t size = 16;
226
227         pr_info("out-of-bounds in memset16\n");
228         ptr = kmalloc(size, GFP_KERNEL);
229         if (!ptr) {
230                 pr_err("Allocation failed\n");
231                 return;
232         }
233
234         memset(ptr+1, 0, 16);
235         kfree(ptr);
236 }
237
238 static noinline void __init kmalloc_oob_in_memset(void)
239 {
240         char *ptr;
241         size_t size = 666;
242
243         pr_info("out-of-bounds in memset\n");
244         ptr = kmalloc(size, GFP_KERNEL);
245         if (!ptr) {
246                 pr_err("Allocation failed\n");
247                 return;
248         }
249
250         memset(ptr, 0, size+5);
251         kfree(ptr);
252 }
253
254 static noinline void __init kmalloc_uaf(void)
255 {
256         char *ptr;
257         size_t size = 10;
258
259         pr_info("use-after-free\n");
260         ptr = kmalloc(size, GFP_KERNEL);
261         if (!ptr) {
262                 pr_err("Allocation failed\n");
263                 return;
264         }
265
266         kfree(ptr);
267         *(ptr + 8) = 'x';
268 }
269
270 static noinline void __init kmalloc_uaf_memset(void)
271 {
272         char *ptr;
273         size_t size = 33;
274
275         pr_info("use-after-free in memset\n");
276         ptr = kmalloc(size, GFP_KERNEL);
277         if (!ptr) {
278                 pr_err("Allocation failed\n");
279                 return;
280         }
281
282         kfree(ptr);
283         memset(ptr, 0, size);
284 }
285
286 static noinline void __init kmalloc_uaf2(void)
287 {
288         char *ptr1, *ptr2;
289         size_t size = 43;
290
291         pr_info("use-after-free after another kmalloc\n");
292         ptr1 = kmalloc(size, GFP_KERNEL);
293         if (!ptr1) {
294                 pr_err("Allocation failed\n");
295                 return;
296         }
297
298         kfree(ptr1);
299         ptr2 = kmalloc(size, GFP_KERNEL);
300         if (!ptr2) {
301                 pr_err("Allocation failed\n");
302                 return;
303         }
304
305         ptr1[40] = 'x';
306         if (ptr1 == ptr2)
307                 pr_err("Could not detect use-after-free: ptr1 == ptr2\n");
308         kfree(ptr2);
309 }
310
311 static noinline void __init kmem_cache_oob(void)
312 {
313         char *p;
314         size_t size = 200;
315         struct kmem_cache *cache = kmem_cache_create("test_cache",
316                                                 size, 0,
317                                                 0, NULL);
318         if (!cache) {
319                 pr_err("Cache allocation failed\n");
320                 return;
321         }
322         pr_info("out-of-bounds in kmem_cache_alloc\n");
323         p = kmem_cache_alloc(cache, GFP_KERNEL);
324         if (!p) {
325                 pr_err("Allocation failed\n");
326                 kmem_cache_destroy(cache);
327                 return;
328         }
329
330         *p = p[size];
331         kmem_cache_free(cache, p);
332         kmem_cache_destroy(cache);
333 }
334
335 static noinline void __init memcg_accounted_kmem_cache(void)
336 {
337         int i;
338         char *p;
339         size_t size = 200;
340         struct kmem_cache *cache;
341
342         cache = kmem_cache_create("test_cache", size, 0, SLAB_ACCOUNT, NULL);
343         if (!cache) {
344                 pr_err("Cache allocation failed\n");
345                 return;
346         }
347
348         pr_info("allocate memcg accounted object\n");
349         /*
350          * Several allocations with a delay to allow for lazy per memcg kmem
351          * cache creation.
352          */
353         for (i = 0; i < 5; i++) {
354                 p = kmem_cache_alloc(cache, GFP_KERNEL);
355                 if (!p) {
356                         pr_err("Allocation failed\n");
357                         goto free_cache;
358                 }
359                 kmem_cache_free(cache, p);
360                 msleep(100);
361         }
362
363 free_cache:
364         kmem_cache_destroy(cache);
365 }
366
367 static char global_array[10];
368
369 static noinline void __init kasan_global_oob(void)
370 {
371         volatile int i = 3;
372         char *p = &global_array[ARRAY_SIZE(global_array) + i];
373
374         pr_info("out-of-bounds global variable\n");
375         *(volatile char *)p;
376 }
377
378 static noinline void __init kasan_stack_oob(void)
379 {
380         char stack_array[10];
381         volatile int i = 0;
382         char *p = &stack_array[ARRAY_SIZE(stack_array) + i];
383
384         pr_info("out-of-bounds on stack\n");
385         *(volatile char *)p;
386 }
387
388 static noinline void __init ksize_unpoisons_memory(void)
389 {
390         char *ptr;
391         size_t size = 123, real_size = size;
392
393         pr_info("ksize() unpoisons the whole allocated chunk\n");
394         ptr = kmalloc(size, GFP_KERNEL);
395         if (!ptr) {
396                 pr_err("Allocation failed\n");
397                 return;
398         }
399         real_size = ksize(ptr);
400         /* This access doesn't trigger an error. */
401         ptr[size] = 'x';
402         /* This one does. */
403         ptr[real_size] = 'y';
404         kfree(ptr);
405 }
406
407 static noinline void __init copy_user_test(void)
408 {
409         char *kmem;
410         char __user *usermem;
411         size_t size = 10;
412         int unused;
413
414         kmem = kmalloc(size, GFP_KERNEL);
415         if (!kmem)
416                 return;
417
418         usermem = (char __user *)vm_mmap(NULL, 0, PAGE_SIZE,
419                             PROT_READ | PROT_WRITE | PROT_EXEC,
420                             MAP_ANONYMOUS | MAP_PRIVATE, 0);
421         if (IS_ERR(usermem)) {
422                 pr_err("Failed to allocate user memory\n");
423                 kfree(kmem);
424                 return;
425         }
426
427         pr_info("out-of-bounds in copy_from_user()\n");
428         unused = copy_from_user(kmem, usermem, size + 1);
429
430         pr_info("out-of-bounds in copy_to_user()\n");
431         unused = copy_to_user(usermem, kmem, size + 1);
432
433         pr_info("out-of-bounds in __copy_from_user()\n");
434         unused = __copy_from_user(kmem, usermem, size + 1);
435
436         pr_info("out-of-bounds in __copy_to_user()\n");
437         unused = __copy_to_user(usermem, kmem, size + 1);
438
439         pr_info("out-of-bounds in __copy_from_user_inatomic()\n");
440         unused = __copy_from_user_inatomic(kmem, usermem, size + 1);
441
442         pr_info("out-of-bounds in __copy_to_user_inatomic()\n");
443         unused = __copy_to_user_inatomic(usermem, kmem, size + 1);
444
445         pr_info("out-of-bounds in strncpy_from_user()\n");
446         unused = strncpy_from_user(kmem, usermem, size + 1);
447
448         vm_munmap((unsigned long)usermem, PAGE_SIZE);
449         kfree(kmem);
450 }
451
452 static noinline void __init use_after_scope_test(void)
453 {
454         volatile char *volatile p;
455
456         pr_info("use-after-scope on int\n");
457         {
458                 int local = 0;
459
460                 p = (char *)&local;
461         }
462         p[0] = 1;
463         p[3] = 1;
464
465         pr_info("use-after-scope on array\n");
466         {
467                 char local[1024] = {0};
468
469                 p = local;
470         }
471         p[0] = 1;
472         p[1023] = 1;
473 }
474
475 static int __init kmalloc_tests_init(void)
476 {
477         kmalloc_oob_right();
478         kmalloc_oob_left();
479         kmalloc_node_oob_right();
480 #ifdef CONFIG_SLUB
481         kmalloc_pagealloc_oob_right();
482 #endif
483         kmalloc_large_oob_right();
484         kmalloc_oob_krealloc_more();
485         kmalloc_oob_krealloc_less();
486         kmalloc_oob_16();
487         kmalloc_oob_in_memset();
488         kmalloc_oob_memset_2();
489         kmalloc_oob_memset_4();
490         kmalloc_oob_memset_8();
491         kmalloc_oob_memset_16();
492         kmalloc_uaf();
493         kmalloc_uaf_memset();
494         kmalloc_uaf2();
495         kmem_cache_oob();
496         memcg_accounted_kmem_cache();
497         kasan_stack_oob();
498         kasan_global_oob();
499         ksize_unpoisons_memory();
500         copy_user_test();
501         use_after_scope_test();
502         return -EAGAIN;
503 }
504
505 module_init(kmalloc_tests_init);
506 MODULE_LICENSE("GPL");