at v5.1 14 kB view raw
1/* 2 * 3 * Copyright (c) 2014 Samsung Electronics Co., Ltd. 4 * Author: Andrey Ryabinin <a.ryabinin@samsung.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 */ 11 12#define pr_fmt(fmt) "kasan test: %s " fmt, __func__ 13 14#include <linux/delay.h> 15#include <linux/kernel.h> 16#include <linux/mman.h> 17#include <linux/mm.h> 18#include <linux/printk.h> 19#include <linux/slab.h> 20#include <linux/string.h> 21#include <linux/uaccess.h> 22#include <linux/module.h> 23#include <linux/kasan.h> 24 25/* 26 * Note: test functions are marked noinline so that their names appear in 27 * reports. 28 */ 29 30static noinline void __init kmalloc_oob_right(void) 31{ 32 char *ptr; 33 size_t size = 123; 34 35 pr_info("out-of-bounds to right\n"); 36 ptr = kmalloc(size, GFP_KERNEL); 37 if (!ptr) { 38 pr_err("Allocation failed\n"); 39 return; 40 } 41 42 ptr[size] = 'x'; 43 kfree(ptr); 44} 45 46static noinline void __init kmalloc_oob_left(void) 47{ 48 char *ptr; 49 size_t size = 15; 50 51 pr_info("out-of-bounds to left\n"); 52 ptr = kmalloc(size, GFP_KERNEL); 53 if (!ptr) { 54 pr_err("Allocation failed\n"); 55 return; 56 } 57 58 *ptr = *(ptr - 1); 59 kfree(ptr); 60} 61 62static noinline void __init kmalloc_node_oob_right(void) 63{ 64 char *ptr; 65 size_t size = 4096; 66 67 pr_info("kmalloc_node(): out-of-bounds to right\n"); 68 ptr = kmalloc_node(size, GFP_KERNEL, 0); 69 if (!ptr) { 70 pr_err("Allocation failed\n"); 71 return; 72 } 73 74 ptr[size] = 0; 75 kfree(ptr); 76} 77 78#ifdef CONFIG_SLUB 79static noinline void __init kmalloc_pagealloc_oob_right(void) 80{ 81 char *ptr; 82 size_t size = KMALLOC_MAX_CACHE_SIZE + 10; 83 84 /* Allocate a chunk that does not fit into a SLUB cache to trigger 85 * the page allocator fallback. 86 */ 87 pr_info("kmalloc pagealloc allocation: out-of-bounds to right\n"); 88 ptr = kmalloc(size, GFP_KERNEL); 89 if (!ptr) { 90 pr_err("Allocation failed\n"); 91 return; 92 } 93 94 ptr[size] = 0; 95 kfree(ptr); 96} 97 98static noinline void __init kmalloc_pagealloc_uaf(void) 99{ 100 char *ptr; 101 size_t size = KMALLOC_MAX_CACHE_SIZE + 10; 102 103 pr_info("kmalloc pagealloc allocation: use-after-free\n"); 104 ptr = kmalloc(size, GFP_KERNEL); 105 if (!ptr) { 106 pr_err("Allocation failed\n"); 107 return; 108 } 109 110 kfree(ptr); 111 ptr[0] = 0; 112} 113 114static noinline void __init kmalloc_pagealloc_invalid_free(void) 115{ 116 char *ptr; 117 size_t size = KMALLOC_MAX_CACHE_SIZE + 10; 118 119 pr_info("kmalloc pagealloc allocation: invalid-free\n"); 120 ptr = kmalloc(size, GFP_KERNEL); 121 if (!ptr) { 122 pr_err("Allocation failed\n"); 123 return; 124 } 125 126 kfree(ptr + 1); 127} 128#endif 129 130static noinline void __init kmalloc_large_oob_right(void) 131{ 132 char *ptr; 133 size_t size = KMALLOC_MAX_CACHE_SIZE - 256; 134 /* Allocate a chunk that is large enough, but still fits into a slab 135 * and does not trigger the page allocator fallback in SLUB. 136 */ 137 pr_info("kmalloc large allocation: out-of-bounds to right\n"); 138 ptr = kmalloc(size, GFP_KERNEL); 139 if (!ptr) { 140 pr_err("Allocation failed\n"); 141 return; 142 } 143 144 ptr[size] = 0; 145 kfree(ptr); 146} 147 148static noinline void __init kmalloc_oob_krealloc_more(void) 149{ 150 char *ptr1, *ptr2; 151 size_t size1 = 17; 152 size_t size2 = 19; 153 154 pr_info("out-of-bounds after krealloc more\n"); 155 ptr1 = kmalloc(size1, GFP_KERNEL); 156 ptr2 = krealloc(ptr1, size2, GFP_KERNEL); 157 if (!ptr1 || !ptr2) { 158 pr_err("Allocation failed\n"); 159 kfree(ptr1); 160 return; 161 } 162 163 ptr2[size2] = 'x'; 164 kfree(ptr2); 165} 166 167static noinline void __init kmalloc_oob_krealloc_less(void) 168{ 169 char *ptr1, *ptr2; 170 size_t size1 = 17; 171 size_t size2 = 15; 172 173 pr_info("out-of-bounds after krealloc less\n"); 174 ptr1 = kmalloc(size1, GFP_KERNEL); 175 ptr2 = krealloc(ptr1, size2, GFP_KERNEL); 176 if (!ptr1 || !ptr2) { 177 pr_err("Allocation failed\n"); 178 kfree(ptr1); 179 return; 180 } 181 ptr2[size2] = 'x'; 182 kfree(ptr2); 183} 184 185static noinline void __init kmalloc_oob_16(void) 186{ 187 struct { 188 u64 words[2]; 189 } *ptr1, *ptr2; 190 191 pr_info("kmalloc out-of-bounds for 16-bytes access\n"); 192 ptr1 = kmalloc(sizeof(*ptr1) - 3, GFP_KERNEL); 193 ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL); 194 if (!ptr1 || !ptr2) { 195 pr_err("Allocation failed\n"); 196 kfree(ptr1); 197 kfree(ptr2); 198 return; 199 } 200 *ptr1 = *ptr2; 201 kfree(ptr1); 202 kfree(ptr2); 203} 204 205static noinline void __init kmalloc_oob_memset_2(void) 206{ 207 char *ptr; 208 size_t size = 8; 209 210 pr_info("out-of-bounds in memset2\n"); 211 ptr = kmalloc(size, GFP_KERNEL); 212 if (!ptr) { 213 pr_err("Allocation failed\n"); 214 return; 215 } 216 217 memset(ptr+7, 0, 2); 218 kfree(ptr); 219} 220 221static noinline void __init kmalloc_oob_memset_4(void) 222{ 223 char *ptr; 224 size_t size = 8; 225 226 pr_info("out-of-bounds in memset4\n"); 227 ptr = kmalloc(size, GFP_KERNEL); 228 if (!ptr) { 229 pr_err("Allocation failed\n"); 230 return; 231 } 232 233 memset(ptr+5, 0, 4); 234 kfree(ptr); 235} 236 237 238static noinline void __init kmalloc_oob_memset_8(void) 239{ 240 char *ptr; 241 size_t size = 8; 242 243 pr_info("out-of-bounds in memset8\n"); 244 ptr = kmalloc(size, GFP_KERNEL); 245 if (!ptr) { 246 pr_err("Allocation failed\n"); 247 return; 248 } 249 250 memset(ptr+1, 0, 8); 251 kfree(ptr); 252} 253 254static noinline void __init kmalloc_oob_memset_16(void) 255{ 256 char *ptr; 257 size_t size = 16; 258 259 pr_info("out-of-bounds in memset16\n"); 260 ptr = kmalloc(size, GFP_KERNEL); 261 if (!ptr) { 262 pr_err("Allocation failed\n"); 263 return; 264 } 265 266 memset(ptr+1, 0, 16); 267 kfree(ptr); 268} 269 270static noinline void __init kmalloc_oob_in_memset(void) 271{ 272 char *ptr; 273 size_t size = 666; 274 275 pr_info("out-of-bounds in memset\n"); 276 ptr = kmalloc(size, GFP_KERNEL); 277 if (!ptr) { 278 pr_err("Allocation failed\n"); 279 return; 280 } 281 282 memset(ptr, 0, size+5); 283 kfree(ptr); 284} 285 286static noinline void __init kmalloc_uaf(void) 287{ 288 char *ptr; 289 size_t size = 10; 290 291 pr_info("use-after-free\n"); 292 ptr = kmalloc(size, GFP_KERNEL); 293 if (!ptr) { 294 pr_err("Allocation failed\n"); 295 return; 296 } 297 298 kfree(ptr); 299 *(ptr + 8) = 'x'; 300} 301 302static noinline void __init kmalloc_uaf_memset(void) 303{ 304 char *ptr; 305 size_t size = 33; 306 307 pr_info("use-after-free in memset\n"); 308 ptr = kmalloc(size, GFP_KERNEL); 309 if (!ptr) { 310 pr_err("Allocation failed\n"); 311 return; 312 } 313 314 kfree(ptr); 315 memset(ptr, 0, size); 316} 317 318static noinline void __init kmalloc_uaf2(void) 319{ 320 char *ptr1, *ptr2; 321 size_t size = 43; 322 323 pr_info("use-after-free after another kmalloc\n"); 324 ptr1 = kmalloc(size, GFP_KERNEL); 325 if (!ptr1) { 326 pr_err("Allocation failed\n"); 327 return; 328 } 329 330 kfree(ptr1); 331 ptr2 = kmalloc(size, GFP_KERNEL); 332 if (!ptr2) { 333 pr_err("Allocation failed\n"); 334 return; 335 } 336 337 ptr1[40] = 'x'; 338 if (ptr1 == ptr2) 339 pr_err("Could not detect use-after-free: ptr1 == ptr2\n"); 340 kfree(ptr2); 341} 342 343static noinline void __init kmem_cache_oob(void) 344{ 345 char *p; 346 size_t size = 200; 347 struct kmem_cache *cache = kmem_cache_create("test_cache", 348 size, 0, 349 0, NULL); 350 if (!cache) { 351 pr_err("Cache allocation failed\n"); 352 return; 353 } 354 pr_info("out-of-bounds in kmem_cache_alloc\n"); 355 p = kmem_cache_alloc(cache, GFP_KERNEL); 356 if (!p) { 357 pr_err("Allocation failed\n"); 358 kmem_cache_destroy(cache); 359 return; 360 } 361 362 *p = p[size]; 363 kmem_cache_free(cache, p); 364 kmem_cache_destroy(cache); 365} 366 367static noinline void __init memcg_accounted_kmem_cache(void) 368{ 369 int i; 370 char *p; 371 size_t size = 200; 372 struct kmem_cache *cache; 373 374 cache = kmem_cache_create("test_cache", size, 0, SLAB_ACCOUNT, NULL); 375 if (!cache) { 376 pr_err("Cache allocation failed\n"); 377 return; 378 } 379 380 pr_info("allocate memcg accounted object\n"); 381 /* 382 * Several allocations with a delay to allow for lazy per memcg kmem 383 * cache creation. 384 */ 385 for (i = 0; i < 5; i++) { 386 p = kmem_cache_alloc(cache, GFP_KERNEL); 387 if (!p) 388 goto free_cache; 389 390 kmem_cache_free(cache, p); 391 msleep(100); 392 } 393 394free_cache: 395 kmem_cache_destroy(cache); 396} 397 398static char global_array[10]; 399 400static noinline void __init kasan_global_oob(void) 401{ 402 volatile int i = 3; 403 char *p = &global_array[ARRAY_SIZE(global_array) + i]; 404 405 pr_info("out-of-bounds global variable\n"); 406 *(volatile char *)p; 407} 408 409static noinline void __init kasan_stack_oob(void) 410{ 411 char stack_array[10]; 412 volatile int i = 0; 413 char *p = &stack_array[ARRAY_SIZE(stack_array) + i]; 414 415 pr_info("out-of-bounds on stack\n"); 416 *(volatile char *)p; 417} 418 419static noinline void __init ksize_unpoisons_memory(void) 420{ 421 char *ptr; 422 size_t size = 123, real_size; 423 424 pr_info("ksize() unpoisons the whole allocated chunk\n"); 425 ptr = kmalloc(size, GFP_KERNEL); 426 if (!ptr) { 427 pr_err("Allocation failed\n"); 428 return; 429 } 430 real_size = ksize(ptr); 431 /* This access doesn't trigger an error. */ 432 ptr[size] = 'x'; 433 /* This one does. */ 434 ptr[real_size] = 'y'; 435 kfree(ptr); 436} 437 438static noinline void __init copy_user_test(void) 439{ 440 char *kmem; 441 char __user *usermem; 442 size_t size = 10; 443 int unused; 444 445 kmem = kmalloc(size, GFP_KERNEL); 446 if (!kmem) 447 return; 448 449 usermem = (char __user *)vm_mmap(NULL, 0, PAGE_SIZE, 450 PROT_READ | PROT_WRITE | PROT_EXEC, 451 MAP_ANONYMOUS | MAP_PRIVATE, 0); 452 if (IS_ERR(usermem)) { 453 pr_err("Failed to allocate user memory\n"); 454 kfree(kmem); 455 return; 456 } 457 458 pr_info("out-of-bounds in copy_from_user()\n"); 459 unused = copy_from_user(kmem, usermem, size + 1); 460 461 pr_info("out-of-bounds in copy_to_user()\n"); 462 unused = copy_to_user(usermem, kmem, size + 1); 463 464 pr_info("out-of-bounds in __copy_from_user()\n"); 465 unused = __copy_from_user(kmem, usermem, size + 1); 466 467 pr_info("out-of-bounds in __copy_to_user()\n"); 468 unused = __copy_to_user(usermem, kmem, size + 1); 469 470 pr_info("out-of-bounds in __copy_from_user_inatomic()\n"); 471 unused = __copy_from_user_inatomic(kmem, usermem, size + 1); 472 473 pr_info("out-of-bounds in __copy_to_user_inatomic()\n"); 474 unused = __copy_to_user_inatomic(usermem, kmem, size + 1); 475 476 pr_info("out-of-bounds in strncpy_from_user()\n"); 477 unused = strncpy_from_user(kmem, usermem, size + 1); 478 479 vm_munmap((unsigned long)usermem, PAGE_SIZE); 480 kfree(kmem); 481} 482 483static noinline void __init kasan_alloca_oob_left(void) 484{ 485 volatile int i = 10; 486 char alloca_array[i]; 487 char *p = alloca_array - 1; 488 489 pr_info("out-of-bounds to left on alloca\n"); 490 *(volatile char *)p; 491} 492 493static noinline void __init kasan_alloca_oob_right(void) 494{ 495 volatile int i = 10; 496 char alloca_array[i]; 497 char *p = alloca_array + i; 498 499 pr_info("out-of-bounds to right on alloca\n"); 500 *(volatile char *)p; 501} 502 503static noinline void __init kmem_cache_double_free(void) 504{ 505 char *p; 506 size_t size = 200; 507 struct kmem_cache *cache; 508 509 cache = kmem_cache_create("test_cache", size, 0, 0, NULL); 510 if (!cache) { 511 pr_err("Cache allocation failed\n"); 512 return; 513 } 514 pr_info("double-free on heap object\n"); 515 p = kmem_cache_alloc(cache, GFP_KERNEL); 516 if (!p) { 517 pr_err("Allocation failed\n"); 518 kmem_cache_destroy(cache); 519 return; 520 } 521 522 kmem_cache_free(cache, p); 523 kmem_cache_free(cache, p); 524 kmem_cache_destroy(cache); 525} 526 527static noinline void __init kmem_cache_invalid_free(void) 528{ 529 char *p; 530 size_t size = 200; 531 struct kmem_cache *cache; 532 533 cache = kmem_cache_create("test_cache", size, 0, SLAB_TYPESAFE_BY_RCU, 534 NULL); 535 if (!cache) { 536 pr_err("Cache allocation failed\n"); 537 return; 538 } 539 pr_info("invalid-free of heap object\n"); 540 p = kmem_cache_alloc(cache, GFP_KERNEL); 541 if (!p) { 542 pr_err("Allocation failed\n"); 543 kmem_cache_destroy(cache); 544 return; 545 } 546 547 /* Trigger invalid free, the object doesn't get freed */ 548 kmem_cache_free(cache, p + 1); 549 550 /* 551 * Properly free the object to prevent the "Objects remaining in 552 * test_cache on __kmem_cache_shutdown" BUG failure. 553 */ 554 kmem_cache_free(cache, p); 555 556 kmem_cache_destroy(cache); 557} 558 559static noinline void __init kasan_memchr(void) 560{ 561 char *ptr; 562 size_t size = 24; 563 564 pr_info("out-of-bounds in memchr\n"); 565 ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO); 566 if (!ptr) 567 return; 568 569 memchr(ptr, '1', size + 1); 570 kfree(ptr); 571} 572 573static noinline void __init kasan_memcmp(void) 574{ 575 char *ptr; 576 size_t size = 24; 577 int arr[9]; 578 579 pr_info("out-of-bounds in memcmp\n"); 580 ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO); 581 if (!ptr) 582 return; 583 584 memset(arr, 0, sizeof(arr)); 585 memcmp(ptr, arr, size+1); 586 kfree(ptr); 587} 588 589static noinline void __init kasan_strings(void) 590{ 591 char *ptr; 592 size_t size = 24; 593 594 pr_info("use-after-free in strchr\n"); 595 ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO); 596 if (!ptr) 597 return; 598 599 kfree(ptr); 600 601 /* 602 * Try to cause only 1 invalid access (less spam in dmesg). 603 * For that we need ptr to point to zeroed byte. 604 * Skip metadata that could be stored in freed object so ptr 605 * will likely point to zeroed byte. 606 */ 607 ptr += 16; 608 strchr(ptr, '1'); 609 610 pr_info("use-after-free in strrchr\n"); 611 strrchr(ptr, '1'); 612 613 pr_info("use-after-free in strcmp\n"); 614 strcmp(ptr, "2"); 615 616 pr_info("use-after-free in strncmp\n"); 617 strncmp(ptr, "2", 1); 618 619 pr_info("use-after-free in strlen\n"); 620 strlen(ptr); 621 622 pr_info("use-after-free in strnlen\n"); 623 strnlen(ptr, 1); 624} 625 626static int __init kmalloc_tests_init(void) 627{ 628 /* 629 * Temporarily enable multi-shot mode. Otherwise, we'd only get a 630 * report for the first case. 631 */ 632 bool multishot = kasan_save_enable_multi_shot(); 633 634 kmalloc_oob_right(); 635 kmalloc_oob_left(); 636 kmalloc_node_oob_right(); 637#ifdef CONFIG_SLUB 638 kmalloc_pagealloc_oob_right(); 639 kmalloc_pagealloc_uaf(); 640 kmalloc_pagealloc_invalid_free(); 641#endif 642 kmalloc_large_oob_right(); 643 kmalloc_oob_krealloc_more(); 644 kmalloc_oob_krealloc_less(); 645 kmalloc_oob_16(); 646 kmalloc_oob_in_memset(); 647 kmalloc_oob_memset_2(); 648 kmalloc_oob_memset_4(); 649 kmalloc_oob_memset_8(); 650 kmalloc_oob_memset_16(); 651 kmalloc_uaf(); 652 kmalloc_uaf_memset(); 653 kmalloc_uaf2(); 654 kmem_cache_oob(); 655 memcg_accounted_kmem_cache(); 656 kasan_stack_oob(); 657 kasan_global_oob(); 658 kasan_alloca_oob_left(); 659 kasan_alloca_oob_right(); 660 ksize_unpoisons_memory(); 661 copy_user_test(); 662 kmem_cache_double_free(); 663 kmem_cache_invalid_free(); 664 kasan_memchr(); 665 kasan_memcmp(); 666 kasan_strings(); 667 668 kasan_restore_multi_shot(multishot); 669 670 return -EAGAIN; 671} 672 673module_init(kmalloc_tests_init); 674MODULE_LICENSE("GPL");