aboutsummaryrefslogtreecommitdiffstats
path: root/mm/kasan/kasan.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/kasan/kasan.c')
-rw-r--r--mm/kasan/kasan.c108
1 files changed, 81 insertions, 27 deletions
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index 405bba487df5..e13d911251e7 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -5,7 +5,7 @@
5 * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com> 5 * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
6 * 6 *
7 * Some code borrowed from https://github.com/xairy/kasan-prototype by 7 * Some code borrowed from https://github.com/xairy/kasan-prototype by
8 * Andrey Konovalov <adech.fo@gmail.com> 8 * Andrey Konovalov <andreyknvl@gmail.com>
9 * 9 *
10 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as 11 * it under the terms of the GNU General Public License version 2 as
@@ -489,21 +489,17 @@ void kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags)
489 kasan_kmalloc(cache, object, cache->object_size, flags); 489 kasan_kmalloc(cache, object, cache->object_size, flags);
490} 490}
491 491
492static void kasan_poison_slab_free(struct kmem_cache *cache, void *object) 492static bool __kasan_slab_free(struct kmem_cache *cache, void *object,
493{ 493 unsigned long ip, bool quarantine)
494 unsigned long size = cache->object_size;
495 unsigned long rounded_up_size = round_up(size, KASAN_SHADOW_SCALE_SIZE);
496
497 /* RCU slabs could be legally used after free within the RCU period */
498 if (unlikely(cache->flags & SLAB_TYPESAFE_BY_RCU))
499 return;
500
501 kasan_poison_shadow(object, rounded_up_size, KASAN_KMALLOC_FREE);
502}
503
504bool kasan_slab_free(struct kmem_cache *cache, void *object)
505{ 494{
506 s8 shadow_byte; 495 s8 shadow_byte;
496 unsigned long rounded_up_size;
497
498 if (unlikely(nearest_obj(cache, virt_to_head_page(object), object) !=
499 object)) {
500 kasan_report_invalid_free(object, ip);
501 return true;
502 }
507 503
508 /* RCU slabs could be legally used after free within the RCU period */ 504 /* RCU slabs could be legally used after free within the RCU period */
509 if (unlikely(cache->flags & SLAB_TYPESAFE_BY_RCU)) 505 if (unlikely(cache->flags & SLAB_TYPESAFE_BY_RCU))
@@ -511,14 +507,14 @@ bool kasan_slab_free(struct kmem_cache *cache, void *object)
511 507
512 shadow_byte = READ_ONCE(*(s8 *)kasan_mem_to_shadow(object)); 508 shadow_byte = READ_ONCE(*(s8 *)kasan_mem_to_shadow(object));
513 if (shadow_byte < 0 || shadow_byte >= KASAN_SHADOW_SCALE_SIZE) { 509 if (shadow_byte < 0 || shadow_byte >= KASAN_SHADOW_SCALE_SIZE) {
514 kasan_report_double_free(cache, object, 510 kasan_report_invalid_free(object, ip);
515 __builtin_return_address(1));
516 return true; 511 return true;
517 } 512 }
518 513
519 kasan_poison_slab_free(cache, object); 514 rounded_up_size = round_up(cache->object_size, KASAN_SHADOW_SCALE_SIZE);
515 kasan_poison_shadow(object, rounded_up_size, KASAN_KMALLOC_FREE);
520 516
521 if (unlikely(!(cache->flags & SLAB_KASAN))) 517 if (!quarantine || unlikely(!(cache->flags & SLAB_KASAN)))
522 return false; 518 return false;
523 519
524 set_track(&get_alloc_info(cache, object)->free_track, GFP_NOWAIT); 520 set_track(&get_alloc_info(cache, object)->free_track, GFP_NOWAIT);
@@ -526,6 +522,11 @@ bool kasan_slab_free(struct kmem_cache *cache, void *object)
526 return true; 522 return true;
527} 523}
528 524
525bool kasan_slab_free(struct kmem_cache *cache, void *object, unsigned long ip)
526{
527 return __kasan_slab_free(cache, object, ip, true);
528}
529
529void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size, 530void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
530 gfp_t flags) 531 gfp_t flags)
531{ 532{
@@ -589,25 +590,29 @@ void kasan_krealloc(const void *object, size_t size, gfp_t flags)
589 kasan_kmalloc(page->slab_cache, object, size, flags); 590 kasan_kmalloc(page->slab_cache, object, size, flags);
590} 591}
591 592
592void kasan_poison_kfree(void *ptr) 593void kasan_poison_kfree(void *ptr, unsigned long ip)
593{ 594{
594 struct page *page; 595 struct page *page;
595 596
596 page = virt_to_head_page(ptr); 597 page = virt_to_head_page(ptr);
597 598
598 if (unlikely(!PageSlab(page))) 599 if (unlikely(!PageSlab(page))) {
600 if (ptr != page_address(page)) {
601 kasan_report_invalid_free(ptr, ip);
602 return;
603 }
599 kasan_poison_shadow(ptr, PAGE_SIZE << compound_order(page), 604 kasan_poison_shadow(ptr, PAGE_SIZE << compound_order(page),
600 KASAN_FREE_PAGE); 605 KASAN_FREE_PAGE);
601 else 606 } else {
602 kasan_poison_slab_free(page->slab_cache, ptr); 607 __kasan_slab_free(page->slab_cache, ptr, ip, false);
608 }
603} 609}
604 610
605void kasan_kfree_large(const void *ptr) 611void kasan_kfree_large(void *ptr, unsigned long ip)
606{ 612{
607 struct page *page = virt_to_page(ptr); 613 if (ptr != page_address(virt_to_head_page(ptr)))
608 614 kasan_report_invalid_free(ptr, ip);
609 kasan_poison_shadow(ptr, PAGE_SIZE << compound_order(page), 615 /* The object will be poisoned by page_alloc. */
610 KASAN_FREE_PAGE);
611} 616}
612 617
613int kasan_module_alloc(void *addr, size_t size) 618int kasan_module_alloc(void *addr, size_t size)
@@ -736,6 +741,55 @@ void __asan_unpoison_stack_memory(const void *addr, size_t size)
736} 741}
737EXPORT_SYMBOL(__asan_unpoison_stack_memory); 742EXPORT_SYMBOL(__asan_unpoison_stack_memory);
738 743
744/* Emitted by compiler to poison alloca()ed objects. */
745void __asan_alloca_poison(unsigned long addr, size_t size)
746{
747 size_t rounded_up_size = round_up(size, KASAN_SHADOW_SCALE_SIZE);
748 size_t padding_size = round_up(size, KASAN_ALLOCA_REDZONE_SIZE) -
749 rounded_up_size;
750 size_t rounded_down_size = round_down(size, KASAN_SHADOW_SCALE_SIZE);
751
752 const void *left_redzone = (const void *)(addr -
753 KASAN_ALLOCA_REDZONE_SIZE);
754 const void *right_redzone = (const void *)(addr + rounded_up_size);
755
756 WARN_ON(!IS_ALIGNED(addr, KASAN_ALLOCA_REDZONE_SIZE));
757
758 kasan_unpoison_shadow((const void *)(addr + rounded_down_size),
759 size - rounded_down_size);
760 kasan_poison_shadow(left_redzone, KASAN_ALLOCA_REDZONE_SIZE,
761 KASAN_ALLOCA_LEFT);
762 kasan_poison_shadow(right_redzone,
763 padding_size + KASAN_ALLOCA_REDZONE_SIZE,
764 KASAN_ALLOCA_RIGHT);
765}
766EXPORT_SYMBOL(__asan_alloca_poison);
767
768/* Emitted by compiler to unpoison alloca()ed areas when the stack unwinds. */
769void __asan_allocas_unpoison(const void *stack_top, const void *stack_bottom)
770{
771 if (unlikely(!stack_top || stack_top > stack_bottom))
772 return;
773
774 kasan_unpoison_shadow(stack_top, stack_bottom - stack_top);
775}
776EXPORT_SYMBOL(__asan_allocas_unpoison);
777
778/* Emitted by the compiler to [un]poison local variables. */
779#define DEFINE_ASAN_SET_SHADOW(byte) \
780 void __asan_set_shadow_##byte(const void *addr, size_t size) \
781 { \
782 __memset((void *)addr, 0x##byte, size); \
783 } \
784 EXPORT_SYMBOL(__asan_set_shadow_##byte)
785
786DEFINE_ASAN_SET_SHADOW(00);
787DEFINE_ASAN_SET_SHADOW(f1);
788DEFINE_ASAN_SET_SHADOW(f2);
789DEFINE_ASAN_SET_SHADOW(f3);
790DEFINE_ASAN_SET_SHADOW(f5);
791DEFINE_ASAN_SET_SHADOW(f8);
792
739#ifdef CONFIG_MEMORY_HOTPLUG 793#ifdef CONFIG_MEMORY_HOTPLUG
740static int __meminit kasan_mem_notifier(struct notifier_block *nb, 794static int __meminit kasan_mem_notifier(struct notifier_block *nb,
741 unsigned long action, void *data) 795 unsigned long action, void *data)