Skip to content

Commit 3de0de7

Browse files
Kuan-Ying Leeakpm00
authored andcommitted
kasan: separate double free case from invalid free
Currently, KASAN describes all invalid-free/double-free bugs as "double-free or invalid-free". This is ambiguous. KASAN should report "double-free" when a double-free is a more likely cause (the address points to the start of an object) and report "invalid-free" otherwise [1]. [1] https://bugzilla.kernel.org/show_bug.cgi?id=212193 Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Kuan-Ying Lee <[email protected]> Reviewed-by: Dmitry Vyukov <[email protected]> Reviewed-by: Andrey Konovalov <[email protected]> Cc: Andrey Ryabinin <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Vincenzo Frascino <[email protected]> Cc: Matthias Brugger <[email protected]> Cc: Chinwen Chang <[email protected]> Cc: Yee Lee <[email protected]> Cc: Andrew Yang <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent cb55b83 commit 3de0de7

File tree

3 files changed

+14
-9
lines changed

3 files changed

+14
-9
lines changed

mm/kasan/common.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ static inline bool ____kasan_slab_free(struct kmem_cache *cache, void *object,
343343

344344
if (unlikely(nearest_obj(cache, virt_to_slab(object), object) !=
345345
object)) {
346-
kasan_report_invalid_free(tagged_object, ip);
346+
kasan_report_invalid_free(tagged_object, ip, KASAN_REPORT_INVALID_FREE);
347347
return true;
348348
}
349349

@@ -352,7 +352,7 @@ static inline bool ____kasan_slab_free(struct kmem_cache *cache, void *object,
352352
return false;
353353

354354
if (!kasan_byte_accessible(tagged_object)) {
355-
kasan_report_invalid_free(tagged_object, ip);
355+
kasan_report_invalid_free(tagged_object, ip, KASAN_REPORT_DOUBLE_FREE);
356356
return true;
357357
}
358358

@@ -377,12 +377,12 @@ bool __kasan_slab_free(struct kmem_cache *cache, void *object,
377377
static inline bool ____kasan_kfree_large(void *ptr, unsigned long ip)
378378
{
379379
if (ptr != page_address(virt_to_head_page(ptr))) {
380-
kasan_report_invalid_free(ptr, ip);
380+
kasan_report_invalid_free(ptr, ip, KASAN_REPORT_INVALID_FREE);
381381
return true;
382382
}
383383

384384
if (!kasan_byte_accessible(ptr)) {
385-
kasan_report_invalid_free(ptr, ip);
385+
kasan_report_invalid_free(ptr, ip, KASAN_REPORT_DOUBLE_FREE);
386386
return true;
387387
}
388388

mm/kasan/kasan.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ static inline bool kasan_sync_fault_possible(void)
125125
enum kasan_report_type {
126126
KASAN_REPORT_ACCESS,
127127
KASAN_REPORT_INVALID_FREE,
128+
KASAN_REPORT_DOUBLE_FREE,
128129
};
129130

130131
struct kasan_report_info {
@@ -277,7 +278,7 @@ static inline void kasan_print_address_stack_frame(const void *addr) { }
277278

278279
bool kasan_report(unsigned long addr, size_t size,
279280
bool is_write, unsigned long ip);
280-
void kasan_report_invalid_free(void *object, unsigned long ip);
281+
void kasan_report_invalid_free(void *object, unsigned long ip, enum kasan_report_type type);
281282

282283
struct page *kasan_addr_to_page(const void *addr);
283284
struct slab *kasan_addr_to_slab(const void *addr);

mm/kasan/report.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,12 @@ static void end_report(unsigned long *flags, void *addr)
176176
static void print_error_description(struct kasan_report_info *info)
177177
{
178178
if (info->type == KASAN_REPORT_INVALID_FREE) {
179-
pr_err("BUG: KASAN: double-free or invalid-free in %pS\n",
180-
(void *)info->ip);
179+
pr_err("BUG: KASAN: invalid-free in %pS\n", (void *)info->ip);
180+
return;
181+
}
182+
183+
if (info->type == KASAN_REPORT_DOUBLE_FREE) {
184+
pr_err("BUG: KASAN: double-free in %pS\n", (void *)info->ip);
181185
return;
182186
}
183187

@@ -433,7 +437,7 @@ static void print_report(struct kasan_report_info *info)
433437
}
434438
}
435439

436-
void kasan_report_invalid_free(void *ptr, unsigned long ip)
440+
void kasan_report_invalid_free(void *ptr, unsigned long ip, enum kasan_report_type type)
437441
{
438442
unsigned long flags;
439443
struct kasan_report_info info;
@@ -448,7 +452,7 @@ void kasan_report_invalid_free(void *ptr, unsigned long ip)
448452

449453
start_report(&flags, true);
450454

451-
info.type = KASAN_REPORT_INVALID_FREE;
455+
info.type = type;
452456
info.access_addr = ptr;
453457
info.first_bad_addr = kasan_reset_tag(ptr);
454458
info.access_size = 0;

0 commit comments

Comments
 (0)