kasan: improve error reports
Subsystems (3)
v3 cover kasan: improve error reports
This patchset improves KASAN reports by making them easier to read and a little more detailed.
Also improves mm/kasan/report.c readability.
Effectively changes a use-after-free report to:
==================================================================
BUG: KASAN: use-after-free in kmalloc_uaf+0xaa/0xb6 [test_kasan] Write of size 1 at addr ffff88006aa59da8 by task insmod/3951 CPU: 1 PID: 3951 Comm: insmod Tainted: G B 4.10.0+ #84 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 Call Trace: dump_stack+0x292/0x398 print_address_description+0x73/0x280 kasan_report.part.2+0x207/0x2f0 __asan_report_store1_noabort+0x2c/0x30 kmalloc_uaf+0xaa/0xb6 [test_kasan] kmalloc_tests_init+0x4f/0xa48 [test_kasan] do_one_initcall+0xf3/0x390 do_init_module+0x215/0x5d0 load_module+0x54de/0x82b0 SYSC_init_module+0x3be/0x430 SyS_init_module+0x9/0x10 entry_SYSCALL_64_fastpath+0x1f/0xc2 RIP: 0033:0x7f22cfd0b9da RSP: 002b:00007ffe69118a78 EFLAGS: 00000206 ORIG_RAX: 00000000000000af RAX: ffffffffffffffda RBX: 0000555671242090 RCX: 00007f22cfd0b9da RDX: 00007f22cffcaf88 RSI: 000000000004df7e RDI: 00007f22d0399000 RBP: 00007f22cffcaf88 R08: 0000000000000003 R09: 0000000000000000 R10: 00007f22cfd07d0a R11: 0000000000000206 R12: 0000555671243190 R13: 000000000001fe81 R14: 0000000000000000 R15: 0000000000000004 Allocated by task 3951: save_stack_trace+0x16/0x20 save_stack+0x43/0xd0 kasan_kmalloc+0xad/0xe0 kmem_cache_alloc_trace+0x82/0x270 kmalloc_uaf+0x56/0xb6 [test_kasan] kmalloc_tests_init+0x4f/0xa48 [test_kasan] do_one_initcall+0xf3/0x390 do_init_module+0x215/0x5d0 load_module+0x54de/0x82b0 SYSC_init_module+0x3be/0x430 SyS_init_module+0x9/0x10 entry_SYSCALL_64_fastpath+0x1f/0xc2 Freed by task 3951: save_stack_trace+0x16/0x20 save_stack+0x43/0xd0 kasan_slab_free+0x72/0xc0 kfree+0xe8/0x2b0 kmalloc_uaf+0x85/0xb6 [test_kasan] kmalloc_tests_init+0x4f/0xa48 [test_kasan] do_one_initcall+0xf3/0x390 do_init_module+0x215/0x5d0 load_module+0x54de/0x82b0 SYSC_init_module+0x3be/0x430 SyS_init_module+0x9/0x10 entry_SYSCALL_64_fastpath+0x1f/0xc
Object at ffff880068388540 belongs to cache kmalloc-128 of size 128 Access 123 bytes inside of 128-byte region [ffff880068388540, ffff8800683885c0)
The buggy address belongs to the page:
page:ffffea0001aa9640 count:1 mapcount:0 mapping: (null) index:0x0
flags: 0x100000000000100(slab)
raw: 0100000000000100 0000000000000000 0000000000000000 0000000180800080
raw: ffffea0001abe380 0000000700000007 ffff88006c401b40 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff88006aa59c80: 00 00 fc fc 00 00 fc fc 00 00 fc fc 00 00 fc fc
ffff88006aa59d00: 00 00 fc fc 00 00 fc fc 00 00 fc fc 00 00 fc fc
>ffff88006aa59d80: fb fb fc fc fb fb fc fc fb fb fc fc fb fb fc fc
^
ffff88006aa59e00: fb fb fc fc fb fb fc fc fb fb fc fc fb fb fc fc
ffff88006aa59e80: fb fb fc fc 00 00 fc fc 00 00 fc fc 00 00 fc fc
==================================================================from:
==================================================================
BUG: KASAN: use-after-free in kmalloc_uaf+0xaa/0xb6 [test_kasan] at addr ffff88006c4dcb28
Write of size 1 by task insmod/3984
CPU: 1 PID: 3984 Comm: insmod Tainted: G B 4.10.0+ #83
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
Call Trace:
dump_stack+0x292/0x398
kasan_object_err+0x1c/0x70
kasan_report.part.1+0x20e/0x4e0
__asan_report_store1_noabort+0x2c/0x30
kmalloc_uaf+0xaa/0xb6 [test_kasan]
kmalloc_tests_init+0x4f/0xa48 [test_kasan]
do_one_initcall+0xf3/0x390
do_init_module+0x215/0x5d0
load_module+0x54de/0x82b0
SYSC_init_module+0x3be/0x430
SyS_init_module+0x9/0x10
entry_SYSCALL_64_fastpath+0x1f/0xc2
RIP: 0033:0x7feca0f779da
RSP: 002b:00007ffdfeae5218 EFLAGS: 00000206 ORIG_RAX: 00000000000000af
RAX: ffffffffffffffda RBX: 000055a064c13090 RCX: 00007feca0f779da
RDX: 00007feca1236f88 RSI: 000000000004df7e RDI: 00007feca1605000
RBP: 00007feca1236f88 R08: 0000000000000003 R09: 0000000000000000
R10: 00007feca0f73d0a R11: 0000000000000206 R12: 000055a064c14190
R13: 000000000001fe81 R14: 0000000000000000 R15: 0000000000000004
Object at ffff88006c4dcb20, in cache kmalloc-16 size: 16
Allocated:
PID = 3984
save_stack_trace+0x16/0x20
save_stack+0x43/0xd0
kasan_kmalloc+0xad/0xe0
kmem_cache_alloc_trace+0x82/0x270
kmalloc_uaf+0x56/0xb6 [test_kasan]
kmalloc_tests_init+0x4f/0xa48 [test_kasan]
do_one_initcall+0xf3/0x390
do_init_module+0x215/0x5d0
load_module+0x54de/0x82b0
SYSC_init_module+0x3be/0x430
SyS_init_module+0x9/0x10
entry_SYSCALL_64_fastpath+0x1f/0xc2
Freed:
PID = 3984
save_stack_trace+0x16/0x20
save_stack+0x43/0xd0
kasan_slab_free+0x73/0xc0
kfree+0xe8/0x2b0
kmalloc_uaf+0x85/0xb6 [test_kasan]
kmalloc_tests_init+0x4f/0xa48 [test_kasan]
do_one_initcall+0xf3/0x390
do_init_module+0x215/0x5d0
load_module+0x54de/0x82b0
SYSC_init_module+0x3be/0x430
SyS_init_module+0x9/0x10
entry_SYSCALL_64_fastpath+0x1f/0xc2
Memory state around the buggy address:
ffff88006c4dca00: fb fb fc fc fb fb fc fc fb fb fc fc fb fb fc fc
ffff88006c4dca80: fb fb fc fc fb fb fc fc fb fb fc fc fb fb fc fc
>ffff88006c4dcb00: fb fb fc fc fb fb fc fc fb fb fc fc fb fb fc fc
^
ffff88006c4dcb80: fb fb fc fc 00 00 fc fc fb fb fc fc fb fb fc fc
ffff88006c4dcc00: fb fb fc fc fb fb fc fc fb fb fc fc fb fb fc fc
==================================================================Changes in v3:
- make slab objects description shorter
- pass caller addr from SLUB/SLAB instead of usign __builtin_return_address
- make get_wild_bug_type() static
- combine consequent lines into one when possible
Changes in v2:
- split patch in multiple smaller ones
- improve double-free reports
Andrey Konovalov (9):
kasan: introduce helper functions for determining bug type
kasan: unify report headers
kasan: change allocation and freeing stack traces headers
kasan: simplify address description logic
kasan: change report header
kasan: improve slab object description
kasan: print page description after stacks
kasan: improve double-free report format
kasan: separate report parts by empty lines
include/linux/kasan.h | 2 +- mm/kasan/kasan.c | 5 +- mm/kasan/kasan.h | 2 +- mm/kasan/report.c | 185 +++++++++++++++++++++++++++++++++----------------- mm/slab.c | 2 +- mm/slub.c | 12 ++-- 6 files changed, 134 insertions(+), 74 deletions(-)
Signature · 7 lines
2.12.0.rc1.440.g5b76565f74-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 1/9 kasan: introduce helper functions for determining bug type
Introduce get_shadow_bug_type() function, which determines bug type based on the shadow value for a particular kernel address. Introduce get_wild_bug_type() function, which determines bug type for addresses which don't have a corresponding shadow value.
--- mm/kasan/report.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-)
mm/kasan/report.c +30 -10
@@ -49,7 +49,13 @@ static const void *find_first_bad_addr(const void *addr, size_t size)return first_bad_addr; } -static void print_error_description (struct kasan_access_info *info) +static bool addr_has_shadow (struct kasan_access_info *info) +{ +return (info->access_addr >= +kasan_shadow_to_mem ((void *)KASAN_SHADOW_START )); +} + +static const char *get_shadow_bug_type (struct kasan_access_info *info) {const char *bug_type ="unknown-crash" ;u8 *shadow_addr;
@@ -96,6 +102,27 @@ static void print_error_description(struct kasan_access_info *info)break ; } +return bug_type; +} + +static const char *get_wild_bug_type (struct kasan_access_info *info) +{ +const char *bug_type; + +if ((unsigned long )info->access_addr <PAGE_SIZE ) + bug_type ="null-ptr-deref" ; +else if ((unsigned long )info->access_addr <TASK_SIZE ) + bug_type ="user-memory-access" ; +else + bug_type ="wild-memory-access" ; + +return bug_type; +} + +static void print_error_description (struct kasan_access_info *info) +{ +const char *bug_type =get_shadow_bug_type (info); +pr_err ("BUG: KASAN: %s in %pS at addr %p\n" , bug_type, (void *)info->ip, info->access_addr);
@@ -265,18 +292,11 @@ static void print_shadow_for_address(const void *addr)static void kasan_report_error (struct kasan_access_info *info) {unsigned long flags; -const char *bug_type;kasan_start_report (&flags); -if (info->access_addr < -kasan_shadow_to_mem ((void *)KASAN_SHADOW_START )) { -if ((unsigned long )info->access_addr <PAGE_SIZE ) - bug_type ="null-ptr-deref" ; -else if ((unsigned long )info->access_addr <TASK_SIZE ) - bug_type ="user-memory-access" ; -else - bug_type ="wild-memory-access" ; +if (!addr_has_shadow (info)) { +const char *bug_type =get_wild_bug_type (info);pr_err ("BUG: KASAN: %s on address %p\n" , bug_type, info->access_addr); pr_err("%s of size %zu by task %s/%d\n",
Signature · 7 lines
2.12.0.rc1.440.g5b76565f74-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 2/9 kasan: unify report headers
In reply to Andrey KonovalovUnify KASAN report header format for different kinds of bad memory accesses. Makes the code simpler.
--- mm/kasan/report.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
mm/kasan/report.c +13 -13
@@ -119,16 +119,22 @@ static const char *get_wild_bug_type(struct kasan_access_info *info)return bug_type; } +static const char *get_bug_type (struct kasan_access_info *info) +{ +if (addr_has_shadow (info)) +return get_shadow_bug_type (info); +return get_wild_bug_type (info); +} +static void print_error_description (struct kasan_access_info *info) { -const char *bug_type =get_shadow_bug_type (info); +const char *bug_type =get_bug_type (info);pr_err ("BUG: KASAN: %s in %pS at addr %p\n" , - bug_type, (void *)info->ip, - info->access_addr); + bug_type, (void *)info->ip, info->access_addr);pr_err ("%s of size %zu by task %s/%d\n" , - info->is_write ?"Write" :"Read" , - info->access_size, current->comm,task_pid_nr (current)); + info->is_write ?"Write" :"Read" , info->access_size, + current->comm,task_pid_nr (current)); }static inline bool kernel_or_module_addr (const void *addr)
@@ -295,17 +301,11 @@ static void kasan_report_error(struct kasan_access_info *info)kasan_start_report (&flags); +print_error_description (info); +if (!addr_has_shadow (info)) { -const char *bug_type =get_wild_bug_type (info); -pr_err ("BUG: KASAN: %s on address %p\n" , - bug_type, info->access_addr); -pr_err ("%s of size %zu by task %s/%d\n" , - info->is_write ?"Write" :"Read" , - info->access_size, current->comm, -task_pid_nr (current));dump_stack (); }else { -print_error_description (info);print_address_description (info);print_shadow_for_address (info->first_bad_addr); }
Signature · 7 lines
2.12.0.rc1.440.g5b76565f74-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 3/9 kasan: change allocation and freeing stack traces headers
In reply to Andrey KonovalovChange stack traces headers from:
Allocated:
PID = 42
to:
Allocated by task 42:
Makes the report one line shorter and look better.
--- mm/kasan/report.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
mm/kasan/report.c +4 -6
@@ -175,9 +175,9 @@ static void kasan_end_report(unsigned long *flags)kasan_enable_current (); } -static void print_track (struct kasan_track *track) +static void print_track (struct kasan_track *track,const char *prefix) { -pr_err ("PID = %u\n" , track->pid); +pr_err ("%s by task %u:\n" , prefix, track->pid);if (track->stack) {struct stack_trace trace;
@@ -199,10 +199,8 @@ static void kasan_object_err(struct kmem_cache *cache, void *object)if (!(cache->flags &SLAB_KASAN ))return ; -pr_err ("Allocated:\n" ); -print_track (&alloc_info->alloc_track); -pr_err ("Freed:\n" ); -print_track (&alloc_info->free_track); +print_track (&alloc_info->alloc_track,"Allocated" ); +print_track (&alloc_info->free_track,"Freed" ); } void kasan_report_double_free(struct kmem_cache *cache, void *object,
Signature · 7 lines
2.12.0.rc1.440.g5b76565f74-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 4/9 kasan: simplify address description logic
In reply to Andrey KonovalovSimplify logic for describing a memory address.
Add addr_to_page() helper function.
Makes the code easier to follow.
--- mm/kasan/report.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-)
mm/kasan/report.c +20 -16
@@ -188,11 +188,17 @@ static void print_track(struct kasan_track *track, const char *prefix) } } -static void kasan_object_err (struct kmem_cache *cache,void *object) +static struct page *addr_to_page (const void *addr) +{ +if ((addr >= (void *)PAGE_OFFSET ) && (addr < high_memory)) +return virt_to_head_page (addr); +return NULL ; +} + +static void describe_object (struct kmem_cache *cache,void *object) {struct kasan_alloc_meta *alloc_info =get_alloc_info (cache, object); -dump_stack ();pr_err ("Object at %p, in cache %s size: %d\n" , object, cache->name, cache->object_size);
@@ -211,34 +217,32 @@ void kasan_report_double_free(struct kmem_cache *cache, void *object,kasan_start_report (&flags);pr_err ("BUG: Double free or freeing an invalid pointer\n" );pr_err ("Unexpected shadow byte: 0x%hhX\n" , shadow); -kasan_object_err (cache, object); +dump_stack (); +describe_object (cache, object);kasan_end_report (&flags); }static void print_address_description (struct kasan_access_info *info) {const void *addr = info->access_addr; +struct page *page =addr_to_page (addr); -if ((addr >= (void *)PAGE_OFFSET ) && - (addr < high_memory)) { -struct page *page =virt_to_head_page (addr); - -if (PageSlab (page)) { -void *object; -struct kmem_cache *cache = page->slab_cache; - object =nearest_obj (cache, page, - (void *)info->access_addr); -kasan_object_err (cache, object); -return ; - } +if (page)dump_page (page,"kasan: bad access detected" ); + +dump_stack (); + +if (page &&PageSlab (page)) { +struct kmem_cache *cache = page->slab_cache; +void *object =nearest_obj (cache, page, (void *)addr); + +describe_object (cache, object); }if (kernel_or_module_addr (addr)) {if (!init_task_stack_addr (addr))pr_err ("Address belongs to variable %pS\n" , addr); } -dump_stack (); }static bool row_is_guilty (const void *row,const void *guilty)
Signature · 7 lines
2.12.0.rc1.440.g5b76565f74-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 5/9 kasan: change report header
In reply to Andrey KonovalovChange report header format from:
BUG: KASAN: use-after-free in unwind_get_return_address+0x28a/0x2c0 at addr ffff880069437950 Read of size 8 by task insmod/3925
to:
BUG: KASAN: use-after-free in unwind_get_return_address+0x28a/0x2c0 Read of size 8 at addr ffff880069437950 by task insmod/3925
The exact access address is not usually important, so move it to the second line. This also makes the header look visually balanced.
--- mm/kasan/report.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
mm/kasan/report.c +3 -4
@@ -130,11 +130,10 @@ static void print_error_description(struct kasan_access_info *info) {const char *bug_type =get_bug_type (info); -pr_err ("BUG: KASAN: %s in %pS at addr %p\n" , - bug_type, (void *)info->ip, info->access_addr); -pr_err ("%s of size %zu by task %s/%d\n" , +pr_err ("BUG: KASAN: %s in %pS\n" , bug_type, (void *)info->ip); +pr_err ("%s of size %zu at addr %p by task %s/%d\n" , info->is_write ?"Write" :"Read" , info->access_size, - current->comm,task_pid_nr (current)); + info->access_addr, current->comm,task_pid_nr (current)); }static inline bool kernel_or_module_addr (const void *addr)
Signature · 7 lines
2.12.0.rc1.440.g5b76565f74-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 6/9 kasan: improve slab object description
In reply to Andrey KonovalovChanges slab object description from:
Object at ffff880068388540, in cache kmalloc-128 size: 128
to:
Object at ffff880068388540 belongs to cache kmalloc-128 of size 128 Access 123 bytes inside of 128-byte region [ffff880068388540, ffff8800683885c0)
This adds information about relative offset of the accessed address to the start of the object.
--- mm/kasan/report.c | 51 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 11 deletions(-)
mm/kasan/report.c +40 -11
@@ -194,18 +194,47 @@ static struct page *addr_to_page(const void *addr)return NULL ; } -static void describe_object (struct kmem_cache *cache,void *object) +static void describe_object_addr (struct kmem_cache *cache,void *object, +const void *addr) { -struct kasan_alloc_meta *alloc_info =get_alloc_info (cache, object); +unsigned long access_addr = (unsigned long )addr; +unsigned long object_addr = (unsigned long )object; +const char *rel_type; +int rel_bytes; -pr_err ("Object at %p, in cache %s size: %d\n" , object, cache->name, - cache->object_size); +pr_err ("Object at %p belongs to cache %s of size %d\n" , + object, cache->name, cache->object_size); -if (!(cache->flags &SLAB_KASAN )) +if (!addr)return ; -print_track (&alloc_info->alloc_track,"Allocated" ); -print_track (&alloc_info->free_track,"Freed" ); +if (access_addr < object_addr) { + rel_type ="to the left" ; + rel_bytes = object_addr - access_addr; + }else if (access_addr >= object_addr + cache->object_size) { + rel_type ="to the right" ; + rel_bytes = access_addr - (object_addr + cache->object_size); + }else { + rel_type ="inside" ; + rel_bytes = access_addr - object_addr; + } + +pr_err ("Access %d bytes %s of %d-byte region [%p, %p)\n" , + rel_bytes, rel_type, cache->object_size, (void *)object_addr, + (void *)(object_addr + cache->object_size)); +} + +static void describe_object (struct kmem_cache *cache,void *object, +const void *addr) +{ +struct kasan_alloc_meta *alloc_info =get_alloc_info (cache, object); + +if (cache->flags &SLAB_KASAN ) { +print_track (&alloc_info->alloc_track,"Allocated" ); +print_track (&alloc_info->free_track,"Freed" ); + } + +describe_object_addr (cache, object, addr); } void kasan_report_double_free(struct kmem_cache *cache, void *object,
@@ -217,13 +246,13 @@ void kasan_report_double_free(struct kmem_cache *cache, void *object,pr_err ("BUG: Double free or freeing an invalid pointer\n" );pr_err ("Unexpected shadow byte: 0x%hhX\n" , shadow);dump_stack (); -describe_object (cache, object); +describe_object (cache, object,NULL );kasan_end_report (&flags); }static void print_address_description (struct kasan_access_info *info) { -const void *addr = info->access_addr; +void *addr = (void *)info->access_addr;struct page *page =addr_to_page (addr);if (page)
@@ -233,9 +262,9 @@ static void print_address_description(struct kasan_access_info *info)if (page &&PageSlab (page)) {struct kmem_cache *cache = page->slab_cache; -void *object =nearest_obj (cache, page, (void *)addr); +void *object =nearest_obj (cache, page, addr); -describe_object (cache, object); +describe_object (cache, object, addr); }if (kernel_or_module_addr (addr)) {
Signature · 7 lines
2.12.0.rc1.440.g5b76565f74-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 7/9 kasan: print page description after stacks
In reply to Andrey KonovalovMoves page description after the stacks since it's less important.
--- mm/kasan/report.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
mm/kasan/report.c +8 -6
@@ -255,9 +255,6 @@ static void print_address_description(struct kasan_access_info *info)void *addr = (void *)info->access_addr;struct page *page =addr_to_page (addr); -if (page) -dump_page (page,"kasan: bad access detected" ); -dump_stack ();if (page &&PageSlab (page)) {
@@ -267,9 +264,14 @@ static void print_address_description(struct kasan_access_info *info)describe_object (cache, object, addr); } -if (kernel_or_module_addr (addr)) { -if (!init_task_stack_addr (addr)) -pr_err ("Address belongs to variable %pS\n" , addr); +if (kernel_or_module_addr (addr) && !init_task_stack_addr (addr)) { +pr_err ("The buggy address belongs to the variable:\n" ); +pr_err (" %pS\n" , addr); + } + +if (page) { +pr_err ("The buggy address belongs to the page:\n" ); +dump_page (page,"kasan: bad access detected" ); } }
Signature · 7 lines
2.12.0.rc1.440.g5b76565f74-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 8/9 kasan: improve double-free report format
In reply to Andrey KonovalovChanges double-free report header from:
BUG: Double free or freeing an invalid pointer
Unexpected shadow byte: 0xFB
to:
BUG: KASAN: double-free or invalid-free in kmalloc_oob_left+0xe5/0xef
This makes a bug uniquely identifiable by the first report line. To account for removing of the unexpected shadow value, print shadow bytes at the end of the report as in reports for other kinds of bugs.
To print caller funtion name in the report header, the caller address is passed from SLUB/SLAB free handlers.
--- include/linux/kasan.h | 2 +- mm/kasan/kasan.c | 5 +++-- mm/kasan/kasan.h | 2 +- mm/kasan/report.c | 30 ++++++++++++++---------------- mm/slab.c | 2 +- mm/slub.c | 12 +++++++----- 6 files changed, 27 insertions(+), 26 deletions(-)
include/linux/kasan.h +1 -1
@@ -60,7 +60,7 @@ void kasan_kmalloc(struct kmem_cache *s, const void *object, size_t size,void kasan_krealloc (const void *object,size_t new_size,gfp_t flags);void kasan_slab_alloc (struct kmem_cache *s,void *object,gfp_t flags); -bool kasan_slab_free (struct kmem_cache *s,void *object); +bool kasan_slab_free (struct kmem_cache *s,void *object,unsigned long pc);struct kasan_cache {int alloc_meta_offset;
mm/kasan/kasan.c +3 -2
@@ -567,7 +567,8 @@ static void kasan_poison_slab_free(struct kmem_cache *cache, void *object)kasan_poison_shadow (object, rounded_up_size,KASAN_KMALLOC_FREE ); } -bool kasan_slab_free (struct kmem_cache *cache,void *object) +bool kasan_slab_free (struct kmem_cache *cache,void *object, +unsigned long pc) {s8 shadow_byte;
@@ -577,7 +578,7 @@ bool kasan_slab_free(struct kmem_cache *cache, void *object) shadow_byte =READ_ONCE (*(s8 *)kasan_mem_to_shadow (object));if (shadow_byte <0 || shadow_byte >=KASAN_SHADOW_SCALE_SIZE ) { -kasan_report_double_free (cache, object, shadow_byte); +kasan_report_double_free (cache, object, pc);return true; }
mm/kasan/kasan.h +1 -1
@@ -104,7 +104,7 @@ static inline bool kasan_report_enabled(void)void kasan_report (unsigned long addr,size_t size,bool is_write,unsigned long ip);void kasan_report_double_free (struct kmem_cache *cache,void *object, -s8 shadow); +void *ip);#if defined(CONFIG_SLAB ) || defined(CONFIG_SLUB )void quarantine_put (struct kasan_free_meta *info,struct kmem_cache *cache);
mm/kasan/report.c +14 -16
@@ -237,22 +237,8 @@ static void describe_object(struct kmem_cache *cache, void *object,describe_object_addr (cache, object, addr); } -void kasan_report_double_free (struct kmem_cache *cache,void *object, -s8 shadow) -{ -unsigned long flags; - -kasan_start_report (&flags); -pr_err ("BUG: Double free or freeing an invalid pointer\n" ); -pr_err ("Unexpected shadow byte: 0x%hhX\n" , shadow); -dump_stack (); -describe_object (cache, object,NULL ); -kasan_end_report (&flags); -} - -static void print_address_description (struct kasan_access_info *info) +static void print_address_description (void *addr) { -void *addr = (void *)info->access_addr;struct page *page =addr_to_page (addr);dump_stack ();
@@ -327,6 +313,18 @@ static void print_shadow_for_address(const void *addr) } } +void kasan_report_double_free (struct kmem_cache *cache,void *object, +void *ip) +{ +unsigned long flags; + +kasan_start_report (&flags); +pr_err ("BUG: KASAN: double-free or invalid-free in %pS\n" , ip); +print_address_description (object); +print_shadow_for_address (object); +kasan_end_report (&flags); +} +static void kasan_report_error (struct kasan_access_info *info) {unsigned long flags;
@@ -338,7 +336,7 @@ static void kasan_report_error(struct kasan_access_info *info)if (!addr_has_shadow (info)) {dump_stack (); }else { -print_address_description (info); +print_address_description ((void *)info->access_addr);print_shadow_for_address (info->first_bad_addr); }
mm/slab.c +1 -1
@@ -3508,7 +3508,7 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp, unsigned long caller) {/* Put the object into the quarantine, don't touch it for now. */ -if (kasan_slab_free (cachep, objp)) +if (kasan_slab_free (cachep, objp, caller))return ;___cache_free (cachep, objp, caller);
mm/slub.c +7 -5
@@ -1325,7 +1325,8 @@ static inline void kfree_hook(const void *x)kasan_kfree_large (x); } -static inline void *slab_free_hook (struct kmem_cache *s,void *x) +static inline void *slab_free_hook (struct kmem_cache *s,void *x, +unsigned long addr) {void *freeptr;
@@ -1354,12 +1355,13 @@ static inline void *slab_free_hook(struct kmem_cache *s, void *x)* kasan_slab_free() may put x into memory quarantine, delaying its * reuse. In this case the object's freelist pointer is changed. */ -kasan_slab_free (s, x); +kasan_slab_free (s, x, addr);return freeptr; }static inline void slab_free_freelist_hook (struct kmem_cache *s, -void *head,void *tail) +void *head,void *tail, +unsigned long addr) {/* * Compiler cannot detect this function can be removed if slab_free_hook()
@@ -1376,7 +1378,7 @@ static inline void slab_free_freelist_hook(struct kmem_cache *s,void *freeptr;do { - freeptr =slab_free_hook (s, object); + freeptr =slab_free_hook (s, object, addr); }while ((object != tail_obj) && (object = freeptr));#endif }
@@ -2958,7 +2960,7 @@ static __always_inline void slab_free(struct kmem_cache *s, struct page *page, void *head, void *tail, int cnt, unsigned long addr) { -slab_free_freelist_hook (s ,head ,tail ); +slab_free_freelist_hook (s ,head ,tail ,addr );/* * slab_free_freelist_hook() could have put the items into quarantine. * If so, no need to free them.
Signature · 7 lines
2.12.0.rc1.440.g5b76565f74-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 9/9 kasan: separate report parts by empty lines
In reply to Andrey KonovalovMakes the report easier to read.
--- mm/kasan/report.c | 7 +++++++ 1 file changed, 7 insertions(+)
mm/kasan/report.c +7 -0
@@ -231,7 +231,9 @@ static void describe_object(struct kmem_cache *cache, void *object,if (cache->flags &SLAB_KASAN ) {print_track (&alloc_info->alloc_track,"Allocated" ); +pr_err ("\n" );print_track (&alloc_info->free_track,"Freed" ); +pr_err ("\n" ); }describe_object_addr (cache, object, addr);
@@ -242,6 +244,7 @@ static void print_address_description(void *addr)struct page *page =addr_to_page (addr);dump_stack (); +pr_err ("\n" );if (page &&PageSlab (page)) {struct kmem_cache *cache = page->slab_cache;
@@ -320,7 +323,9 @@ void kasan_report_double_free(struct kmem_cache *cache, void *object,kasan_start_report (&flags);pr_err ("BUG: KASAN: double-free or invalid-free in %pS\n" , ip); +pr_err ("\n" );print_address_description (object); +pr_err ("\n" );print_shadow_for_address (object);kasan_end_report (&flags); }
@@ -332,11 +337,13 @@ static void kasan_report_error(struct kasan_access_info *info)kasan_start_report (&flags);print_error_description (info); +pr_err ("\n" );if (!addr_has_shadow (info)) {dump_stack (); }else {print_address_description ((void *)info->access_addr); +pr_err ("\n" );print_shadow_for_address (info->first_bad_addr); }
Signature · 7 lines
2.12.0.rc1.440.g5b76565f74-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>