test_kasan.c 9.1 KB

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