test_user_copy.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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_AVR32) && \
  32. !defined(CONFIG_BLACKFIN) && \
  33. !defined(CONFIG_M32R) && \
  34. !defined(CONFIG_M68K) && \
  35. !defined(CONFIG_MICROBLAZE) && \
  36. !defined(CONFIG_MN10300) && \
  37. !defined(CONFIG_NIOS2) && \
  38. !defined(CONFIG_PPC32) && \
  39. !defined(CONFIG_SUPERH))
  40. # define TEST_U64
  41. #endif
  42. #define test(condition, msg) \
  43. ({ \
  44. int cond = (condition); \
  45. if (cond) \
  46. pr_warn("%s\n", msg); \
  47. cond; \
  48. })
  49. static int __init test_user_copy_init(void)
  50. {
  51. int ret = 0;
  52. char *kmem;
  53. char __user *usermem;
  54. char *bad_usermem;
  55. unsigned long user_addr;
  56. u8 val_u8;
  57. u16 val_u16;
  58. u32 val_u32;
  59. #ifdef TEST_U64
  60. u64 val_u64;
  61. #endif
  62. kmem = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
  63. if (!kmem)
  64. return -ENOMEM;
  65. user_addr = vm_mmap(NULL, 0, PAGE_SIZE * 2,
  66. PROT_READ | PROT_WRITE | PROT_EXEC,
  67. MAP_ANONYMOUS | MAP_PRIVATE, 0);
  68. if (user_addr >= (unsigned long)(TASK_SIZE)) {
  69. pr_warn("Failed to allocate user memory\n");
  70. kfree(kmem);
  71. return -ENOMEM;
  72. }
  73. usermem = (char __user *)user_addr;
  74. bad_usermem = (char *)user_addr;
  75. /*
  76. * Legitimate usage: none of these copies should fail.
  77. */
  78. memset(kmem, 0x3a, PAGE_SIZE * 2);
  79. ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE),
  80. "legitimate copy_to_user failed");
  81. memset(kmem, 0x0, PAGE_SIZE);
  82. ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE),
  83. "legitimate copy_from_user failed");
  84. ret |= test(memcmp(kmem, kmem + PAGE_SIZE, PAGE_SIZE),
  85. "legitimate usercopy failed to copy data");
  86. #define test_legit(size, check) \
  87. do { \
  88. val_##size = check; \
  89. ret |= test(put_user(val_##size, (size __user *)usermem), \
  90. "legitimate put_user (" #size ") failed"); \
  91. val_##size = 0; \
  92. ret |= test(get_user(val_##size, (size __user *)usermem), \
  93. "legitimate get_user (" #size ") failed"); \
  94. ret |= test(val_##size != check, \
  95. "legitimate get_user (" #size ") failed to do copy"); \
  96. if (val_##size != check) { \
  97. pr_info("0x%llx != 0x%llx\n", \
  98. (unsigned long long)val_##size, \
  99. (unsigned long long)check); \
  100. } \
  101. } while (0)
  102. test_legit(u8, 0x5a);
  103. test_legit(u16, 0x5a5b);
  104. test_legit(u32, 0x5a5b5c5d);
  105. #ifdef TEST_U64
  106. test_legit(u64, 0x5a5b5c5d6a6b6c6d);
  107. #endif
  108. #undef test_legit
  109. /*
  110. * Invalid usage: none of these copies should succeed.
  111. */
  112. /* Prepare kernel memory with check values. */
  113. memset(kmem, 0x5a, PAGE_SIZE);
  114. memset(kmem + PAGE_SIZE, 0, PAGE_SIZE);
  115. /* Reject kernel-to-kernel copies through copy_from_user(). */
  116. ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE),
  117. PAGE_SIZE),
  118. "illegal all-kernel copy_from_user passed");
  119. /* Destination half of buffer should have been zeroed. */
  120. ret |= test(memcmp(kmem + PAGE_SIZE, kmem, PAGE_SIZE),
  121. "zeroing failure for illegal all-kernel copy_from_user");
  122. #if 0
  123. /*
  124. * When running with SMAP/PAN/etc, this will Oops the kernel
  125. * due to the zeroing of userspace memory on failure. This needs
  126. * to be tested in LKDTM instead, since this test module does not
  127. * expect to explode.
  128. */
  129. ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem,
  130. PAGE_SIZE),
  131. "illegal reversed copy_from_user passed");
  132. #endif
  133. ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
  134. PAGE_SIZE),
  135. "illegal all-kernel copy_to_user passed");
  136. ret |= test(!copy_to_user((char __user *)kmem, bad_usermem,
  137. PAGE_SIZE),
  138. "illegal reversed copy_to_user passed");
  139. #define test_illegal(size, check) \
  140. do { \
  141. val_##size = (check); \
  142. ret |= test(!get_user(val_##size, (size __user *)kmem), \
  143. "illegal get_user (" #size ") passed"); \
  144. ret |= test(val_##size != (size)0, \
  145. "zeroing failure for illegal get_user (" #size ")"); \
  146. if (val_##size != (size)0) { \
  147. pr_info("0x%llx != 0\n", \
  148. (unsigned long long)val_##size); \
  149. } \
  150. ret |= test(!put_user(val_##size, (size __user *)kmem), \
  151. "illegal put_user (" #size ") passed"); \
  152. } while (0)
  153. test_illegal(u8, 0x5a);
  154. test_illegal(u16, 0x5a5b);
  155. test_illegal(u32, 0x5a5b5c5d);
  156. #ifdef TEST_U64
  157. test_illegal(u64, 0x5a5b5c5d6a6b6c6d);
  158. #endif
  159. #undef test_illegal
  160. vm_munmap(user_addr, PAGE_SIZE * 2);
  161. kfree(kmem);
  162. if (ret == 0) {
  163. pr_info("tests passed.\n");
  164. return 0;
  165. }
  166. return -EINVAL;
  167. }
  168. module_init(test_user_copy_init);
  169. static void __exit test_user_copy_exit(void)
  170. {
  171. pr_info("unloaded.\n");
  172. }
  173. module_exit(test_user_copy_exit);
  174. MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
  175. MODULE_LICENSE("GPL");