~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/test_kasan.c

Version: ~ [ linux-5.5-rc1 ] ~ [ linux-5.4.2 ] ~ [ linux-5.3.15 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.88 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.158 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.206 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.206 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.78 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 #include <linux/kasan.h>
 24 
 25 /*
 26  * Note: test functions are marked noinline so that their names appear in
 27  * reports.
 28  */
 29 
 30 static noinline void __init kmalloc_oob_right(void)
 31 {
 32         char *ptr;
 33         size_t size = 123;
 34 
 35         pr_info("out-of-bounds to right\n");
 36         ptr = kmalloc(size, GFP_KERNEL);
 37         if (!ptr) {
 38                 pr_err("Allocation failed\n");
 39                 return;
 40         }
 41 
 42         ptr[size] = 'x';
 43         kfree(ptr);
 44 }
 45 
 46 static noinline void __init kmalloc_oob_left(void)
 47 {
 48         char *ptr;
 49         size_t size = 15;
 50 
 51         pr_info("out-of-bounds to left\n");
 52         ptr = kmalloc(size, GFP_KERNEL);
 53         if (!ptr) {
 54                 pr_err("Allocation failed\n");
 55                 return;
 56         }
 57 
 58         *ptr = *(ptr - 1);
 59         kfree(ptr);
 60 }
 61 
 62 static noinline void __init kmalloc_node_oob_right(void)
 63 {
 64         char *ptr;
 65         size_t size = 4096;
 66 
 67         pr_info("kmalloc_node(): out-of-bounds to right\n");
 68         ptr = kmalloc_node(size, GFP_KERNEL, 0);
 69         if (!ptr) {
 70                 pr_err("Allocation failed\n");
 71                 return;
 72         }
 73 
 74         ptr[size] = 0;
 75         kfree(ptr);
 76 }
 77 
 78 #ifdef CONFIG_SLUB
 79 static noinline void __init kmalloc_pagealloc_oob_right(void)
 80 {
 81         char *ptr;
 82         size_t size = KMALLOC_MAX_CACHE_SIZE + 10;
 83 
 84         /* Allocate a chunk that does not fit into a SLUB cache to trigger
 85          * the page allocator fallback.
 86          */
 87         pr_info("kmalloc pagealloc allocation: out-of-bounds to right\n");
 88         ptr = kmalloc(size, GFP_KERNEL);
 89         if (!ptr) {
 90                 pr_err("Allocation failed\n");
 91                 return;
 92         }
 93 
 94         ptr[size] = 0;
 95         kfree(ptr);
 96 }
 97 #endif
 98 
 99 static noinline void __init kmalloc_large_oob_right(void)
100 {
101         char *ptr;
102         size_t size = KMALLOC_MAX_CACHE_SIZE - 256;
103         /* Allocate a chunk that is large enough, but still fits into a slab
104          * and does not trigger the page allocator fallback in SLUB.
105          */
106         pr_info("kmalloc large allocation: out-of-bounds to right\n");
107         ptr = kmalloc(size, GFP_KERNEL);
108         if (!ptr) {
109                 pr_err("Allocation failed\n");
110                 return;
111         }
112 
113         ptr[size] = 0;
114         kfree(ptr);
115 }
116 
117 static noinline void __init kmalloc_oob_krealloc_more(void)
118 {
119         char *ptr1, *ptr2;
120         size_t size1 = 17;
121         size_t size2 = 19;
122 
123         pr_info("out-of-bounds after krealloc more\n");
124         ptr1 = kmalloc(size1, GFP_KERNEL);
125         ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
126         if (!ptr1 || !ptr2) {
127                 pr_err("Allocation failed\n");
128                 kfree(ptr1);
129                 return;
130         }
131 
132         ptr2[size2] = 'x';
133         kfree(ptr2);
134 }
135 
136 static noinline void __init kmalloc_oob_krealloc_less(void)
137 {
138         char *ptr1, *ptr2;
139         size_t size1 = 17;
140         size_t size2 = 15;
141 
142         pr_info("out-of-bounds after krealloc less\n");
143         ptr1 = kmalloc(size1, GFP_KERNEL);
144         ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
145         if (!ptr1 || !ptr2) {
146                 pr_err("Allocation failed\n");
147                 kfree(ptr1);
148                 return;
149         }
150         ptr2[size2] = 'x';
151         kfree(ptr2);
152 }
153 
154 static noinline void __init kmalloc_oob_16(void)
155 {
156         struct {
157                 u64 words[2];
158         } *ptr1, *ptr2;
159 
160         pr_info("kmalloc out-of-bounds for 16-bytes access\n");
161         ptr1 = kmalloc(sizeof(*ptr1) - 3, GFP_KERNEL);
162         ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL);
163         if (!ptr1 || !ptr2) {
164                 pr_err("Allocation failed\n");
165                 kfree(ptr1);
166                 kfree(ptr2);
167                 return;
168         }
169         *ptr1 = *ptr2;
170         kfree(ptr1);
171         kfree(ptr2);
172 }
173 
174 static noinline void __init kmalloc_oob_memset_2(void)
175 {
176         char *ptr;
177         size_t size = 8;
178 
179         pr_info("out-of-bounds in memset2\n");
180         ptr = kmalloc(size, GFP_KERNEL);
181         if (!ptr) {
182                 pr_err("Allocation failed\n");
183                 return;
184         }
185 
186         memset(ptr+7, 0, 2);
187         kfree(ptr);
188 }
189 
190 static noinline void __init kmalloc_oob_memset_4(void)
191 {
192         char *ptr;
193         size_t size = 8;
194 
195         pr_info("out-of-bounds in memset4\n");
196         ptr = kmalloc(size, GFP_KERNEL);
197         if (!ptr) {
198                 pr_err("Allocation failed\n");
199                 return;
200         }
201 
202         memset(ptr+5, 0, 4);
203         kfree(ptr);
204 }
205 
206 
207 static noinline void __init kmalloc_oob_memset_8(void)
208 {
209         char *ptr;
210         size_t size = 8;
211 
212         pr_info("out-of-bounds in memset8\n");
213         ptr = kmalloc(size, GFP_KERNEL);
214         if (!ptr) {
215                 pr_err("Allocation failed\n");
216                 return;
217         }
218 
219         memset(ptr+1, 0, 8);
220         kfree(ptr);
221 }
222 
223 static noinline void __init kmalloc_oob_memset_16(void)
224 {
225         char *ptr;
226         size_t size = 16;
227 
228         pr_info("out-of-bounds in memset16\n");
229         ptr = kmalloc(size, GFP_KERNEL);
230         if (!ptr) {
231                 pr_err("Allocation failed\n");
232                 return;
233         }
234 
235         memset(ptr+1, 0, 16);
236         kfree(ptr);
237 }
238 
239 static noinline void __init kmalloc_oob_in_memset(void)
240 {
241         char *ptr;
242         size_t size = 666;
243 
244         pr_info("out-of-bounds in memset\n");
245         ptr = kmalloc(size, GFP_KERNEL);
246         if (!ptr) {
247                 pr_err("Allocation failed\n");
248                 return;
249         }
250 
251         memset(ptr, 0, size+5);
252         kfree(ptr);
253 }
254 
255 static noinline void __init kmalloc_uaf(void)
256 {
257         char *ptr;
258         size_t size = 10;
259 
260         pr_info("use-after-free\n");
261         ptr = kmalloc(size, GFP_KERNEL);
262         if (!ptr) {
263                 pr_err("Allocation failed\n");
264                 return;
265         }
266 
267         kfree(ptr);
268         *(ptr + 8) = 'x';
269 }
270 
271 static noinline void __init kmalloc_uaf_memset(void)
272 {
273         char *ptr;
274         size_t size = 33;
275 
276         pr_info("use-after-free in memset\n");
277         ptr = kmalloc(size, GFP_KERNEL);
278         if (!ptr) {
279                 pr_err("Allocation failed\n");
280                 return;
281         }
282 
283         kfree(ptr);
284         memset(ptr, 0, size);
285 }
286 
287 static noinline void __init kmalloc_uaf2(void)
288 {
289         char *ptr1, *ptr2;
290         size_t size = 43;
291 
292         pr_info("use-after-free after another kmalloc\n");
293         ptr1 = kmalloc(size, GFP_KERNEL);
294         if (!ptr1) {
295                 pr_err("Allocation failed\n");
296                 return;
297         }
298 
299         kfree(ptr1);
300         ptr2 = kmalloc(size, GFP_KERNEL);
301         if (!ptr2) {
302                 pr_err("Allocation failed\n");
303                 return;
304         }
305 
306         ptr1[40] = 'x';
307         if (ptr1 == ptr2)
308                 pr_err("Could not detect use-after-free: ptr1 == ptr2\n");
309         kfree(ptr2);
310 }
311 
312 static noinline void __init kmem_cache_oob(void)
313 {
314         char *p;
315         size_t size = 200;
316         struct kmem_cache *cache = kmem_cache_create("test_cache",
317                                                 size, 0,
318                                                 0, NULL);
319         if (!cache) {
320                 pr_err("Cache allocation failed\n");
321                 return;
322         }
323         pr_info("out-of-bounds in kmem_cache_alloc\n");
324         p = kmem_cache_alloc(cache, GFP_KERNEL);
325         if (!p) {
326                 pr_err("Allocation failed\n");
327                 kmem_cache_destroy(cache);
328                 return;
329         }
330 
331         *p = p[size];
332         kmem_cache_free(cache, p);
333         kmem_cache_destroy(cache);
334 }
335 
336 static noinline void __init memcg_accounted_kmem_cache(void)
337 {
338         int i;
339         char *p;
340         size_t size = 200;
341         struct kmem_cache *cache;
342 
343         cache = kmem_cache_create("test_cache", size, 0, SLAB_ACCOUNT, NULL);
344         if (!cache) {
345                 pr_err("Cache allocation failed\n");
346                 return;
347         }
348 
349         pr_info("allocate memcg accounted object\n");
350         /*
351          * Several allocations with a delay to allow for lazy per memcg kmem
352          * cache creation.
353          */
354         for (i = 0; i < 5; i++) {
355                 p = kmem_cache_alloc(cache, GFP_KERNEL);
356                 if (!p)
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         /*
478          * Temporarily enable multi-shot mode. Otherwise, we'd only get a
479          * report for the first case.
480          */
481         bool multishot = kasan_save_enable_multi_shot();
482 
483         kmalloc_oob_right();
484         kmalloc_oob_left();
485         kmalloc_node_oob_right();
486 #ifdef CONFIG_SLUB
487         kmalloc_pagealloc_oob_right();
488 #endif
489         kmalloc_large_oob_right();
490         kmalloc_oob_krealloc_more();
491         kmalloc_oob_krealloc_less();
492         kmalloc_oob_16();
493         kmalloc_oob_in_memset();
494         kmalloc_oob_memset_2();
495         kmalloc_oob_memset_4();
496         kmalloc_oob_memset_8();
497         kmalloc_oob_memset_16();
498         kmalloc_uaf();
499         kmalloc_uaf_memset();
500         kmalloc_uaf2();
501         kmem_cache_oob();
502         memcg_accounted_kmem_cache();
503         kasan_stack_oob();
504         kasan_global_oob();
505         ksize_unpoisons_memory();
506         copy_user_test();
507         use_after_scope_test();
508 
509         kasan_restore_multi_shot(multishot);
510 
511         return -EAGAIN;
512 }
513 
514 module_init(kmalloc_tests_init);
515 MODULE_LICENSE("GPL");
516 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp