linux/lib/test_kasan.c
<<
>>
Prefs
   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");
 699