* [PATCH v3 1/9] kasan: introduce helper functions for determining bug type
2017-03-06 16:00 [PATCH v3 0/9] kasan: improve error reports Andrey Konovalov
@ 2017-03-06 16:00 ` Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 2/9] kasan: unify report headers Andrey Konovalov
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andrey Konovalov @ 2017-03-06 16:00 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov, kasan-dev,
linux-mm, linux-kernel
Cc: Andrey Konovalov
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.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/kasan/report.c | 40 ++++++++++++++++++++++++++++++----------
1 file changed, 30 insertions(+), 10 deletions(-)
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index f479365530b6..e3af37b7a74c 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -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",
--
2.12.0.rc1.440.g5b76565f74-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 2/9] kasan: unify report headers
2017-03-06 16:00 [PATCH v3 0/9] kasan: improve error reports Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 1/9] kasan: introduce helper functions for determining bug type Andrey Konovalov
@ 2017-03-06 16:00 ` Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 3/9] kasan: change allocation and freeing stack traces headers Andrey Konovalov
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andrey Konovalov @ 2017-03-06 16:00 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov, kasan-dev,
linux-mm, linux-kernel
Cc: Andrey Konovalov
Unify KASAN report header format for different kinds of bad memory
accesses. Makes the code simpler.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/kasan/report.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index e3af37b7a74c..fc0577d15671 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -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);
}
--
2.12.0.rc1.440.g5b76565f74-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 3/9] kasan: change allocation and freeing stack traces headers
2017-03-06 16:00 [PATCH v3 0/9] kasan: improve error reports Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 1/9] kasan: introduce helper functions for determining bug type Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 2/9] kasan: unify report headers Andrey Konovalov
@ 2017-03-06 16:00 ` Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 4/9] kasan: simplify address description logic Andrey Konovalov
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andrey Konovalov @ 2017-03-06 16:00 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov, kasan-dev,
linux-mm, linux-kernel
Cc: Andrey Konovalov
Change stack traces headers from:
Allocated:
PID = 42
to:
Allocated by task 42:
Makes the report one line shorter and look better.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/kasan/report.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index fc0577d15671..382d4d2b9052 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -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,
--
2.12.0.rc1.440.g5b76565f74-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 4/9] kasan: simplify address description logic
2017-03-06 16:00 [PATCH v3 0/9] kasan: improve error reports Andrey Konovalov
` (2 preceding siblings ...)
2017-03-06 16:00 ` [PATCH v3 3/9] kasan: change allocation and freeing stack traces headers Andrey Konovalov
@ 2017-03-06 16:00 ` Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 5/9] kasan: change report header Andrey Konovalov
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andrey Konovalov @ 2017-03-06 16:00 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov, kasan-dev,
linux-mm, linux-kernel
Cc: Andrey Konovalov
Simplify logic for describing a memory address.
Add addr_to_page() helper function.
Makes the code easier to follow.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/kasan/report.c | 36 ++++++++++++++++++++----------------
1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 382d4d2b9052..f77341979dae 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -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)
--
2.12.0.rc1.440.g5b76565f74-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 5/9] kasan: change report header
2017-03-06 16:00 [PATCH v3 0/9] kasan: improve error reports Andrey Konovalov
` (3 preceding siblings ...)
2017-03-06 16:00 ` [PATCH v3 4/9] kasan: simplify address description logic Andrey Konovalov
@ 2017-03-06 16:00 ` Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 6/9] kasan: improve slab object description Andrey Konovalov
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andrey Konovalov @ 2017-03-06 16:00 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov, kasan-dev,
linux-mm, linux-kernel
Cc: Andrey Konovalov
Change 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.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/kasan/report.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index f77341979dae..156f998199e2 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -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)
--
2.12.0.rc1.440.g5b76565f74-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 6/9] kasan: improve slab object description
2017-03-06 16:00 [PATCH v3 0/9] kasan: improve error reports Andrey Konovalov
` (4 preceding siblings ...)
2017-03-06 16:00 ` [PATCH v3 5/9] kasan: change report header Andrey Konovalov
@ 2017-03-06 16:00 ` Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 7/9] kasan: print page description after stacks Andrey Konovalov
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Andrey Konovalov @ 2017-03-06 16:00 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov, kasan-dev,
linux-mm, linux-kernel
Cc: Andrey Konovalov
Changes 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.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/kasan/report.c | 51 ++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 40 insertions(+), 11 deletions(-)
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 156f998199e2..87f8293d7b79 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -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)) {
--
2.12.0.rc1.440.g5b76565f74-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 7/9] kasan: print page description after stacks
2017-03-06 16:00 [PATCH v3 0/9] kasan: improve error reports Andrey Konovalov
` (5 preceding siblings ...)
2017-03-06 16:00 ` [PATCH v3 6/9] kasan: improve slab object description Andrey Konovalov
@ 2017-03-06 16:00 ` Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 8/9] kasan: improve double-free report format Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 9/9] kasan: separate report parts by empty lines Andrey Konovalov
8 siblings, 0 replies; 10+ messages in thread
From: Andrey Konovalov @ 2017-03-06 16:00 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov, kasan-dev,
linux-mm, linux-kernel
Cc: Andrey Konovalov
Moves page description after the stacks since it's less important.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/kasan/report.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 87f8293d7b79..09a5f5b4bc79 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -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");
}
}
--
2.12.0.rc1.440.g5b76565f74-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 8/9] kasan: improve double-free report format
2017-03-06 16:00 [PATCH v3 0/9] kasan: improve error reports Andrey Konovalov
` (6 preceding siblings ...)
2017-03-06 16:00 ` [PATCH v3 7/9] kasan: print page description after stacks Andrey Konovalov
@ 2017-03-06 16:00 ` Andrey Konovalov
2017-03-06 16:00 ` [PATCH v3 9/9] kasan: separate report parts by empty lines Andrey Konovalov
8 siblings, 0 replies; 10+ messages in thread
From: Andrey Konovalov @ 2017-03-06 16:00 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov, kasan-dev,
linux-mm, linux-kernel
Cc: Andrey Konovalov
Changes 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.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
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(-)
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index ceb3fe78a0d3..55604168f48f 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -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;
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index 98b27195e38b..83cc011bb9bc 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -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;
}
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
index 1c260e6b3b3c..75729173ade9 100644
--- a/mm/kasan/kasan.h
+++ b/mm/kasan/kasan.h
@@ -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);
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 09a5f5b4bc79..e5b762f4a6a4 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -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);
}
diff --git a/mm/slab.c b/mm/slab.c
index 807d86c76908..aba5f30ea63e 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -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);
diff --git a/mm/slub.c b/mm/slub.c
index 7f4bc7027ed5..763570a0b15e 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -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.
--
2.12.0.rc1.440.g5b76565f74-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 9/9] kasan: separate report parts by empty lines
2017-03-06 16:00 [PATCH v3 0/9] kasan: improve error reports Andrey Konovalov
` (7 preceding siblings ...)
2017-03-06 16:00 ` [PATCH v3 8/9] kasan: improve double-free report format Andrey Konovalov
@ 2017-03-06 16:00 ` Andrey Konovalov
8 siblings, 0 replies; 10+ messages in thread
From: Andrey Konovalov @ 2017-03-06 16:00 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov, kasan-dev,
linux-mm, linux-kernel
Cc: Andrey Konovalov
Makes the report easier to read.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/kasan/report.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index e5b762f4a6a4..2f3ff28b4d76 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -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);
}
--
2.12.0.rc1.440.g5b76565f74-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 10+ messages in thread