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.

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