test_user_copy.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Kernel module for testing copy_to/from_user infrastructure.
  4. *
  5. * Copyright 2013 Google Inc. All Rights Reserved
  6. *
  7. * Authors:
  8. * Kees Cook <keescook@chromium.org>
  9. */
  10. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  11. #include <linux/mman.h>
  12. #include <linux/module.h>
  13. #include <linux/sched.h>
  14. #include <linux/slab.h>
  15. #include <linux/uaccess.h>
  16. #include <linux/vmalloc.h>
  17. /*
  18. * Several 32-bit architectures support 64-bit {get,put}_user() calls.
  19. * As there doesn't appear to be anything that can safely determine
  20. * their capability at compile-time, we just have to opt-out certain archs.
  21. */
  22. #if BITS_PER_LONG == 64 || (!(defined(CONFIG_ARM) && !defined(MMU)) && \
  23. !defined(CONFIG_M68K) && \
  24. !defined(CONFIG_MICROBLAZE) && \
  25. !defined(CONFIG_NIOS2) && \
  26. !defined(CONFIG_PPC32) && \
  27. !defined(CONFIG_SUPERH))
  28. # define TEST_U64
  29. #endif
  30. #define test(condition, msg, ...) \
  31. ({ \
  32. int cond = (condition); \
  33. if (cond) \
  34. pr_warn("[%d] " msg "\n", __LINE__, ##__VA_ARGS__); \
  35. cond; \
  36. })
  37. static bool is_zeroed(void *from, size_t size)
  38. {
  39. return memchr_inv(from, 0x0, size) == NULL;
  40. }
  41. static int test_check_nonzero_user(char *kmem, char __user *umem, size_t size)
  42. {
  43. int ret = 0;
  44. size_t start, end, i, zero_start, zero_end;
  45. if (test(size < 2 * PAGE_SIZE, "buffer too small"))
  46. return -EINVAL;
  47. /*
  48. * We want to cross a page boundary to exercise the code more
  49. * effectively. We also don't want to make the size we scan too large,
  50. * otherwise the test can take a long time and cause soft lockups. So
  51. * scan a 1024 byte region across the page boundary.
  52. */
  53. size = 1024;
  54. start = PAGE_SIZE - (size / 2);
  55. kmem += start;
  56. umem += start;
  57. zero_start = size / 4;
  58. zero_end = size - zero_start;
  59. /*
  60. * We conduct a series of check_nonzero_user() tests on a block of
  61. * memory with the following byte-pattern (trying every possible
  62. * [start,end] pair):
  63. *
  64. * [ 00 ff 00 ff ... 00 00 00 00 ... ff 00 ff 00 ]
  65. *
  66. * And we verify that check_nonzero_user() acts identically to
  67. * memchr_inv().
  68. */
  69. memset(kmem, 0x0, size);
  70. for (i = 1; i < zero_start; i += 2)
  71. kmem[i] = 0xff;
  72. for (i = zero_end; i < size; i += 2)
  73. kmem[i] = 0xff;
  74. ret |= test(copy_to_user(umem, kmem, size),
  75. "legitimate copy_to_user failed");
  76. for (start = 0; start <= size; start++) {
  77. for (end = start; end <= size; end++) {
  78. size_t len = end - start;
  79. int retval = check_zeroed_user(umem + start, len);
  80. int expected = is_zeroed(kmem + start, len);
  81. ret |= test(retval != expected,
  82. "check_nonzero_user(=%d) != memchr_inv(=%d) mismatch (start=%zu, end=%zu)",
  83. retval, expected, start, end);
  84. }
  85. }
  86. return ret;
  87. }
  88. static int test_copy_struct_from_user(char *kmem, char __user *umem,
  89. size_t size)
  90. {
  91. int ret = 0;
  92. char *umem_src = NULL, *expected = NULL;
  93. size_t ksize, usize;
  94. umem_src = kmalloc(size, GFP_KERNEL);
  95. ret = test(umem_src == NULL, "kmalloc failed");
  96. if (ret)
  97. goto out_free;
  98. expected = kmalloc(size, GFP_KERNEL);
  99. ret = test(expected == NULL, "kmalloc failed");
  100. if (ret)
  101. goto out_free;
  102. /* Fill umem with a fixed byte pattern. */
  103. memset(umem_src, 0x3e, size);
  104. ret |= test(copy_to_user(umem, umem_src, size),
  105. "legitimate copy_to_user failed");
  106. /* Check basic case -- (usize == ksize). */
  107. ksize = size;
  108. usize = size;
  109. memcpy(expected, umem_src, ksize);
  110. memset(kmem, 0x0, size);
  111. ret |= test(copy_struct_from_user(kmem, ksize, umem, usize),
  112. "copy_struct_from_user(usize == ksize) failed");
  113. ret |= test(memcmp(kmem, expected, ksize),
  114. "copy_struct_from_user(usize == ksize) gives unexpected copy");
  115. /* Old userspace case -- (usize < ksize). */
  116. ksize = size;
  117. usize = size / 2;
  118. memcpy(expected, umem_src, usize);
  119. memset(expected + usize, 0x0, ksize - usize);
  120. memset(kmem, 0x0, size);
  121. ret |= test(copy_struct_from_user(kmem, ksize, umem, usize),
  122. "copy_struct_from_user(usize < ksize) failed");
  123. ret |= test(memcmp(kmem, expected, ksize),
  124. "copy_struct_from_user(usize < ksize) gives unexpected copy");
  125. /* New userspace (-E2BIG) case -- (usize > ksize). */
  126. ksize = size / 2;
  127. usize = size;
  128. memset(kmem, 0x0, size);
  129. ret |= test(copy_struct_from_user(kmem, ksize, umem, usize) != -E2BIG,
  130. "copy_struct_from_user(usize > ksize) didn't give E2BIG");
  131. /* New userspace (success) case -- (usize > ksize). */
  132. ksize = size / 2;
  133. usize = size;
  134. memcpy(expected, umem_src, ksize);
  135. ret |= test(clear_user(umem + ksize, usize - ksize),
  136. "legitimate clear_user failed");
  137. memset(kmem, 0x0, size);
  138. ret |= test(copy_struct_from_user(kmem, ksize, umem, usize),
  139. "copy_struct_from_user(usize > ksize) failed");
  140. ret |= test(memcmp(kmem, expected, ksize),
  141. "copy_struct_from_user(usize > ksize) gives unexpected copy");
  142. out_free:
  143. kfree(expected);
  144. kfree(umem_src);
  145. return ret;
  146. }
  147. static int __init test_user_copy_init(void)
  148. {
  149. int ret = 0;
  150. char *kmem;
  151. char __user *usermem;
  152. char *bad_usermem;
  153. unsigned long user_addr;
  154. u8 val_u8;
  155. u16 val_u16;
  156. u32 val_u32;
  157. #ifdef TEST_U64
  158. u64 val_u64;
  159. #endif
  160. kmem = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
  161. if (!kmem)
  162. return -ENOMEM;
  163. user_addr = vm_mmap(NULL, 0, PAGE_SIZE * 2,
  164. PROT_READ | PROT_WRITE | PROT_EXEC,
  165. MAP_ANONYMOUS | MAP_PRIVATE, 0);
  166. if (user_addr >= (unsigned long)(TASK_SIZE)) {
  167. pr_warn("Failed to allocate user memory\n");
  168. kfree(kmem);
  169. return -ENOMEM;
  170. }
  171. usermem = (char __user *)user_addr;
  172. bad_usermem = (char *)user_addr;
  173. /*
  174. * Legitimate usage: none of these copies should fail.
  175. */
  176. memset(kmem, 0x3a, PAGE_SIZE * 2);
  177. ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE),
  178. "legitimate copy_to_user failed");
  179. memset(kmem, 0x0, PAGE_SIZE);
  180. ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE),
  181. "legitimate copy_from_user failed");
  182. ret |= test(memcmp(kmem, kmem + PAGE_SIZE, PAGE_SIZE),
  183. "legitimate usercopy failed to copy data");
  184. #define test_legit(size, check) \
  185. do { \
  186. val_##size = check; \
  187. ret |= test(put_user(val_##size, (size __user *)usermem), \
  188. "legitimate put_user (" #size ") failed"); \
  189. val_##size = 0; \
  190. ret |= test(get_user(val_##size, (size __user *)usermem), \
  191. "legitimate get_user (" #size ") failed"); \
  192. ret |= test(val_##size != check, \
  193. "legitimate get_user (" #size ") failed to do copy"); \
  194. if (val_##size != check) { \
  195. pr_info("0x%llx != 0x%llx\n", \
  196. (unsigned long long)val_##size, \
  197. (unsigned long long)check); \
  198. } \
  199. } while (0)
  200. test_legit(u8, 0x5a);
  201. test_legit(u16, 0x5a5b);
  202. test_legit(u32, 0x5a5b5c5d);
  203. #ifdef TEST_U64
  204. test_legit(u64, 0x5a5b5c5d6a6b6c6d);
  205. #endif
  206. #undef test_legit
  207. /* Test usage of check_nonzero_user(). */
  208. ret |= test_check_nonzero_user(kmem, usermem, 2 * PAGE_SIZE);
  209. /* Test usage of copy_struct_from_user(). */
  210. ret |= test_copy_struct_from_user(kmem, usermem, 2 * PAGE_SIZE);
  211. /*
  212. * Invalid usage: none of these copies should succeed.
  213. */
  214. /* Prepare kernel memory with check values. */
  215. memset(kmem, 0x5a, PAGE_SIZE);
  216. memset(kmem + PAGE_SIZE, 0, PAGE_SIZE);
  217. /* Reject kernel-to-kernel copies through copy_from_user(). */
  218. ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE),
  219. PAGE_SIZE),
  220. "illegal all-kernel copy_from_user passed");
  221. /* Destination half of buffer should have been zeroed. */
  222. ret |= test(memcmp(kmem + PAGE_SIZE, kmem, PAGE_SIZE),
  223. "zeroing failure for illegal all-kernel copy_from_user");
  224. #if 0
  225. /*
  226. * When running with SMAP/PAN/etc, this will Oops the kernel
  227. * due to the zeroing of userspace memory on failure. This needs
  228. * to be tested in LKDTM instead, since this test module does not
  229. * expect to explode.
  230. */
  231. ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem,
  232. PAGE_SIZE),
  233. "illegal reversed copy_from_user passed");
  234. #endif
  235. ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
  236. PAGE_SIZE),
  237. "illegal all-kernel copy_to_user passed");
  238. ret |= test(!copy_to_user((char __user *)kmem, bad_usermem,
  239. PAGE_SIZE),
  240. "illegal reversed copy_to_user passed");
  241. #define test_illegal(size, check) \
  242. do { \
  243. val_##size = (check); \
  244. ret |= test(!get_user(val_##size, (size __user *)kmem), \
  245. "illegal get_user (" #size ") passed"); \
  246. ret |= test(val_##size != (size)0, \
  247. "zeroing failure for illegal get_user (" #size ")"); \
  248. if (val_##size != (size)0) { \
  249. pr_info("0x%llx != 0\n", \
  250. (unsigned long long)val_##size); \
  251. } \
  252. ret |= test(!put_user(val_##size, (size __user *)kmem), \
  253. "illegal put_user (" #size ") passed"); \
  254. } while (0)
  255. test_illegal(u8, 0x5a);
  256. test_illegal(u16, 0x5a5b);
  257. test_illegal(u32, 0x5a5b5c5d);
  258. #ifdef TEST_U64
  259. test_illegal(u64, 0x5a5b5c5d6a6b6c6d);
  260. #endif
  261. #undef test_illegal
  262. vm_munmap(user_addr, PAGE_SIZE * 2);
  263. kfree(kmem);
  264. if (ret == 0) {
  265. pr_info("tests passed.\n");
  266. return 0;
  267. }
  268. return -EINVAL;
  269. }
  270. module_init(test_user_copy_init);
  271. static void __exit test_user_copy_exit(void)
  272. {
  273. pr_info("unloaded.\n");
  274. }
  275. module_exit(test_user_copy_exit);
  276. MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
  277. MODULE_LICENSE("GPL");