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