mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
UPSTREAM: 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/20220615062219.22618-1-Kuan-Ying.Lee@mediatek.com
Signed-off-by: Kuan-Ying Lee <Kuan-Ying.Lee@mediatek.com>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
Reviewed-by: Andrey Konovalov <andreyknvl@gmail.com>
Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: Matthias Brugger <matthias.bgg@gmail.com>
Cc: Chinwen Chang <chinwen.chang@mediatek.com>
Cc: Yee Lee <yee.lee@mediatek.com>
Cc: Andrew Yang <andrew.yang@mediatek.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Bug: 254721825
(cherry picked from commit 3de0de7580)
Change-Id: Iab0938ac700f18a364fcb5518a3512dad18b6962
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
This commit is contained in:
committed by
Andrey Konovalov
parent
b5b25c2c41
commit
55273c6120
@@ -343,7 +343,7 @@ static inline bool ____kasan_slab_free(struct kmem_cache *cache, void *object,
|
||||
|
||||
if (unlikely(nearest_obj(cache, virt_to_head_page(object), object) !=
|
||||
object)) {
|
||||
kasan_report_invalid_free(tagged_object, ip);
|
||||
kasan_report_invalid_free(tagged_object, ip, KASAN_REPORT_INVALID_FREE);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ static inline bool ____kasan_slab_free(struct kmem_cache *cache, void *object,
|
||||
return false;
|
||||
|
||||
if (!kasan_byte_accessible(tagged_object)) {
|
||||
kasan_report_invalid_free(tagged_object, ip);
|
||||
kasan_report_invalid_free(tagged_object, ip, KASAN_REPORT_DOUBLE_FREE);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -377,12 +377,12 @@ bool __kasan_slab_free(struct kmem_cache *cache, void *object,
|
||||
static inline bool ____kasan_kfree_large(void *ptr, unsigned long ip)
|
||||
{
|
||||
if (ptr != page_address(virt_to_head_page(ptr))) {
|
||||
kasan_report_invalid_free(ptr, ip);
|
||||
kasan_report_invalid_free(ptr, ip, KASAN_REPORT_INVALID_FREE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!kasan_byte_accessible(ptr)) {
|
||||
kasan_report_invalid_free(ptr, ip);
|
||||
kasan_report_invalid_free(ptr, ip, KASAN_REPORT_DOUBLE_FREE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ static inline bool kasan_sync_fault_possible(void)
|
||||
enum kasan_report_type {
|
||||
KASAN_REPORT_ACCESS,
|
||||
KASAN_REPORT_INVALID_FREE,
|
||||
KASAN_REPORT_DOUBLE_FREE,
|
||||
};
|
||||
|
||||
struct kasan_report_info {
|
||||
@@ -275,7 +276,7 @@ static inline void kasan_print_address_stack_frame(const void *addr) { }
|
||||
|
||||
bool kasan_report(unsigned long addr, size_t size,
|
||||
bool is_write, unsigned long ip);
|
||||
void kasan_report_invalid_free(void *object, unsigned long ip);
|
||||
void kasan_report_invalid_free(void *object, unsigned long ip, enum kasan_report_type type);
|
||||
|
||||
struct page *kasan_addr_to_page(const void *addr);
|
||||
|
||||
|
||||
@@ -172,8 +172,12 @@ static void end_report(unsigned long *flags, void *addr)
|
||||
static void print_error_description(struct kasan_report_info *info)
|
||||
{
|
||||
if (info->type == KASAN_REPORT_INVALID_FREE) {
|
||||
pr_err("BUG: KASAN: double-free or invalid-free in %pS\n",
|
||||
(void *)info->ip);
|
||||
pr_err("BUG: KASAN: invalid-free in %pS\n", (void *)info->ip);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->type == KASAN_REPORT_DOUBLE_FREE) {
|
||||
pr_err("BUG: KASAN: double-free in %pS\n", (void *)info->ip);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -420,7 +424,7 @@ static void print_report(struct kasan_report_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
void kasan_report_invalid_free(void *ptr, unsigned long ip)
|
||||
void kasan_report_invalid_free(void *ptr, unsigned long ip, enum kasan_report_type type)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kasan_report_info info;
|
||||
@@ -435,7 +439,7 @@ void kasan_report_invalid_free(void *ptr, unsigned long ip)
|
||||
|
||||
start_report(&flags, true);
|
||||
|
||||
info.type = KASAN_REPORT_INVALID_FREE;
|
||||
info.type = type;
|
||||
info.access_addr = ptr;
|
||||
info.first_bad_addr = kasan_reset_tag(ptr);
|
||||
info.access_size = 0;
|
||||
|
||||
Reference in New Issue
Block a user