mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-15 15:15:47 +00:00
8f17febb34
Make KASAN scan metadata to infer the requested allocation size instead of printing cache->object_size. This patch fixes confusing slab-out-of-bounds reports as reported in: https://bugzilla.kernel.org/show_bug.cgi?id=216457 As an example of the confusing behavior, the report below hints that the allocation size was 192, while the kernel actually called kmalloc(184): ================================================================== BUG: KASAN: slab-out-of-bounds in _find_next_bit+0x143/0x160 lib/find_bit.c:109 Read of size 8 at addr ffff8880175766b8 by task kworker/1:1/26 ... The buggy address belongs to the object at ffff888017576600 which belongs to the cache kmalloc-192 of size 192 The buggy address is located 184 bytes inside of 192-byte region [ffff888017576600, ffff8880175766c0) ... Memory state around the buggy address: ffff888017576580: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffff888017576600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ffff888017576680: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc ^ ffff888017576700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff888017576780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ================================================================== With this patch, the report shows: ================================================================== ... The buggy address belongs to the object at ffff888017576600 which belongs to the cache kmalloc-192 of size 192 The buggy address is located 0 bytes to the right of allocated 184-byte region [ffff888017576600, ffff8880175766b8) ... ================================================================== Also report slab use-after-free bugs as "slab-use-after-free" and print "freed" instead of "allocated" in the report when describing the accessed memory region. Also improve the metadata-related comment in kasan_find_first_bad_addr and use addr_has_metadata across KASAN code instead of open-coding KASAN_SHADOW_START checks. [akpm@linux-foundation.org: fix printk warning] Link: https://bugzilla.kernel.org/show_bug.cgi?id=216457 Link: https://lkml.kernel.org/r/20230129021437.18812-1-Kuan-Ying.Lee@mediatek.com Signed-off-by: Kuan-Ying Lee <Kuan-Ying.Lee@mediatek.com> Co-developed-by: Andrey Konovalov <andreyknvl@gmail.com> Cc: Alexander Potapenko <glider@google.com> Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com> Cc: Chinwen Chang <chinwen.chang@mediatek.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Matthias Brugger <matthias.bgg@gmail.com> Cc: Qun-Wei Lin <qun-wei.lin@mediatek.com> Cc: Vincenzo Frascino <vincenzo.frascino@arm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
116 lines
2.9 KiB
C
116 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
|
* Copyright (c) 2020 Google, Inc.
|
|
*/
|
|
|
|
#include <linux/atomic.h>
|
|
|
|
#include "kasan.h"
|
|
|
|
extern struct kasan_stack_ring stack_ring;
|
|
|
|
static const char *get_common_bug_type(struct kasan_report_info *info)
|
|
{
|
|
/*
|
|
* If access_size is a negative number, then it has reason to be
|
|
* defined as out-of-bounds bug type.
|
|
*
|
|
* Casting negative numbers to size_t would indeed turn up as
|
|
* a large size_t and its value will be larger than ULONG_MAX/2,
|
|
* so that this can qualify as out-of-bounds.
|
|
*/
|
|
if (info->access_addr + info->access_size < info->access_addr)
|
|
return "out-of-bounds";
|
|
|
|
return "invalid-access";
|
|
}
|
|
|
|
void kasan_complete_mode_report_info(struct kasan_report_info *info)
|
|
{
|
|
unsigned long flags;
|
|
u64 pos;
|
|
struct kasan_stack_ring_entry *entry;
|
|
void *ptr;
|
|
u32 pid;
|
|
depot_stack_handle_t stack;
|
|
bool is_free;
|
|
bool alloc_found = false, free_found = false;
|
|
|
|
if ((!info->cache || !info->object) && !info->bug_type) {
|
|
info->bug_type = get_common_bug_type(info);
|
|
return;
|
|
}
|
|
|
|
write_lock_irqsave(&stack_ring.lock, flags);
|
|
|
|
pos = atomic64_read(&stack_ring.pos);
|
|
|
|
/*
|
|
* The loop below tries to find stack ring entries relevant to the
|
|
* buggy object. This is a best-effort process.
|
|
*
|
|
* First, another object with the same tag can be allocated in place of
|
|
* the buggy object. Also, since the number of entries is limited, the
|
|
* entries relevant to the buggy object can be overwritten.
|
|
*/
|
|
|
|
for (u64 i = pos - 1; i != pos - 1 - stack_ring.size; i--) {
|
|
if (alloc_found && free_found)
|
|
break;
|
|
|
|
entry = &stack_ring.entries[i % stack_ring.size];
|
|
|
|
/* Paired with smp_store_release() in save_stack_info(). */
|
|
ptr = (void *)smp_load_acquire(&entry->ptr);
|
|
|
|
if (kasan_reset_tag(ptr) != info->object ||
|
|
get_tag(ptr) != get_tag(info->access_addr))
|
|
continue;
|
|
|
|
pid = READ_ONCE(entry->pid);
|
|
stack = READ_ONCE(entry->stack);
|
|
is_free = READ_ONCE(entry->is_free);
|
|
|
|
if (is_free) {
|
|
/*
|
|
* Second free of the same object.
|
|
* Give up on trying to find the alloc entry.
|
|
*/
|
|
if (free_found)
|
|
break;
|
|
|
|
info->free_track.pid = pid;
|
|
info->free_track.stack = stack;
|
|
free_found = true;
|
|
|
|
/*
|
|
* If a free entry is found first, the bug is likely
|
|
* a use-after-free.
|
|
*/
|
|
if (!info->bug_type)
|
|
info->bug_type = "slab-use-after-free";
|
|
} else {
|
|
/* Second alloc of the same object. Give up. */
|
|
if (alloc_found)
|
|
break;
|
|
|
|
info->alloc_track.pid = pid;
|
|
info->alloc_track.stack = stack;
|
|
alloc_found = true;
|
|
|
|
/*
|
|
* If an alloc entry is found first, the bug is likely
|
|
* an out-of-bounds.
|
|
*/
|
|
if (!info->bug_type)
|
|
info->bug_type = "slab-out-of-bounds";
|
|
}
|
|
}
|
|
|
|
write_unlock_irqrestore(&stack_ring.lock, flags);
|
|
|
|
/* Assign the common bug type if no entries were found. */
|
|
if (!info->bug_type)
|
|
info->bug_type = get_common_bug_type(info);
|
|
}
|