test_user_copy.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * Kernel module for testing copy_to/from_user infrastructure.
  3. *
  4. * Copyright 2013 Google Inc. All Rights Reserved
  5. *
  6. * Authors:
  7. * Kees Cook <keescook@chromium.org>
  8. *
  9. * This software is licensed under the terms of the GNU General Public
  10. * License version 2, as published by the Free Software Foundation, and
  11. * may be copied, distributed, and modified under those terms.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. */
  18. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  19. #include <linux/mman.h>
  20. #include <linux/module.h>
  21. #include <linux/sched.h>
  22. #include <linux/slab.h>
  23. #include <linux/uaccess.h>
  24. #include <linux/vmalloc.h>
  25. /*
  26. * Several 32-bit architectures support 64-bit {get,put}_user() calls.
  27. * As there doesn't appear to be anything that can safely determine
  28. * their capability at compile-time, we just have to opt-out certain archs.
  29. */
  30. #if BITS_PER_LONG == 64 || (!(defined(CONFIG_ARM) && !defined(MMU)) && \
  31. !defined(CONFIG_M68K) && \
  32. !defined(CONFIG_MICROBLAZE) && \
  33. !defined(CONFIG_NIOS2) && \
  34. !defined(CONFIG_PPC32) && \
  35. !defined(CONFIG_SUPERH))
  36. # define TEST_U64
  37. #endif
  38. #define test(condition, msg) \
  39. ({ \
  40. int cond = (condition); \
  41. if (cond) \
  42. pr_warn("%s\n", msg); \
  43. cond; \
  44. })
  45. static int __init test_user_copy_init(void)
  46. {
  47. int ret = 0;
  48. char *kmem;
  49. char __user *usermem;
  50. char *bad_usermem;
  51. unsigned long user_addr;
  52. u8 val_u8;
  53. u16 val_u16;
  54. u32 val_u32;
  55. #ifdef TEST_U64
  56. u64 val_u64;
  57. #endif
  58. kmem = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
  59. if (!kmem)
  60. return -ENOMEM;
  61. user_addr = vm_mmap(NULL, 0, PAGE_SIZE * 2,
  62. PROT_READ | PROT_WRITE | PROT_EXEC,
  63. MAP_ANONYMOUS | MAP_PRIVATE, 0);
  64. if (user_addr >= (unsigned long)(TASK_SIZE)) {
  65. pr_warn("Failed to allocate user memory\n");
  66. kfree(kmem);
  67. return -ENOMEM;
  68. }
  69. usermem = (char __user *)user_addr;
  70. bad_usermem = (char *)user_addr;
  71. /*
  72. * Legitimate usage: none of these copies should fail.
  73. */
  74. memset(kmem, 0x3a, PAGE_SIZE * 2);
  75. ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE),
  76. "legitimate copy_to_user failed");
  77. memset(kmem, 0x0, PAGE_SIZE);
  78. ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE),
  79. "legitimate copy_from_user failed");
  80. ret |= test(memcmp(kmem, kmem + PAGE_SIZE, PAGE_SIZE),
  81. "legitimate usercopy failed to copy data");
  82. #define test_legit(size, check) \
  83. do { \
  84. val_##size = check; \
  85. ret |= test(put_user(val_##size, (size __user *)usermem), \
  86. "legitimate put_user (" #size ") failed"); \
  87. val_##size = 0; \
  88. ret |= test(get_user(val_##size, (size __user *)usermem), \
  89. "legitimate get_user (" #size ") failed"); \
  90. ret |= test(val_##size != check, \
  91. "legitimate get_user (" #size ") failed to do copy"); \
  92. if (val_##size != check) { \
  93. pr_info("0x%llx != 0x%llx\n", \
  94. (unsigned long long)val_##size, \
  95. (unsigned long long)check); \
  96. } \
  97. } while (0)
  98. test_legit(u8, 0x5a);
  99. test_legit(u16, 0x5a5b);
  100. test_legit(u32, 0x5a5b5c5d);
  101. #ifdef TEST_U64
  102. test_legit(u64, 0x5a5b5c5d6a6b6c6d);
  103. #endif
  104. #undef test_legit
  105. /*
  106. * Invalid usage: none of these copies should succeed.
  107. */
  108. /* Prepare kernel memory with check values. */
  109. memset(kmem, 0x5a, PAGE_SIZE);
  110. memset(kmem + PAGE_SIZE, 0, PAGE_SIZE);
  111. /* Reject kernel-to-kernel copies through copy_from_user(). */
  112. ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE),
  113. PAGE_SIZE),
  114. "illegal all-kernel copy_from_user passed");
  115. /* Destination half of buffer should have been zeroed. */
  116. ret |= test(memcmp(kmem + PAGE_SIZE, kmem, PAGE_SIZE),
  117. "zeroing failure for illegal all-kernel copy_from_user");
  118. #if 0
  119. /*
  120. * When running with SMAP/PAN/etc, this will Oops the kernel
  121. * due to the zeroing of userspace memory on failure. This needs
  122. * to be tested in LKDTM instead, since this test module does not
  123. * expect to explode.
  124. */
  125. ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem,
  126. PAGE_SIZE),
  127. "illegal reversed copy_from_user passed");
  128. #endif
  129. ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
  130. PAGE_SIZE),
  131. "illegal all-kernel copy_to_user passed");
  132. ret |= test(!copy_to_user((char __user *)kmem, bad_usermem,
  133. PAGE_SIZE),
  134. "illegal reversed copy_to_user passed");
  135. #define test_illegal(size, check) \
  136. do { \
  137. val_##size = (check); \
  138. ret |= test(!get_user(val_##size, (size __user *)kmem), \
  139. "illegal get_user (" #size ") passed"); \
  140. ret |= test(val_##size != (size)0, \
  141. "zeroing failure for illegal get_user (" #size ")"); \
  142. if (val_##size != (size)0) { \
  143. pr_info("0x%llx != 0\n", \
  144. (unsigned long long)val_##size); \
  145. } \
  146. ret |= test(!put_user(val_##size, (size __user *)kmem), \
  147. "illegal put_user (" #size ") passed"); \
  148. } while (0)
  149. test_illegal(u8, 0x5a);
  150. test_illegal(u16, 0x5a5b);
  151. test_illegal(u32, 0x5a5b5c5d);
  152. #ifdef TEST_U64
  153. test_illegal(u64, 0x5a5b5c5d6a6b6c6d);
  154. #endif
  155. #undef test_illegal
  156. vm_munmap(user_addr, PAGE_SIZE * 2);
  157. kfree(kmem);
  158. if (ret == 0) {
  159. pr_info("tests passed.\n");
  160. return 0;
  161. }
  162. return -EINVAL;
  163. }
  164. module_init(test_user_copy_init);
  165. static void __exit test_user_copy_exit(void)
  166. {
  167. pr_info("unloaded.\n");
  168. }
  169. module_exit(test_user_copy_exit);
  170. MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
  171. MODULE_LICENSE("GPL");