mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-14 06:35:12 +00:00
8cceeff48f
Patch series "fix the missing underflow in memory operation function", v4. The patchset helps to produce a KASAN report when size is negative in memory operation functions. It is helpful for programmer to solve an undefined behavior issue. Patch 1 based on Dmitry's review and suggestion, patch 2 is a test in order to verify the patch 1. [1]https://bugzilla.kernel.org/show_bug.cgi?id=199341 [2]https://lore.kernel.org/linux-arm-kernel/20190927034338.15813-1-walter-zh.wu@mediatek.com/ This patch (of 2): KASAN missed detecting size is a negative number in memset(), memcpy(), and memmove(), it will cause out-of-bounds bug. So needs to be detected by KASAN. If size is a negative number, then it has a 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. KASAN report is shown below: BUG: KASAN: out-of-bounds in kmalloc_memmove_invalid_size+0x70/0xa0 Read of size 18446744073709551608 at addr ffffff8069660904 by task cat/72 CPU: 2 PID: 72 Comm: cat Not tainted 5.4.0-rc1-next-20191004ajb-00001-gdb8af2f372b2-dirty #1 Hardware name: linux,dummy-virt (DT) Call trace: dump_backtrace+0x0/0x288 show_stack+0x14/0x20 dump_stack+0x10c/0x164 print_address_description.isra.9+0x68/0x378 __kasan_report+0x164/0x1a0 kasan_report+0xc/0x18 check_memory_region+0x174/0x1d0 memmove+0x34/0x88 kmalloc_memmove_invalid_size+0x70/0xa0 [1] https://bugzilla.kernel.org/show_bug.cgi?id=199341 [cai@lca.pw: fix -Wdeclaration-after-statement warn] Link: http://lkml.kernel.org/r/1583509030-27939-1-git-send-email-cai@lca.pw [peterz@infradead.org: fix objtool warning] Link: http://lkml.kernel.org/r/20200305095436.GV2596@hirez.programming.kicks-ass.net Reported-by: kernel test robot <lkp@intel.com> Reported-by: Dmitry Vyukov <dvyukov@google.com> Suggested-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Walter Wu <walter-zh.wu@mediatek.com> Signed-off-by: Qian Cai <cai@lca.pw> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Reviewed-by: Dmitry Vyukov <dvyukov@google.com> Reviewed-by: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Alexander Potapenko <glider@google.com> Link: http://lkml.kernel.org/r/20191112065302.7015-1-walter-zh.wu@mediatek.com Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
93 lines
2.4 KiB
C
93 lines
2.4 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* This file contains tag-based KASAN specific error reporting code.
|
|
*
|
|
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
|
* Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
|
|
*
|
|
* Some code borrowed from https://github.com/xairy/kasan-prototype by
|
|
* Andrey Konovalov <andreyknvl@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
*/
|
|
|
|
#include <linux/bitops.h>
|
|
#include <linux/ftrace.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/printk.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/stackdepot.h>
|
|
#include <linux/stacktrace.h>
|
|
#include <linux/string.h>
|
|
#include <linux/types.h>
|
|
#include <linux/kasan.h>
|
|
#include <linux/module.h>
|
|
|
|
#include <asm/sections.h>
|
|
|
|
#include "kasan.h"
|
|
#include "../slab.h"
|
|
|
|
const char *get_bug_type(struct kasan_access_info *info)
|
|
{
|
|
#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY
|
|
struct kasan_alloc_meta *alloc_meta;
|
|
struct kmem_cache *cache;
|
|
struct page *page;
|
|
const void *addr;
|
|
void *object;
|
|
u8 tag;
|
|
int i;
|
|
|
|
tag = get_tag(info->access_addr);
|
|
addr = reset_tag(info->access_addr);
|
|
page = kasan_addr_to_page(addr);
|
|
if (page && PageSlab(page)) {
|
|
cache = page->slab_cache;
|
|
object = nearest_obj(cache, page, (void *)addr);
|
|
alloc_meta = get_alloc_info(cache, object);
|
|
|
|
for (i = 0; i < KASAN_NR_FREE_STACKS; i++)
|
|
if (alloc_meta->free_pointer_tag[i] == tag)
|
|
return "use-after-free";
|
|
return "out-of-bounds";
|
|
}
|
|
|
|
#endif
|
|
/*
|
|
* 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 *find_first_bad_addr(void *addr, size_t size)
|
|
{
|
|
u8 tag = get_tag(addr);
|
|
void *p = reset_tag(addr);
|
|
void *end = p + size;
|
|
|
|
while (p < end && tag == *(u8 *)kasan_mem_to_shadow(p))
|
|
p += KASAN_SHADOW_SCALE_SIZE;
|
|
return p;
|
|
}
|
|
|
|
void print_tags(u8 addr_tag, const void *addr)
|
|
{
|
|
u8 *shadow = (u8 *)kasan_mem_to_shadow(addr);
|
|
|
|
pr_err("Pointer tag: [%02x], memory tag: [%02x]\n", addr_tag, *shadow);
|
|
}
|