Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usercopy: Convert test_user_copy to KUnit test

Convert the runtime tests of hardened usercopy to standard KUnit tests.

Additionally disable usercopy_test_invalid() for systems with separate
address spaces (or no MMU) since it's not sensible to test for address
confusion there (e.g. m68k).

Co-developed-by: Vitor Massaru Iha <vitor@massaru.org>
Signed-off-by: Vitor Massaru Iha <vitor@massaru.org>
Link: https://lore.kernel.org/r/20200721174654.72132-1-vitor@massaru.org
Tested-by: Ivan Orlov <ivan.orlov0322@gmail.com>
Reviewed-by: David Gow <davidgow@google.com>
Signed-off-by: Kees Cook <kees@kernel.org>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

Kees Cook and committed by
Shuah Khan
cf6219ee 51104c19

+340 -344
+1
MAINTAINERS
··· 11962 11962 F: include/linux/overflow.h 11963 11963 F: include/linux/randomize_kstack.h 11964 11964 F: kernel/configs/hardening.config 11965 + F: lib/usercopy_kunit.c 11965 11966 F: mm/usercopy.c 11966 11967 K: \b(add|choose)_random_kstack_offset\b 11967 11968 K: \b__check_(object_size|heap_object)\b
+9 -12
lib/Kconfig.debug
··· 2505 2505 2506 2506 If unsure, say N. 2507 2507 2508 - config TEST_USER_COPY 2509 - tristate "Test user/kernel boundary protections" 2510 - depends on m 2511 - help 2512 - This builds the "test_user_copy" module that runs sanity checks 2513 - on the copy_to/from_user infrastructure, making sure basic 2514 - user/kernel boundary testing is working. If it fails to load, 2515 - a regression has been detected in the user/kernel memory boundary 2516 - protections. 2517 - 2518 - If unsure, say N. 2519 - 2520 2508 config TEST_BPF 2521 2509 tristate "Test BPF filter functionality" 2522 2510 depends on m && NET ··· 2801 2813 2802 2814 This is intended to help people writing architecture-specific 2803 2815 optimized versions. If unsure, say N. 2816 + 2817 + config USERCOPY_KUNIT_TEST 2818 + tristate "KUnit Test for user/kernel boundary protections" 2819 + depends on KUNIT 2820 + default KUNIT_ALL_TESTS 2821 + help 2822 + This builds the "usercopy_kunit" module that runs sanity checks 2823 + on the copy_to/from_user infrastructure, making sure basic 2824 + user/kernel boundary testing is working. 2804 2825 2805 2826 config TEST_UDELAY 2806 2827 tristate "udelay test driver"
+1 -1
lib/Makefile
··· 78 78 obj-$(CONFIG_TEST_VMALLOC) += test_vmalloc.o 79 79 obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o 80 80 obj-$(CONFIG_TEST_SORT) += test_sort.o 81 - obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o 82 81 obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o 83 82 obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o 84 83 obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o ··· 387 388 CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN) 388 389 obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o 389 390 obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o 391 + obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o 390 392 391 393 obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o 392 394
-331
lib/test_user_copy.c
··· 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 - 11 - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 - 13 - #include <linux/mman.h> 14 - #include <linux/module.h> 15 - #include <linux/sched.h> 16 - #include <linux/slab.h> 17 - #include <linux/uaccess.h> 18 - #include <linux/vmalloc.h> 19 - 20 - /* 21 - * Several 32-bit architectures support 64-bit {get,put}_user() calls. 22 - * As there doesn't appear to be anything that can safely determine 23 - * their capability at compile-time, we just have to opt-out certain archs. 24 - */ 25 - #if BITS_PER_LONG == 64 || (!(defined(CONFIG_ARM) && !defined(MMU)) && \ 26 - !defined(CONFIG_M68K) && \ 27 - !defined(CONFIG_MICROBLAZE) && \ 28 - !defined(CONFIG_NIOS2) && \ 29 - !defined(CONFIG_PPC32) && \ 30 - !defined(CONFIG_SUPERH)) 31 - # define TEST_U64 32 - #endif 33 - 34 - #define test(condition, msg, ...) \ 35 - ({ \ 36 - int cond = (condition); \ 37 - if (cond) \ 38 - pr_warn("[%d] " msg "\n", __LINE__, ##__VA_ARGS__); \ 39 - cond; \ 40 - }) 41 - 42 - static bool is_zeroed(void *from, size_t size) 43 - { 44 - return memchr_inv(from, 0x0, size) == NULL; 45 - } 46 - 47 - static int test_check_nonzero_user(char *kmem, char __user *umem, size_t size) 48 - { 49 - int ret = 0; 50 - size_t start, end, i, zero_start, zero_end; 51 - 52 - if (test(size < 2 * PAGE_SIZE, "buffer too small")) 53 - return -EINVAL; 54 - 55 - /* 56 - * We want to cross a page boundary to exercise the code more 57 - * effectively. We also don't want to make the size we scan too large, 58 - * otherwise the test can take a long time and cause soft lockups. So 59 - * scan a 1024 byte region across the page boundary. 60 - */ 61 - size = 1024; 62 - start = PAGE_SIZE - (size / 2); 63 - 64 - kmem += start; 65 - umem += start; 66 - 67 - zero_start = size / 4; 68 - zero_end = size - zero_start; 69 - 70 - /* 71 - * We conduct a series of check_nonzero_user() tests on a block of 72 - * memory with the following byte-pattern (trying every possible 73 - * [start,end] pair): 74 - * 75 - * [ 00 ff 00 ff ... 00 00 00 00 ... ff 00 ff 00 ] 76 - * 77 - * And we verify that check_nonzero_user() acts identically to 78 - * memchr_inv(). 79 - */ 80 - 81 - memset(kmem, 0x0, size); 82 - for (i = 1; i < zero_start; i += 2) 83 - kmem[i] = 0xff; 84 - for (i = zero_end; i < size; i += 2) 85 - kmem[i] = 0xff; 86 - 87 - ret |= test(copy_to_user(umem, kmem, size), 88 - "legitimate copy_to_user failed"); 89 - 90 - for (start = 0; start <= size; start++) { 91 - for (end = start; end <= size; end++) { 92 - size_t len = end - start; 93 - int retval = check_zeroed_user(umem + start, len); 94 - int expected = is_zeroed(kmem + start, len); 95 - 96 - ret |= test(retval != expected, 97 - "check_nonzero_user(=%d) != memchr_inv(=%d) mismatch (start=%zu, end=%zu)", 98 - retval, expected, start, end); 99 - } 100 - } 101 - 102 - return ret; 103 - } 104 - 105 - static int test_copy_struct_from_user(char *kmem, char __user *umem, 106 - size_t size) 107 - { 108 - int ret = 0; 109 - char *umem_src = NULL, *expected = NULL; 110 - size_t ksize, usize; 111 - 112 - umem_src = kmalloc(size, GFP_KERNEL); 113 - ret = test(umem_src == NULL, "kmalloc failed"); 114 - if (ret) 115 - goto out_free; 116 - 117 - expected = kmalloc(size, GFP_KERNEL); 118 - ret = test(expected == NULL, "kmalloc failed"); 119 - if (ret) 120 - goto out_free; 121 - 122 - /* Fill umem with a fixed byte pattern. */ 123 - memset(umem_src, 0x3e, size); 124 - ret |= test(copy_to_user(umem, umem_src, size), 125 - "legitimate copy_to_user failed"); 126 - 127 - /* Check basic case -- (usize == ksize). */ 128 - ksize = size; 129 - usize = size; 130 - 131 - memcpy(expected, umem_src, ksize); 132 - 133 - memset(kmem, 0x0, size); 134 - ret |= test(copy_struct_from_user(kmem, ksize, umem, usize), 135 - "copy_struct_from_user(usize == ksize) failed"); 136 - ret |= test(memcmp(kmem, expected, ksize), 137 - "copy_struct_from_user(usize == ksize) gives unexpected copy"); 138 - 139 - /* Old userspace case -- (usize < ksize). */ 140 - ksize = size; 141 - usize = size / 2; 142 - 143 - memcpy(expected, umem_src, usize); 144 - memset(expected + usize, 0x0, ksize - usize); 145 - 146 - memset(kmem, 0x0, size); 147 - ret |= test(copy_struct_from_user(kmem, ksize, umem, usize), 148 - "copy_struct_from_user(usize < ksize) failed"); 149 - ret |= test(memcmp(kmem, expected, ksize), 150 - "copy_struct_from_user(usize < ksize) gives unexpected copy"); 151 - 152 - /* New userspace (-E2BIG) case -- (usize > ksize). */ 153 - ksize = size / 2; 154 - usize = size; 155 - 156 - memset(kmem, 0x0, size); 157 - ret |= test(copy_struct_from_user(kmem, ksize, umem, usize) != -E2BIG, 158 - "copy_struct_from_user(usize > ksize) didn't give E2BIG"); 159 - 160 - /* New userspace (success) case -- (usize > ksize). */ 161 - ksize = size / 2; 162 - usize = size; 163 - 164 - memcpy(expected, umem_src, ksize); 165 - ret |= test(clear_user(umem + ksize, usize - ksize), 166 - "legitimate clear_user failed"); 167 - 168 - memset(kmem, 0x0, size); 169 - ret |= test(copy_struct_from_user(kmem, ksize, umem, usize), 170 - "copy_struct_from_user(usize > ksize) failed"); 171 - ret |= test(memcmp(kmem, expected, ksize), 172 - "copy_struct_from_user(usize > ksize) gives unexpected copy"); 173 - 174 - out_free: 175 - kfree(expected); 176 - kfree(umem_src); 177 - return ret; 178 - } 179 - 180 - static int __init test_user_copy_init(void) 181 - { 182 - int ret = 0; 183 - char *kmem; 184 - char __user *usermem; 185 - char *bad_usermem; 186 - unsigned long user_addr; 187 - u8 val_u8; 188 - u16 val_u16; 189 - u32 val_u32; 190 - #ifdef TEST_U64 191 - u64 val_u64; 192 - #endif 193 - 194 - kmem = kmalloc(PAGE_SIZE * 2, GFP_KERNEL); 195 - if (!kmem) 196 - return -ENOMEM; 197 - 198 - user_addr = vm_mmap(NULL, 0, PAGE_SIZE * 2, 199 - PROT_READ | PROT_WRITE | PROT_EXEC, 200 - MAP_ANONYMOUS | MAP_PRIVATE, 0); 201 - if (user_addr >= (unsigned long)(TASK_SIZE)) { 202 - pr_warn("Failed to allocate user memory\n"); 203 - kfree(kmem); 204 - return -ENOMEM; 205 - } 206 - 207 - usermem = (char __user *)user_addr; 208 - bad_usermem = (char *)user_addr; 209 - 210 - /* 211 - * Legitimate usage: none of these copies should fail. 212 - */ 213 - memset(kmem, 0x3a, PAGE_SIZE * 2); 214 - ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE), 215 - "legitimate copy_to_user failed"); 216 - memset(kmem, 0x0, PAGE_SIZE); 217 - ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE), 218 - "legitimate copy_from_user failed"); 219 - ret |= test(memcmp(kmem, kmem + PAGE_SIZE, PAGE_SIZE), 220 - "legitimate usercopy failed to copy data"); 221 - 222 - #define test_legit(size, check) \ 223 - do { \ 224 - val_##size = check; \ 225 - ret |= test(put_user(val_##size, (size __user *)usermem), \ 226 - "legitimate put_user (" #size ") failed"); \ 227 - val_##size = 0; \ 228 - ret |= test(get_user(val_##size, (size __user *)usermem), \ 229 - "legitimate get_user (" #size ") failed"); \ 230 - ret |= test(val_##size != check, \ 231 - "legitimate get_user (" #size ") failed to do copy"); \ 232 - if (val_##size != check) { \ 233 - pr_info("0x%llx != 0x%llx\n", \ 234 - (unsigned long long)val_##size, \ 235 - (unsigned long long)check); \ 236 - } \ 237 - } while (0) 238 - 239 - test_legit(u8, 0x5a); 240 - test_legit(u16, 0x5a5b); 241 - test_legit(u32, 0x5a5b5c5d); 242 - #ifdef TEST_U64 243 - test_legit(u64, 0x5a5b5c5d6a6b6c6d); 244 - #endif 245 - #undef test_legit 246 - 247 - /* Test usage of check_nonzero_user(). */ 248 - ret |= test_check_nonzero_user(kmem, usermem, 2 * PAGE_SIZE); 249 - /* Test usage of copy_struct_from_user(). */ 250 - ret |= test_copy_struct_from_user(kmem, usermem, 2 * PAGE_SIZE); 251 - 252 - /* 253 - * Invalid usage: none of these copies should succeed. 254 - */ 255 - 256 - /* Prepare kernel memory with check values. */ 257 - memset(kmem, 0x5a, PAGE_SIZE); 258 - memset(kmem + PAGE_SIZE, 0, PAGE_SIZE); 259 - 260 - /* Reject kernel-to-kernel copies through copy_from_user(). */ 261 - ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE), 262 - PAGE_SIZE), 263 - "illegal all-kernel copy_from_user passed"); 264 - 265 - /* Destination half of buffer should have been zeroed. */ 266 - ret |= test(memcmp(kmem + PAGE_SIZE, kmem, PAGE_SIZE), 267 - "zeroing failure for illegal all-kernel copy_from_user"); 268 - 269 - #if 0 270 - /* 271 - * When running with SMAP/PAN/etc, this will Oops the kernel 272 - * due to the zeroing of userspace memory on failure. This needs 273 - * to be tested in LKDTM instead, since this test module does not 274 - * expect to explode. 275 - */ 276 - ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem, 277 - PAGE_SIZE), 278 - "illegal reversed copy_from_user passed"); 279 - #endif 280 - ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE, 281 - PAGE_SIZE), 282 - "illegal all-kernel copy_to_user passed"); 283 - ret |= test(!copy_to_user((char __user *)kmem, bad_usermem, 284 - PAGE_SIZE), 285 - "illegal reversed copy_to_user passed"); 286 - 287 - #define test_illegal(size, check) \ 288 - do { \ 289 - val_##size = (check); \ 290 - ret |= test(!get_user(val_##size, (size __user *)kmem), \ 291 - "illegal get_user (" #size ") passed"); \ 292 - ret |= test(val_##size != (size)0, \ 293 - "zeroing failure for illegal get_user (" #size ")"); \ 294 - if (val_##size != (size)0) { \ 295 - pr_info("0x%llx != 0\n", \ 296 - (unsigned long long)val_##size); \ 297 - } \ 298 - ret |= test(!put_user(val_##size, (size __user *)kmem), \ 299 - "illegal put_user (" #size ") passed"); \ 300 - } while (0) 301 - 302 - test_illegal(u8, 0x5a); 303 - test_illegal(u16, 0x5a5b); 304 - test_illegal(u32, 0x5a5b5c5d); 305 - #ifdef TEST_U64 306 - test_illegal(u64, 0x5a5b5c5d6a6b6c6d); 307 - #endif 308 - #undef test_illegal 309 - 310 - vm_munmap(user_addr, PAGE_SIZE * 2); 311 - kfree(kmem); 312 - 313 - if (ret == 0) { 314 - pr_info("tests passed.\n"); 315 - return 0; 316 - } 317 - 318 - return -EINVAL; 319 - } 320 - 321 - module_init(test_user_copy_init); 322 - 323 - static void __exit test_user_copy_exit(void) 324 - { 325 - pr_info("unloaded.\n"); 326 - } 327 - 328 - module_exit(test_user_copy_exit); 329 - 330 - MODULE_AUTHOR("Kees Cook <keescook@chromium.org>"); 331 - MODULE_LICENSE("GPL");
+329
lib/usercopy_kunit.c
··· 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 + 11 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 + 13 + #include <linux/mman.h> 14 + #include <linux/module.h> 15 + #include <linux/sched.h> 16 + #include <linux/slab.h> 17 + #include <linux/uaccess.h> 18 + #include <kunit/test.h> 19 + 20 + /* 21 + * Several 32-bit architectures support 64-bit {get,put}_user() calls. 22 + * As there doesn't appear to be anything that can safely determine 23 + * their capability at compile-time, we just have to opt-out certain archs. 24 + */ 25 + #if BITS_PER_LONG == 64 || (!(defined(CONFIG_ARM) && !defined(MMU)) && \ 26 + !defined(CONFIG_M68K) && \ 27 + !defined(CONFIG_MICROBLAZE) && \ 28 + !defined(CONFIG_NIOS2) && \ 29 + !defined(CONFIG_PPC32) && \ 30 + !defined(CONFIG_SUPERH)) 31 + # define TEST_U64 32 + #endif 33 + 34 + struct usercopy_test_priv { 35 + char *kmem; 36 + char __user *umem; 37 + size_t size; 38 + }; 39 + 40 + static bool is_zeroed(void *from, size_t size) 41 + { 42 + return memchr_inv(from, 0x0, size) == NULL; 43 + } 44 + 45 + /* Test usage of check_nonzero_user(). */ 46 + static void usercopy_test_check_nonzero_user(struct kunit *test) 47 + { 48 + size_t start, end, i, zero_start, zero_end; 49 + struct usercopy_test_priv *priv = test->priv; 50 + char __user *umem = priv->umem; 51 + char *kmem = priv->kmem; 52 + size_t size = priv->size; 53 + 54 + KUNIT_ASSERT_GE_MSG(test, size, 2 * PAGE_SIZE, "buffer too small"); 55 + 56 + /* 57 + * We want to cross a page boundary to exercise the code more 58 + * effectively. We also don't want to make the size we scan too large, 59 + * otherwise the test can take a long time and cause soft lockups. So 60 + * scan a 1024 byte region across the page boundary. 61 + */ 62 + size = 1024; 63 + start = PAGE_SIZE - (size / 2); 64 + 65 + kmem += start; 66 + umem += start; 67 + 68 + zero_start = size / 4; 69 + zero_end = size - zero_start; 70 + 71 + /* 72 + * We conduct a series of check_nonzero_user() tests on a block of 73 + * memory with the following byte-pattern (trying every possible 74 + * [start,end] pair): 75 + * 76 + * [ 00 ff 00 ff ... 00 00 00 00 ... ff 00 ff 00 ] 77 + * 78 + * And we verify that check_nonzero_user() acts identically to 79 + * memchr_inv(). 80 + */ 81 + 82 + memset(kmem, 0x0, size); 83 + for (i = 1; i < zero_start; i += 2) 84 + kmem[i] = 0xff; 85 + for (i = zero_end; i < size; i += 2) 86 + kmem[i] = 0xff; 87 + 88 + KUNIT_EXPECT_EQ_MSG(test, copy_to_user(umem, kmem, size), 0, 89 + "legitimate copy_to_user failed"); 90 + 91 + for (start = 0; start <= size; start++) { 92 + for (end = start; end <= size; end++) { 93 + size_t len = end - start; 94 + int retval = check_zeroed_user(umem + start, len); 95 + int expected = is_zeroed(kmem + start, len); 96 + 97 + KUNIT_ASSERT_EQ_MSG(test, retval, expected, 98 + "check_nonzero_user(=%d) != memchr_inv(=%d) mismatch (start=%zu, end=%zu)", 99 + retval, expected, start, end); 100 + } 101 + } 102 + } 103 + 104 + /* Test usage of copy_struct_from_user(). */ 105 + static void usercopy_test_copy_struct_from_user(struct kunit *test) 106 + { 107 + char *umem_src = NULL, *expected = NULL; 108 + struct usercopy_test_priv *priv = test->priv; 109 + char __user *umem = priv->umem; 110 + char *kmem = priv->kmem; 111 + size_t size = priv->size; 112 + size_t ksize, usize; 113 + 114 + umem_src = kunit_kmalloc(test, size, GFP_KERNEL); 115 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, umem_src); 116 + 117 + expected = kunit_kmalloc(test, size, GFP_KERNEL); 118 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected); 119 + 120 + /* Fill umem with a fixed byte pattern. */ 121 + memset(umem_src, 0x3e, size); 122 + KUNIT_ASSERT_EQ_MSG(test, copy_to_user(umem, umem_src, size), 0, 123 + "legitimate copy_to_user failed"); 124 + 125 + /* Check basic case -- (usize == ksize). */ 126 + ksize = size; 127 + usize = size; 128 + 129 + memcpy(expected, umem_src, ksize); 130 + 131 + memset(kmem, 0x0, size); 132 + KUNIT_EXPECT_EQ_MSG(test, copy_struct_from_user(kmem, ksize, umem, usize), 0, 133 + "copy_struct_from_user(usize == ksize) failed"); 134 + KUNIT_EXPECT_MEMEQ_MSG(test, kmem, expected, ksize, 135 + "copy_struct_from_user(usize == ksize) gives unexpected copy"); 136 + 137 + /* Old userspace case -- (usize < ksize). */ 138 + ksize = size; 139 + usize = size / 2; 140 + 141 + memcpy(expected, umem_src, usize); 142 + memset(expected + usize, 0x0, ksize - usize); 143 + 144 + memset(kmem, 0x0, size); 145 + KUNIT_EXPECT_EQ_MSG(test, copy_struct_from_user(kmem, ksize, umem, usize), 0, 146 + "copy_struct_from_user(usize < ksize) failed"); 147 + KUNIT_EXPECT_MEMEQ_MSG(test, kmem, expected, ksize, 148 + "copy_struct_from_user(usize < ksize) gives unexpected copy"); 149 + 150 + /* New userspace (-E2BIG) case -- (usize > ksize). */ 151 + ksize = size / 2; 152 + usize = size; 153 + 154 + memset(kmem, 0x0, size); 155 + KUNIT_EXPECT_EQ_MSG(test, copy_struct_from_user(kmem, ksize, umem, usize), -E2BIG, 156 + "copy_struct_from_user(usize > ksize) didn't give E2BIG"); 157 + 158 + /* New userspace (success) case -- (usize > ksize). */ 159 + ksize = size / 2; 160 + usize = size; 161 + 162 + memcpy(expected, umem_src, ksize); 163 + KUNIT_EXPECT_EQ_MSG(test, clear_user(umem + ksize, usize - ksize), 0, 164 + "legitimate clear_user failed"); 165 + 166 + memset(kmem, 0x0, size); 167 + KUNIT_EXPECT_EQ_MSG(test, copy_struct_from_user(kmem, ksize, umem, usize), 0, 168 + "copy_struct_from_user(usize > ksize) failed"); 169 + KUNIT_EXPECT_MEMEQ_MSG(test, kmem, expected, ksize, 170 + "copy_struct_from_user(usize > ksize) gives unexpected copy"); 171 + } 172 + 173 + /* 174 + * Legitimate usage: none of these copies should fail. 175 + */ 176 + static void usercopy_test_valid(struct kunit *test) 177 + { 178 + struct usercopy_test_priv *priv = test->priv; 179 + char __user *usermem = priv->umem; 180 + char *kmem = priv->kmem; 181 + 182 + memset(kmem, 0x3a, PAGE_SIZE * 2); 183 + KUNIT_EXPECT_EQ_MSG(test, 0, copy_to_user(usermem, kmem, PAGE_SIZE), 184 + "legitimate copy_to_user failed"); 185 + memset(kmem, 0x0, PAGE_SIZE); 186 + KUNIT_EXPECT_EQ_MSG(test, 0, copy_from_user(kmem, usermem, PAGE_SIZE), 187 + "legitimate copy_from_user failed"); 188 + KUNIT_EXPECT_MEMEQ_MSG(test, kmem, kmem + PAGE_SIZE, PAGE_SIZE, 189 + "legitimate usercopy failed to copy data"); 190 + 191 + #define test_legit(size, check) \ 192 + do { \ 193 + size val_##size = (check); \ 194 + KUNIT_EXPECT_EQ_MSG(test, 0, \ 195 + put_user(val_##size, (size __user *)usermem), \ 196 + "legitimate put_user (" #size ") failed"); \ 197 + val_##size = 0; \ 198 + KUNIT_EXPECT_EQ_MSG(test, 0, \ 199 + get_user(val_##size, (size __user *)usermem), \ 200 + "legitimate get_user (" #size ") failed"); \ 201 + KUNIT_EXPECT_EQ_MSG(test, val_##size, check, \ 202 + "legitimate get_user (" #size ") failed to do copy"); \ 203 + } while (0) 204 + 205 + test_legit(u8, 0x5a); 206 + test_legit(u16, 0x5a5b); 207 + test_legit(u32, 0x5a5b5c5d); 208 + #ifdef TEST_U64 209 + test_legit(u64, 0x5a5b5c5d6a6b6c6d); 210 + #endif 211 + #undef test_legit 212 + } 213 + 214 + /* 215 + * Invalid usage: none of these copies should succeed. 216 + */ 217 + static void usercopy_test_invalid(struct kunit *test) 218 + { 219 + struct usercopy_test_priv *priv = test->priv; 220 + char __user *usermem = priv->umem; 221 + char *bad_usermem = (char *)usermem; 222 + char *kmem = priv->kmem; 223 + u64 *kmem_u64 = (u64 *)kmem; 224 + 225 + if (IS_ENABLED(CONFIG_ALTERNATE_USER_ADDRESS_SPACE) || 226 + !IS_ENABLED(CONFIG_MMU)) { 227 + kunit_skip(test, "Testing for kernel/userspace address confusion is only sensible on architectures with a shared address space"); 228 + return; 229 + } 230 + 231 + /* Prepare kernel memory with check values. */ 232 + memset(kmem, 0x5a, PAGE_SIZE); 233 + memset(kmem + PAGE_SIZE, 0, PAGE_SIZE); 234 + 235 + /* Reject kernel-to-kernel copies through copy_from_user(). */ 236 + KUNIT_EXPECT_NE_MSG(test, copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE), 237 + PAGE_SIZE), 0, 238 + "illegal all-kernel copy_from_user passed"); 239 + 240 + /* Destination half of buffer should have been zeroed. */ 241 + KUNIT_EXPECT_MEMEQ_MSG(test, kmem + PAGE_SIZE, kmem, PAGE_SIZE, 242 + "zeroing failure for illegal all-kernel copy_from_user"); 243 + 244 + #if 0 245 + /* 246 + * When running with SMAP/PAN/etc, this will Oops the kernel 247 + * due to the zeroing of userspace memory on failure. This needs 248 + * to be tested in LKDTM instead, since this test module does not 249 + * expect to explode. 250 + */ 251 + KUNIT_EXPECT_NE_MSG(test, copy_from_user(bad_usermem, (char __user *)kmem, 252 + PAGE_SIZE), 0, 253 + "illegal reversed copy_from_user passed"); 254 + #endif 255 + KUNIT_EXPECT_NE_MSG(test, copy_to_user((char __user *)kmem, kmem + PAGE_SIZE, 256 + PAGE_SIZE), 0, 257 + "illegal all-kernel copy_to_user passed"); 258 + 259 + KUNIT_EXPECT_NE_MSG(test, copy_to_user((char __user *)kmem, bad_usermem, 260 + PAGE_SIZE), 0, 261 + "illegal reversed copy_to_user passed"); 262 + 263 + #define test_illegal(size, check) \ 264 + do { \ 265 + size val_##size = (check); \ 266 + /* get_user() */ \ 267 + KUNIT_EXPECT_NE_MSG(test, get_user(val_##size, (size __user *)kmem), 0, \ 268 + "illegal get_user (" #size ") passed"); \ 269 + KUNIT_EXPECT_EQ_MSG(test, val_##size, 0, \ 270 + "zeroing failure for illegal get_user (" #size ")"); \ 271 + /* put_user() */ \ 272 + *kmem_u64 = 0xF09FA4AFF09FA4AF; \ 273 + KUNIT_EXPECT_NE_MSG(test, put_user(val_##size, (size __user *)kmem), 0, \ 274 + "illegal put_user (" #size ") passed"); \ 275 + KUNIT_EXPECT_EQ_MSG(test, *kmem_u64, 0xF09FA4AFF09FA4AF, \ 276 + "illegal put_user (" #size ") wrote to kernel memory!"); \ 277 + } while (0) 278 + 279 + test_illegal(u8, 0x5a); 280 + test_illegal(u16, 0x5a5b); 281 + test_illegal(u32, 0x5a5b5c5d); 282 + #ifdef TEST_U64 283 + test_illegal(u64, 0x5a5b5c5d6a6b6c6d); 284 + #endif 285 + #undef test_illegal 286 + } 287 + 288 + static int usercopy_test_init(struct kunit *test) 289 + { 290 + struct usercopy_test_priv *priv; 291 + unsigned long user_addr; 292 + 293 + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 294 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv); 295 + test->priv = priv; 296 + priv->size = PAGE_SIZE * 2; 297 + 298 + priv->kmem = kunit_kmalloc(test, priv->size, GFP_KERNEL); 299 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->kmem); 300 + 301 + user_addr = kunit_vm_mmap(test, NULL, 0, priv->size, 302 + PROT_READ | PROT_WRITE | PROT_EXEC, 303 + MAP_ANONYMOUS | MAP_PRIVATE, 0); 304 + KUNIT_ASSERT_NE_MSG(test, user_addr, 0, 305 + "Could not create userspace mm"); 306 + KUNIT_ASSERT_LT_MSG(test, user_addr, (unsigned long)TASK_SIZE, 307 + "Failed to allocate user memory"); 308 + priv->umem = (char __user *)user_addr; 309 + 310 + return 0; 311 + } 312 + 313 + static struct kunit_case usercopy_test_cases[] = { 314 + KUNIT_CASE(usercopy_test_valid), 315 + KUNIT_CASE(usercopy_test_invalid), 316 + KUNIT_CASE(usercopy_test_check_nonzero_user), 317 + KUNIT_CASE(usercopy_test_copy_struct_from_user), 318 + {} 319 + }; 320 + 321 + static struct kunit_suite usercopy_test_suite = { 322 + .name = "usercopy", 323 + .init = usercopy_test_init, 324 + .test_cases = usercopy_test_cases, 325 + }; 326 + 327 + kunit_test_suites(&usercopy_test_suite); 328 + MODULE_AUTHOR("Kees Cook <kees@kernel.org>"); 329 + MODULE_LICENSE("GPL");