at v4.20 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 use_after_scope_test(void) 484{ 485 volatile char *volatile p; 486 487 pr_info("use-after-scope on int\n"); 488 { 489 int local = 0; 490 491 p = (char *)&local; 492 } 493 p[0] = 1; 494 p[3] = 1; 495 496 pr_info("use-after-scope on array\n"); 497 { 498 char local[1024] = {0}; 499 500 p = local; 501 } 502 p[0] = 1; 503 p[1023] = 1; 504} 505 506static noinline void __init kasan_alloca_oob_left(void) 507{ 508 volatile int i = 10; 509 char alloca_array[i]; 510 char *p = alloca_array - 1; 511 512 pr_info("out-of-bounds to left on alloca\n"); 513 *(volatile char *)p; 514} 515 516static noinline void __init kasan_alloca_oob_right(void) 517{ 518 volatile int i = 10; 519 char alloca_array[i]; 520 char *p = alloca_array + i; 521 522 pr_info("out-of-bounds to right on alloca\n"); 523 *(volatile char *)p; 524} 525 526static noinline void __init kmem_cache_double_free(void) 527{ 528 char *p; 529 size_t size = 200; 530 struct kmem_cache *cache; 531 532 cache = kmem_cache_create("test_cache", size, 0, 0, NULL); 533 if (!cache) { 534 pr_err("Cache allocation failed\n"); 535 return; 536 } 537 pr_info("double-free on heap object\n"); 538 p = kmem_cache_alloc(cache, GFP_KERNEL); 539 if (!p) { 540 pr_err("Allocation failed\n"); 541 kmem_cache_destroy(cache); 542 return; 543 } 544 545 kmem_cache_free(cache, p); 546 kmem_cache_free(cache, p); 547 kmem_cache_destroy(cache); 548} 549 550static noinline void __init kmem_cache_invalid_free(void) 551{ 552 char *p; 553 size_t size = 200; 554 struct kmem_cache *cache; 555 556 cache = kmem_cache_create("test_cache", size, 0, SLAB_TYPESAFE_BY_RCU, 557 NULL); 558 if (!cache) { 559 pr_err("Cache allocation failed\n"); 560 return; 561 } 562 pr_info("invalid-free of heap object\n"); 563 p = kmem_cache_alloc(cache, GFP_KERNEL); 564 if (!p) { 565 pr_err("Allocation failed\n"); 566 kmem_cache_destroy(cache); 567 return; 568 } 569 570 /* Trigger invalid free, the object doesn't get freed */ 571 kmem_cache_free(cache, p + 1); 572 573 /* 574 * Properly free the object to prevent the "Objects remaining in 575 * test_cache on __kmem_cache_shutdown" BUG failure. 576 */ 577 kmem_cache_free(cache, p); 578 579 kmem_cache_destroy(cache); 580} 581 582static noinline void __init kasan_memchr(void) 583{ 584 char *ptr; 585 size_t size = 24; 586 587 pr_info("out-of-bounds in memchr\n"); 588 ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO); 589 if (!ptr) 590 return; 591 592 memchr(ptr, '1', size + 1); 593 kfree(ptr); 594} 595 596static noinline void __init kasan_memcmp(void) 597{ 598 char *ptr; 599 size_t size = 24; 600 int arr[9]; 601 602 pr_info("out-of-bounds in memcmp\n"); 603 ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO); 604 if (!ptr) 605 return; 606 607 memset(arr, 0, sizeof(arr)); 608 memcmp(ptr, arr, size+1); 609 kfree(ptr); 610} 611 612static noinline void __init kasan_strings(void) 613{ 614 char *ptr; 615 size_t size = 24; 616 617 pr_info("use-after-free in strchr\n"); 618 ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO); 619 if (!ptr) 620 return; 621 622 kfree(ptr); 623 624 /* 625 * Try to cause only 1 invalid access (less spam in dmesg). 626 * For that we need ptr to point to zeroed byte. 627 * Skip metadata that could be stored in freed object so ptr 628 * will likely point to zeroed byte. 629 */ 630 ptr += 16; 631 strchr(ptr, '1'); 632 633 pr_info("use-after-free in strrchr\n"); 634 strrchr(ptr, '1'); 635 636 pr_info("use-after-free in strcmp\n"); 637 strcmp(ptr, "2"); 638 639 pr_info("use-after-free in strncmp\n"); 640 strncmp(ptr, "2", 1); 641 642 pr_info("use-after-free in strlen\n"); 643 strlen(ptr); 644 645 pr_info("use-after-free in strnlen\n"); 646 strnlen(ptr, 1); 647} 648 649static int __init kmalloc_tests_init(void) 650{ 651 /* 652 * Temporarily enable multi-shot mode. Otherwise, we'd only get a 653 * report for the first case. 654 */ 655 bool multishot = kasan_save_enable_multi_shot(); 656 657 kmalloc_oob_right(); 658 kmalloc_oob_left(); 659 kmalloc_node_oob_right(); 660#ifdef CONFIG_SLUB 661 kmalloc_pagealloc_oob_right(); 662 kmalloc_pagealloc_uaf(); 663 kmalloc_pagealloc_invalid_free(); 664#endif 665 kmalloc_large_oob_right(); 666 kmalloc_oob_krealloc_more(); 667 kmalloc_oob_krealloc_less(); 668 kmalloc_oob_16(); 669 kmalloc_oob_in_memset(); 670 kmalloc_oob_memset_2(); 671 kmalloc_oob_memset_4(); 672 kmalloc_oob_memset_8(); 673 kmalloc_oob_memset_16(); 674 kmalloc_uaf(); 675 kmalloc_uaf_memset(); 676 kmalloc_uaf2(); 677 kmem_cache_oob(); 678 memcg_accounted_kmem_cache(); 679 kasan_stack_oob(); 680 kasan_global_oob(); 681 kasan_alloca_oob_left(); 682 kasan_alloca_oob_right(); 683 ksize_unpoisons_memory(); 684 copy_user_test(); 685 use_after_scope_test(); 686 kmem_cache_double_free(); 687 kmem_cache_invalid_free(); 688 kasan_memchr(); 689 kasan_memcmp(); 690 kasan_strings(); 691 692 kasan_restore_multi_shot(multishot); 693 694 return -EAGAIN; 695} 696 697module_init(kmalloc_tests_init); 698MODULE_LICENSE("GPL");