diff options
| -rw-r--r-- | drivers/block/zram/zram_drv.c | 3 | ||||
| -rw-r--r-- | include/linux/compiler-gcc.h | 4 | ||||
| -rw-r--r-- | include/linux/pagemap.h | 21 | ||||
| -rw-r--r-- | lib/debugobjects.c | 8 | ||||
| -rw-r--r-- | lib/test_kasan.c | 29 | ||||
| -rw-r--r-- | mm/kasan/kasan.c | 19 | ||||
| -rw-r--r-- | mm/kasan/kasan.h | 4 | ||||
| -rw-r--r-- | mm/kasan/report.c | 3 | ||||
| -rw-r--r-- | mm/khugepaged.c | 2 | ||||
| -rw-r--r-- | mm/mlock.c | 7 | ||||
| -rw-r--r-- | mm/truncate.c | 8 |
11 files changed, 94 insertions, 14 deletions
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 04365b17ee67..5163c8f918cb 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c | |||
| @@ -1403,7 +1403,8 @@ static ssize_t hot_remove_store(struct class *class, | |||
| 1403 | zram = idr_find(&zram_index_idr, dev_id); | 1403 | zram = idr_find(&zram_index_idr, dev_id); |
| 1404 | if (zram) { | 1404 | if (zram) { |
| 1405 | ret = zram_remove(zram); | 1405 | ret = zram_remove(zram); |
| 1406 | idr_remove(&zram_index_idr, dev_id); | 1406 | if (!ret) |
| 1407 | idr_remove(&zram_index_idr, dev_id); | ||
| 1407 | } else { | 1408 | } else { |
| 1408 | ret = -ENODEV; | 1409 | ret = -ENODEV; |
| 1409 | } | 1410 | } |
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 432f5c97e18f..928e5ca0caee 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h | |||
| @@ -263,7 +263,9 @@ | |||
| 263 | #endif | 263 | #endif |
| 264 | #endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP && !__CHECKER__ */ | 264 | #endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP && !__CHECKER__ */ |
| 265 | 265 | ||
| 266 | #if GCC_VERSION >= 50000 | 266 | #if GCC_VERSION >= 70000 |
| 267 | #define KASAN_ABI_VERSION 5 | ||
| 268 | #elif GCC_VERSION >= 50000 | ||
| 267 | #define KASAN_ABI_VERSION 4 | 269 | #define KASAN_ABI_VERSION 4 |
| 268 | #elif GCC_VERSION >= 40902 | 270 | #elif GCC_VERSION >= 40902 |
| 269 | #define KASAN_ABI_VERSION 3 | 271 | #define KASAN_ABI_VERSION 3 |
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index dd15d39e1985..7dbe9148b2f8 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h | |||
| @@ -374,16 +374,13 @@ static inline struct page *read_mapping_page(struct address_space *mapping, | |||
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | /* | 376 | /* |
| 377 | * Get the offset in PAGE_SIZE. | 377 | * Get index of the page with in radix-tree |
| 378 | * (TODO: hugepage should have ->index in PAGE_SIZE) | 378 | * (TODO: remove once hugetlb pages will have ->index in PAGE_SIZE) |
| 379 | */ | 379 | */ |
| 380 | static inline pgoff_t page_to_pgoff(struct page *page) | 380 | static inline pgoff_t page_to_index(struct page *page) |
| 381 | { | 381 | { |
| 382 | pgoff_t pgoff; | 382 | pgoff_t pgoff; |
| 383 | 383 | ||
| 384 | if (unlikely(PageHeadHuge(page))) | ||
| 385 | return page->index << compound_order(page); | ||
| 386 | |||
| 387 | if (likely(!PageTransTail(page))) | 384 | if (likely(!PageTransTail(page))) |
| 388 | return page->index; | 385 | return page->index; |
| 389 | 386 | ||
| @@ -397,6 +394,18 @@ static inline pgoff_t page_to_pgoff(struct page *page) | |||
| 397 | } | 394 | } |
| 398 | 395 | ||
| 399 | /* | 396 | /* |
| 397 | * Get the offset in PAGE_SIZE. | ||
| 398 | * (TODO: hugepage should have ->index in PAGE_SIZE) | ||
| 399 | */ | ||
| 400 | static inline pgoff_t page_to_pgoff(struct page *page) | ||
| 401 | { | ||
| 402 | if (unlikely(PageHeadHuge(page))) | ||
| 403 | return page->index << compound_order(page); | ||
| 404 | |||
| 405 | return page_to_index(page); | ||
| 406 | } | ||
| 407 | |||
| 408 | /* | ||
| 400 | * Return byte-offset into filesystem object for page. | 409 | * Return byte-offset into filesystem object for page. |
| 401 | */ | 410 | */ |
| 402 | static inline loff_t page_offset(struct page *page) | 411 | static inline loff_t page_offset(struct page *page) |
diff --git a/lib/debugobjects.c b/lib/debugobjects.c index a8e12601eb37..056052dc8e91 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c | |||
| @@ -362,6 +362,7 @@ void debug_object_init(void *addr, struct debug_obj_descr *descr) | |||
| 362 | 362 | ||
| 363 | __debug_object_init(addr, descr, 0); | 363 | __debug_object_init(addr, descr, 0); |
| 364 | } | 364 | } |
| 365 | EXPORT_SYMBOL_GPL(debug_object_init); | ||
| 365 | 366 | ||
| 366 | /** | 367 | /** |
| 367 | * debug_object_init_on_stack - debug checks when an object on stack is | 368 | * debug_object_init_on_stack - debug checks when an object on stack is |
| @@ -376,6 +377,7 @@ void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr) | |||
| 376 | 377 | ||
| 377 | __debug_object_init(addr, descr, 1); | 378 | __debug_object_init(addr, descr, 1); |
| 378 | } | 379 | } |
| 380 | EXPORT_SYMBOL_GPL(debug_object_init_on_stack); | ||
| 379 | 381 | ||
| 380 | /** | 382 | /** |
| 381 | * debug_object_activate - debug checks when an object is activated | 383 | * debug_object_activate - debug checks when an object is activated |
| @@ -449,6 +451,7 @@ int debug_object_activate(void *addr, struct debug_obj_descr *descr) | |||
| 449 | } | 451 | } |
| 450 | return 0; | 452 | return 0; |
| 451 | } | 453 | } |
| 454 | EXPORT_SYMBOL_GPL(debug_object_activate); | ||
| 452 | 455 | ||
| 453 | /** | 456 | /** |
| 454 | * debug_object_deactivate - debug checks when an object is deactivated | 457 | * debug_object_deactivate - debug checks when an object is deactivated |
| @@ -496,6 +499,7 @@ void debug_object_deactivate(void *addr, struct debug_obj_descr *descr) | |||
| 496 | 499 | ||
| 497 | raw_spin_unlock_irqrestore(&db->lock, flags); | 500 | raw_spin_unlock_irqrestore(&db->lock, flags); |
| 498 | } | 501 | } |
| 502 | EXPORT_SYMBOL_GPL(debug_object_deactivate); | ||
| 499 | 503 | ||
| 500 | /** | 504 | /** |
| 501 | * debug_object_destroy - debug checks when an object is destroyed | 505 | * debug_object_destroy - debug checks when an object is destroyed |
| @@ -542,6 +546,7 @@ void debug_object_destroy(void *addr, struct debug_obj_descr *descr) | |||
| 542 | out_unlock: | 546 | out_unlock: |
| 543 | raw_spin_unlock_irqrestore(&db->lock, flags); | 547 | raw_spin_unlock_irqrestore(&db->lock, flags); |
| 544 | } | 548 | } |
| 549 | EXPORT_SYMBOL_GPL(debug_object_destroy); | ||
| 545 | 550 | ||
| 546 | /** | 551 | /** |
| 547 | * debug_object_free - debug checks when an object is freed | 552 | * debug_object_free - debug checks when an object is freed |
| @@ -582,6 +587,7 @@ void debug_object_free(void *addr, struct debug_obj_descr *descr) | |||
| 582 | out_unlock: | 587 | out_unlock: |
| 583 | raw_spin_unlock_irqrestore(&db->lock, flags); | 588 | raw_spin_unlock_irqrestore(&db->lock, flags); |
| 584 | } | 589 | } |
| 590 | EXPORT_SYMBOL_GPL(debug_object_free); | ||
| 585 | 591 | ||
| 586 | /** | 592 | /** |
| 587 | * debug_object_assert_init - debug checks when object should be init-ed | 593 | * debug_object_assert_init - debug checks when object should be init-ed |
| @@ -626,6 +632,7 @@ void debug_object_assert_init(void *addr, struct debug_obj_descr *descr) | |||
| 626 | 632 | ||
| 627 | raw_spin_unlock_irqrestore(&db->lock, flags); | 633 | raw_spin_unlock_irqrestore(&db->lock, flags); |
| 628 | } | 634 | } |
| 635 | EXPORT_SYMBOL_GPL(debug_object_assert_init); | ||
| 629 | 636 | ||
| 630 | /** | 637 | /** |
| 631 | * debug_object_active_state - debug checks object usage state machine | 638 | * debug_object_active_state - debug checks object usage state machine |
| @@ -673,6 +680,7 @@ debug_object_active_state(void *addr, struct debug_obj_descr *descr, | |||
| 673 | 680 | ||
| 674 | raw_spin_unlock_irqrestore(&db->lock, flags); | 681 | raw_spin_unlock_irqrestore(&db->lock, flags); |
| 675 | } | 682 | } |
| 683 | EXPORT_SYMBOL_GPL(debug_object_active_state); | ||
| 676 | 684 | ||
| 677 | #ifdef CONFIG_DEBUG_OBJECTS_FREE | 685 | #ifdef CONFIG_DEBUG_OBJECTS_FREE |
| 678 | static void __debug_check_no_obj_freed(const void *address, unsigned long size) | 686 | static void __debug_check_no_obj_freed(const void *address, unsigned long size) |
diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 5e51872b3fc1..fbdf87920093 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c | |||
| @@ -20,6 +20,11 @@ | |||
| 20 | #include <linux/uaccess.h> | 20 | #include <linux/uaccess.h> |
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | 22 | ||
| 23 | /* | ||
| 24 | * Note: test functions are marked noinline so that their names appear in | ||
| 25 | * reports. | ||
| 26 | */ | ||
| 27 | |||
| 23 | static noinline void __init kmalloc_oob_right(void) | 28 | static noinline void __init kmalloc_oob_right(void) |
| 24 | { | 29 | { |
| 25 | char *ptr; | 30 | char *ptr; |
| @@ -411,6 +416,29 @@ static noinline void __init copy_user_test(void) | |||
| 411 | kfree(kmem); | 416 | kfree(kmem); |
| 412 | } | 417 | } |
| 413 | 418 | ||
| 419 | static noinline void __init use_after_scope_test(void) | ||
| 420 | { | ||
| 421 | volatile char *volatile p; | ||
| 422 | |||
| 423 | pr_info("use-after-scope on int\n"); | ||
| 424 | { | ||
| 425 | int local = 0; | ||
| 426 | |||
| 427 | p = (char *)&local; | ||
| 428 | } | ||
| 429 | p[0] = 1; | ||
| 430 | p[3] = 1; | ||
| 431 | |||
| 432 | pr_info("use-after-scope on array\n"); | ||
| 433 | { | ||
| 434 | char local[1024] = {0}; | ||
| 435 | |||
| 436 | p = local; | ||
| 437 | } | ||
| 438 | p[0] = 1; | ||
| 439 | p[1023] = 1; | ||
| 440 | } | ||
| 441 | |||
| 414 | static int __init kmalloc_tests_init(void) | 442 | static int __init kmalloc_tests_init(void) |
| 415 | { | 443 | { |
| 416 | kmalloc_oob_right(); | 444 | kmalloc_oob_right(); |
| @@ -436,6 +464,7 @@ static int __init kmalloc_tests_init(void) | |||
| 436 | kasan_global_oob(); | 464 | kasan_global_oob(); |
| 437 | ksize_unpoisons_memory(); | 465 | ksize_unpoisons_memory(); |
| 438 | copy_user_test(); | 466 | copy_user_test(); |
| 467 | use_after_scope_test(); | ||
| 439 | return -EAGAIN; | 468 | return -EAGAIN; |
| 440 | } | 469 | } |
| 441 | 470 | ||
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c index 70c009741aab..0e9505f66ec1 100644 --- a/mm/kasan/kasan.c +++ b/mm/kasan/kasan.c | |||
| @@ -764,6 +764,25 @@ EXPORT_SYMBOL(__asan_storeN_noabort); | |||
| 764 | void __asan_handle_no_return(void) {} | 764 | void __asan_handle_no_return(void) {} |
| 765 | EXPORT_SYMBOL(__asan_handle_no_return); | 765 | EXPORT_SYMBOL(__asan_handle_no_return); |
| 766 | 766 | ||
| 767 | /* Emitted by compiler to poison large objects when they go out of scope. */ | ||
| 768 | void __asan_poison_stack_memory(const void *addr, size_t size) | ||
| 769 | { | ||
| 770 | /* | ||
| 771 | * Addr is KASAN_SHADOW_SCALE_SIZE-aligned and the object is surrounded | ||
| 772 | * by redzones, so we simply round up size to simplify logic. | ||
| 773 | */ | ||
| 774 | kasan_poison_shadow(addr, round_up(size, KASAN_SHADOW_SCALE_SIZE), | ||
| 775 | KASAN_USE_AFTER_SCOPE); | ||
| 776 | } | ||
| 777 | EXPORT_SYMBOL(__asan_poison_stack_memory); | ||
| 778 | |||
| 779 | /* Emitted by compiler to unpoison large objects when they go into scope. */ | ||
| 780 | void __asan_unpoison_stack_memory(const void *addr, size_t size) | ||
| 781 | { | ||
| 782 | kasan_unpoison_shadow(addr, size); | ||
| 783 | } | ||
| 784 | EXPORT_SYMBOL(__asan_unpoison_stack_memory); | ||
| 785 | |||
| 767 | #ifdef CONFIG_MEMORY_HOTPLUG | 786 | #ifdef CONFIG_MEMORY_HOTPLUG |
| 768 | static int kasan_mem_notifier(struct notifier_block *nb, | 787 | static int kasan_mem_notifier(struct notifier_block *nb, |
| 769 | unsigned long action, void *data) | 788 | unsigned long action, void *data) |
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index e5c2181fee6f..1c260e6b3b3c 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #define KASAN_STACK_MID 0xF2 | 21 | #define KASAN_STACK_MID 0xF2 |
| 22 | #define KASAN_STACK_RIGHT 0xF3 | 22 | #define KASAN_STACK_RIGHT 0xF3 |
| 23 | #define KASAN_STACK_PARTIAL 0xF4 | 23 | #define KASAN_STACK_PARTIAL 0xF4 |
| 24 | #define KASAN_USE_AFTER_SCOPE 0xF8 | ||
| 24 | 25 | ||
| 25 | /* Don't break randconfig/all*config builds */ | 26 | /* Don't break randconfig/all*config builds */ |
| 26 | #ifndef KASAN_ABI_VERSION | 27 | #ifndef KASAN_ABI_VERSION |
| @@ -53,6 +54,9 @@ struct kasan_global { | |||
| 53 | #if KASAN_ABI_VERSION >= 4 | 54 | #if KASAN_ABI_VERSION >= 4 |
| 54 | struct kasan_source_location *location; | 55 | struct kasan_source_location *location; |
| 55 | #endif | 56 | #endif |
| 57 | #if KASAN_ABI_VERSION >= 5 | ||
| 58 | char *odr_indicator; | ||
| 59 | #endif | ||
| 56 | }; | 60 | }; |
| 57 | 61 | ||
| 58 | /** | 62 | /** |
diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 24c1211fe9d5..073325aedc68 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c | |||
| @@ -90,6 +90,9 @@ static void print_error_description(struct kasan_access_info *info) | |||
| 90 | case KASAN_KMALLOC_FREE: | 90 | case KASAN_KMALLOC_FREE: |
| 91 | bug_type = "use-after-free"; | 91 | bug_type = "use-after-free"; |
| 92 | break; | 92 | break; |
| 93 | case KASAN_USE_AFTER_SCOPE: | ||
| 94 | bug_type = "use-after-scope"; | ||
| 95 | break; | ||
| 93 | } | 96 | } |
| 94 | 97 | ||
| 95 | pr_err("BUG: KASAN: %s in %pS at addr %p\n", | 98 | pr_err("BUG: KASAN: %s in %pS at addr %p\n", |
diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 728d7790dc2d..87e1a7ca3846 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c | |||
| @@ -103,6 +103,7 @@ static struct khugepaged_scan khugepaged_scan = { | |||
| 103 | .mm_head = LIST_HEAD_INIT(khugepaged_scan.mm_head), | 103 | .mm_head = LIST_HEAD_INIT(khugepaged_scan.mm_head), |
| 104 | }; | 104 | }; |
| 105 | 105 | ||
| 106 | #ifdef CONFIG_SYSFS | ||
| 106 | static ssize_t scan_sleep_millisecs_show(struct kobject *kobj, | 107 | static ssize_t scan_sleep_millisecs_show(struct kobject *kobj, |
| 107 | struct kobj_attribute *attr, | 108 | struct kobj_attribute *attr, |
| 108 | char *buf) | 109 | char *buf) |
| @@ -295,6 +296,7 @@ struct attribute_group khugepaged_attr_group = { | |||
| 295 | .attrs = khugepaged_attr, | 296 | .attrs = khugepaged_attr, |
| 296 | .name = "khugepaged", | 297 | .name = "khugepaged", |
| 297 | }; | 298 | }; |
| 299 | #endif /* CONFIG_SYSFS */ | ||
| 298 | 300 | ||
| 299 | #define VM_NO_KHUGEPAGED (VM_SPECIAL | VM_HUGETLB) | 301 | #define VM_NO_KHUGEPAGED (VM_SPECIAL | VM_HUGETLB) |
| 300 | 302 | ||
diff --git a/mm/mlock.c b/mm/mlock.c index 145a4258ddbc..cdbed8aaa426 100644 --- a/mm/mlock.c +++ b/mm/mlock.c | |||
| @@ -190,10 +190,13 @@ unsigned int munlock_vma_page(struct page *page) | |||
| 190 | */ | 190 | */ |
| 191 | spin_lock_irq(zone_lru_lock(zone)); | 191 | spin_lock_irq(zone_lru_lock(zone)); |
| 192 | 192 | ||
| 193 | nr_pages = hpage_nr_pages(page); | 193 | if (!TestClearPageMlocked(page)) { |
| 194 | if (!TestClearPageMlocked(page)) | 194 | /* Potentially, PTE-mapped THP: do not skip the rest PTEs */ |
| 195 | nr_pages = 1; | ||
| 195 | goto unlock_out; | 196 | goto unlock_out; |
| 197 | } | ||
| 196 | 198 | ||
| 199 | nr_pages = hpage_nr_pages(page); | ||
| 197 | __mod_zone_page_state(zone, NR_MLOCK, -nr_pages); | 200 | __mod_zone_page_state(zone, NR_MLOCK, -nr_pages); |
| 198 | 201 | ||
| 199 | if (__munlock_isolate_lru_page(page, true)) { | 202 | if (__munlock_isolate_lru_page(page, true)) { |
diff --git a/mm/truncate.c b/mm/truncate.c index a01cce450a26..8d8c62d89e6d 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
| @@ -283,7 +283,7 @@ void truncate_inode_pages_range(struct address_space *mapping, | |||
| 283 | 283 | ||
| 284 | if (!trylock_page(page)) | 284 | if (!trylock_page(page)) |
| 285 | continue; | 285 | continue; |
| 286 | WARN_ON(page_to_pgoff(page) != index); | 286 | WARN_ON(page_to_index(page) != index); |
| 287 | if (PageWriteback(page)) { | 287 | if (PageWriteback(page)) { |
| 288 | unlock_page(page); | 288 | unlock_page(page); |
| 289 | continue; | 289 | continue; |
| @@ -371,7 +371,7 @@ void truncate_inode_pages_range(struct address_space *mapping, | |||
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | lock_page(page); | 373 | lock_page(page); |
| 374 | WARN_ON(page_to_pgoff(page) != index); | 374 | WARN_ON(page_to_index(page) != index); |
| 375 | wait_on_page_writeback(page); | 375 | wait_on_page_writeback(page); |
| 376 | truncate_inode_page(mapping, page); | 376 | truncate_inode_page(mapping, page); |
| 377 | unlock_page(page); | 377 | unlock_page(page); |
| @@ -492,7 +492,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping, | |||
| 492 | if (!trylock_page(page)) | 492 | if (!trylock_page(page)) |
| 493 | continue; | 493 | continue; |
| 494 | 494 | ||
| 495 | WARN_ON(page_to_pgoff(page) != index); | 495 | WARN_ON(page_to_index(page) != index); |
| 496 | 496 | ||
| 497 | /* Middle of THP: skip */ | 497 | /* Middle of THP: skip */ |
| 498 | if (PageTransTail(page)) { | 498 | if (PageTransTail(page)) { |
| @@ -612,7 +612,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping, | |||
| 612 | } | 612 | } |
| 613 | 613 | ||
| 614 | lock_page(page); | 614 | lock_page(page); |
| 615 | WARN_ON(page_to_pgoff(page) != index); | 615 | WARN_ON(page_to_index(page) != index); |
| 616 | if (page->mapping != mapping) { | 616 | if (page->mapping != mapping) { |
| 617 | unlock_page(page); | 617 | unlock_page(page); |
| 618 | continue; | 618 | continue; |
