test_kasan.c 9.7 KB

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