1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * This is for all the tests related to copy_to_user() and copy_from_user() 4 * hardening. 5 */ 6 #include "lkdtm.h" 7 #include <linux/slab.h> 8 #include <linux/highmem.h> 9 #include <linux/vmalloc.h> 10 #include <linux/sched/task_stack.h> 11 #include <linux/mman.h> 12 #include <linux/uaccess.h> 13 #include <asm/cacheflush.h> 14 15 /* 16 * Many of the tests here end up using const sizes, but those would 17 * normally be ignored by hardened usercopy, so force the compiler 18 * into choosing the non-const path to make sure we trigger the 19 * hardened usercopy checks by added "unconst" to all the const copies, 20 * and making sure "cache_size" isn't optimized into a const. 21 */ 22 static volatile size_t unconst; 23 static volatile size_t cache_size = 1024; 24 static struct kmem_cache *whitelist_cache; 25 26 static const unsigned char test_text[] = "This is a test.\n"; 27 28 /* 29 * Instead of adding -Wno-return-local-addr, just pass the stack address 30 * through a function to obfuscate it from the compiler. 31 */ 32 static noinline unsigned char *trick_compiler(unsigned char *stack) 33 { 34 return stack + unconst; 35 } 36 37 static noinline unsigned char *do_usercopy_stack_callee(int value) 38 { 39 unsigned char buf[128]; 40 int i; 41 42 /* Exercise stack to avoid everything living in registers. */ 43 for (i = 0; i < sizeof(buf); i++) { 44 buf[i] = value & 0xff; 45 } 46 47 /* 48 * Put the target buffer in the middle of stack allocation 49 * so that we don't step on future stack users regardless 50 * of stack growth direction. 51 */ 52 return trick_compiler(&buf[(128/2)-32]); 53 } 54 55 static noinline void do_usercopy_stack(bool to_user, bool bad_frame) 56 { 57 unsigned long user_addr; 58 unsigned char good_stack[32]; 59 unsigned char *bad_stack; 60 int i; 61 62 /* Exercise stack to avoid everything living in registers. */ 63 for (i = 0; i < sizeof(good_stack); i++) 64 good_stack[i] = test_text[i % sizeof(test_text)]; 65 66 /* This is a pointer to outside our current stack frame. */ 67 if (bad_frame) { 68 bad_stack = do_usercopy_stack_callee((uintptr_t)&bad_stack); 69 } else { 70 /* Put start address just inside stack. */ 71 bad_stack = task_stack_page(current) + THREAD_SIZE; 72 bad_stack -= sizeof(unsigned long); 73 } 74 75 #ifdef ARCH_HAS_CURRENT_STACK_POINTER 76 pr_info("stack : %px\n", (void *)current_stack_pointer); 77 #endif 78 pr_info("good_stack: %px-%px\n", good_stack, good_stack + sizeof(good_stack)); 79 pr_info("bad_stack : %px-%px\n", bad_stack, bad_stack + sizeof(good_stack)); 80 81 user_addr = vm_mmap(NULL, 0, PAGE_SIZE, 82 PROT_READ | PROT_WRITE | PROT_EXEC, 83 MAP_ANONYMOUS | MAP_PRIVATE, 0); 84 if (user_addr >= TASK_SIZE) { 85 pr_warn("Failed to allocate user memory\n"); 86 return; 87 } 88 89 if (to_user) { 90 pr_info("attempting good copy_to_user of local stack\n"); 91 if (copy_to_user((void __user *)user_addr, good_stack, 92 unconst + sizeof(good_stack))) { 93 pr_warn("copy_to_user failed unexpectedly?!\n"); 94 goto free_user; 95 } 96 97 pr_info("attempting bad copy_to_user of distant stack\n"); 98 if (copy_to_user((void __user *)user_addr, bad_stack, 99 unconst + sizeof(good_stack))) { 100 pr_warn("copy_to_user failed, but lacked Oops\n"); 101 goto free_user; 102 } 103 } else { 104 /* 105 * There isn't a safe way to not be protected by usercopy 106 * if we're going to write to another thread's stack. 107 */ 108 if (!bad_frame) 109 goto free_user; 110 111 pr_info("attempting good copy_from_user of local stack\n"); 112 if (copy_from_user(good_stack, (void __user *)user_addr, 113 unconst + sizeof(good_stack))) { 114 pr_warn("copy_from_user failed unexpectedly?!\n"); 115 goto free_user; 116 } 117 118 pr_info("attempting bad copy_from_user of distant stack\n"); 119 if (copy_from_user(bad_stack, (void __user *)user_addr, 120 unconst + sizeof(good_stack))) { 121 pr_warn("copy_from_user failed, but lacked Oops\n"); 122 goto free_user; 123 } 124 } 125 126 free_user: 127 vm_munmap(user_addr, PAGE_SIZE); 128 } 129 130 /* 131 * This checks for whole-object size validation with hardened usercopy, 132 * with or without usercopy whitelisting. 133 */ 134 static void do_usercopy_slab_size(bool to_user) 135 { 136 unsigned long user_addr; 137 unsigned char *one, *two; 138 void __user *test_user_addr; 139 void *test_kern_addr; 140 size_t size = unconst + 1024; 141 142 one = kmalloc(size, GFP_KERNEL); 143 two = kmalloc(size, GFP_KERNEL); 144 if (!one || !two) { 145 pr_warn("Failed to allocate kernel memory\n"); 146 goto free_kernel; 147 } 148 149 user_addr = vm_mmap(NULL, 0, PAGE_SIZE, 150 PROT_READ | PROT_WRITE | PROT_EXEC, 151 MAP_ANONYMOUS | MAP_PRIVATE, 0); 152 if (user_addr >= TASK_SIZE) { 153 pr_warn("Failed to allocate user memory\n"); 154 goto free_kernel; 155 } 156 157 memset(one, 'A', size); 158 memset(two, 'B', size); 159 160 test_user_addr = (void __user *)(user_addr + 16); 161 test_kern_addr = one + 16; 162 163 if (to_user) { 164 pr_info("attempting good copy_to_user of correct size\n"); 165 if (copy_to_user(test_user_addr, test_kern_addr, size / 2)) { 166 pr_warn("copy_to_user failed unexpectedly?!\n"); 167 goto free_user; 168 } 169 170 pr_info("attempting bad copy_to_user of too large size\n"); 171 if (copy_to_user(test_user_addr, test_kern_addr, size)) { 172 pr_warn("copy_to_user failed, but lacked Oops\n"); 173 goto free_user; 174 } 175 } else { 176 pr_info("attempting good copy_from_user of correct size\n"); 177 if (copy_from_user(test_kern_addr, test_user_addr, size / 2)) { 178 pr_warn("copy_from_user failed unexpectedly?!\n"); 179 goto free_user; 180 } 181 182 pr_info("attempting bad copy_from_user of too large size\n"); 183 if (copy_from_user(test_kern_addr, test_user_addr, size)) { 184 pr_warn("copy_from_user failed, but lacked Oops\n"); 185 goto free_user; 186 } 187 } 188 pr_err("FAIL: bad usercopy not detected!\n"); 189 pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy"); 190 191 free_user: 192 vm_munmap(user_addr, PAGE_SIZE); 193 free_kernel: 194 kfree(one); 195 kfree(two); 196 } 197 198 /* 199 * This checks for the specific whitelist window within an object. If this 200 * test passes, then do_usercopy_slab_size() tests will pass too. 201 */ 202 static void do_usercopy_slab_whitelist(bool to_user) 203 { 204 unsigned long user_alloc; 205 unsigned char *buf = NULL; 206 unsigned char __user *user_addr; 207 size_t offset, size; 208 209 /* Make sure cache was prepared. */ 210 if (!whitelist_cache) { 211 pr_warn("Failed to allocate kernel cache\n"); 212 return; 213 } 214 215 /* 216 * Allocate a buffer with a whitelisted window in the buffer. 217 */ 218 buf = kmem_cache_alloc(whitelist_cache, GFP_KERNEL); 219 if (!buf) { 220 pr_warn("Failed to allocate buffer from whitelist cache\n"); 221 goto free_alloc; 222 } 223 224 /* Allocate user memory we'll poke at. */ 225 user_alloc = vm_mmap(NULL, 0, PAGE_SIZE, 226 PROT_READ | PROT_WRITE | PROT_EXEC, 227 MAP_ANONYMOUS | MAP_PRIVATE, 0); 228 if (user_alloc >= TASK_SIZE) { 229 pr_warn("Failed to allocate user memory\n"); 230 goto free_alloc; 231 } 232 user_addr = (void __user *)user_alloc; 233 234 memset(buf, 'B', cache_size); 235 236 /* Whitelisted window in buffer, from kmem_cache_create_usercopy. */ 237 offset = (cache_size / 4) + unconst; 238 size = (cache_size / 16) + unconst; 239 240 if (to_user) { 241 pr_info("attempting good copy_to_user inside whitelist\n"); 242 if (copy_to_user(user_addr, buf + offset, size)) { 243 pr_warn("copy_to_user failed unexpectedly?!\n"); 244 goto free_user; 245 } 246 247 pr_info("attempting bad copy_to_user outside whitelist\n"); 248 if (copy_to_user(user_addr, buf + offset - 1, size)) { 249 pr_warn("copy_to_user failed, but lacked Oops\n"); 250 goto free_user; 251 } 252 } else { 253 pr_info("attempting good copy_from_user inside whitelist\n"); 254 if (copy_from_user(buf + offset, user_addr, size)) { 255 pr_warn("copy_from_user failed unexpectedly?!\n"); 256 goto free_user; 257 } 258 259 pr_info("attempting bad copy_from_user outside whitelist\n"); 260 if (copy_from_user(buf + offset - 1, user_addr, size)) { 261 pr_warn("copy_from_user failed, but lacked Oops\n"); 262 goto free_user; 263 } 264 } 265 pr_err("FAIL: bad usercopy not detected!\n"); 266 pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy"); 267 268 free_user: 269 vm_munmap(user_alloc, PAGE_SIZE); 270 free_alloc: 271 if (buf) 272 kmem_cache_free(whitelist_cache, buf); 273 } 274 275 /* Callable tests. */ 276 static void lkdtm_USERCOPY_SLAB_SIZE_TO(void) 277 { 278 do_usercopy_slab_size(true); 279 } 280 281 static void lkdtm_USERCOPY_SLAB_SIZE_FROM(void) 282 { 283 do_usercopy_slab_size(false); 284 } 285 286 static void lkdtm_USERCOPY_SLAB_WHITELIST_TO(void) 287 { 288 do_usercopy_slab_whitelist(true); 289 } 290 291 static void lkdtm_USERCOPY_SLAB_WHITELIST_FROM(void) 292 { 293 do_usercopy_slab_whitelist(false); 294 } 295 296 static void lkdtm_USERCOPY_STACK_FRAME_TO(void) 297 { 298 do_usercopy_stack(true, true); 299 } 300 301 static void lkdtm_USERCOPY_STACK_FRAME_FROM(void) 302 { 303 do_usercopy_stack(false, true); 304 } 305 306 static void lkdtm_USERCOPY_STACK_BEYOND(void) 307 { 308 do_usercopy_stack(true, false); 309 } 310 311 static void lkdtm_USERCOPY_KERNEL(void) 312 { 313 unsigned long user_addr; 314 315 user_addr = vm_mmap(NULL, 0, PAGE_SIZE, 316 PROT_READ | PROT_WRITE | PROT_EXEC, 317 MAP_ANONYMOUS | MAP_PRIVATE, 0); 318 if (user_addr >= TASK_SIZE) { 319 pr_warn("Failed to allocate user memory\n"); 320 return; 321 } 322 323 pr_info("attempting good copy_to_user from kernel rodata: %px\n", 324 test_text); 325 if (copy_to_user((void __user *)user_addr, test_text, 326 unconst + sizeof(test_text))) { 327 pr_warn("copy_to_user failed unexpectedly?!\n"); 328 goto free_user; 329 } 330 331 pr_info("attempting bad copy_to_user from kernel text: %px\n", 332 vm_mmap); 333 if (copy_to_user((void __user *)user_addr, function_nocfi(vm_mmap), 334 unconst + PAGE_SIZE)) { 335 pr_warn("copy_to_user failed, but lacked Oops\n"); 336 goto free_user; 337 } 338 pr_err("FAIL: bad copy_to_user() not detected!\n"); 339 pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy"); 340 341 free_user: 342 vm_munmap(user_addr, PAGE_SIZE); 343 } 344 345 /* 346 * This expects "kaddr" to point to a PAGE_SIZE allocation, which means 347 * a more complete test that would include copy_from_user() would risk 348 * memory corruption. Just test copy_to_user() here, as that exercises 349 * almost exactly the same code paths. 350 */ 351 static void do_usercopy_page_span(const char *name, void *kaddr) 352 { 353 unsigned long uaddr; 354 355 uaddr = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_WRITE, 356 MAP_ANONYMOUS | MAP_PRIVATE, 0); 357 if (uaddr >= TASK_SIZE) { 358 pr_warn("Failed to allocate user memory\n"); 359 return; 360 } 361 362 /* Initialize contents. */ 363 memset(kaddr, 0xAA, PAGE_SIZE); 364 365 /* Bump the kaddr forward to detect a page-spanning overflow. */ 366 kaddr += PAGE_SIZE / 2; 367 368 pr_info("attempting good copy_to_user() from kernel %s: %px\n", 369 name, kaddr); 370 if (copy_to_user((void __user *)uaddr, kaddr, 371 unconst + (PAGE_SIZE / 2))) { 372 pr_err("copy_to_user() failed unexpectedly?!\n"); 373 goto free_user; 374 } 375 376 pr_info("attempting bad copy_to_user() from kernel %s: %px\n", 377 name, kaddr); 378 if (copy_to_user((void __user *)uaddr, kaddr, unconst + PAGE_SIZE)) { 379 pr_warn("Good, copy_to_user() failed, but lacked Oops(?!)\n"); 380 goto free_user; 381 } 382 383 pr_err("FAIL: bad copy_to_user() not detected!\n"); 384 pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy"); 385 386 free_user: 387 vm_munmap(uaddr, PAGE_SIZE); 388 } 389 390 static void lkdtm_USERCOPY_VMALLOC(void) 391 { 392 void *addr; 393 394 addr = vmalloc(PAGE_SIZE); 395 if (!addr) { 396 pr_err("vmalloc() failed!?\n"); 397 return; 398 } 399 do_usercopy_page_span("vmalloc", addr); 400 vfree(addr); 401 } 402 403 static void lkdtm_USERCOPY_FOLIO(void) 404 { 405 struct folio *folio; 406 void *addr; 407 408 /* 409 * FIXME: Folio checking currently misses 0-order allocations, so 410 * allocate and bump forward to the last page. 411 */ 412 folio = folio_alloc(GFP_KERNEL | __GFP_ZERO, 1); 413 if (!folio) { 414 pr_err("folio_alloc() failed!?\n"); 415 return; 416 } 417 addr = folio_address(folio); 418 if (addr) 419 do_usercopy_page_span("folio", addr + PAGE_SIZE); 420 else 421 pr_err("folio_address() failed?!\n"); 422 folio_put(folio); 423 } 424 425 void __init lkdtm_usercopy_init(void) 426 { 427 /* Prepare cache that lacks SLAB_USERCOPY flag. */ 428 whitelist_cache = 429 kmem_cache_create_usercopy("lkdtm-usercopy", cache_size, 430 0, 0, 431 cache_size / 4, 432 cache_size / 16, 433 NULL); 434 } 435 436 void __exit lkdtm_usercopy_exit(void) 437 { 438 kmem_cache_destroy(whitelist_cache); 439 } 440 441 static struct crashtype crashtypes[] = { 442 CRASHTYPE(USERCOPY_SLAB_SIZE_TO), 443 CRASHTYPE(USERCOPY_SLAB_SIZE_FROM), 444 CRASHTYPE(USERCOPY_SLAB_WHITELIST_TO), 445 CRASHTYPE(USERCOPY_SLAB_WHITELIST_FROM), 446 CRASHTYPE(USERCOPY_STACK_FRAME_TO), 447 CRASHTYPE(USERCOPY_STACK_FRAME_FROM), 448 CRASHTYPE(USERCOPY_STACK_BEYOND), 449 CRASHTYPE(USERCOPY_VMALLOC), 450 CRASHTYPE(USERCOPY_FOLIO), 451 CRASHTYPE(USERCOPY_KERNEL), 452 }; 453 454 struct crashtype_category usercopy_crashtypes = { 455 .crashtypes = crashtypes, 456 .len = ARRAY_SIZE(crashtypes), 457 }; 458