Received: by 2002:a25:31c3:0:0:0:0:0 with SMTP id x186csp3404546ybx; Sun, 3 Nov 2019 18:12:05 -0800 (PST) X-Google-Smtp-Source: APXvYqxm7JdN0krSFoHiSNwvpSBlxGFRr8xJXPdwkO1BETRVd0HY0YMFa8HDOWYmTrI4zyBD1Wtf X-Received: by 2002:a50:950a:: with SMTP id u10mr27225406eda.68.1572833525833; Sun, 03 Nov 2019 18:12:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1572833525; cv=none; d=google.com; s=arc-20160816; b=xlsBMcW18QGlP4KoamccRMvfB0NRnAQR295+pJOCIwR1Yi1P9A9FEZJ8rCzSHf6fXh YOVgrHnTQyz+iVqgCiOVBm5TESIhtCnJzAM4nnwf7qhuQY38Np/u7Vbs859kBIX+JIhG wkBlWpzv3BYWw33b3yVJXDs1QWojbnNUg4x0EsqLvMukoaZWM1gC62fPgtExO4MIj1ii hW0cb8QKOHQwIQUTOk2CSzwM2+Fmh4+fi4Wz84WuqTs2tKN+eaT1ffQed88I54HXLGOM n3ekdbp4gwQS9oXT7HvF6MARs44whVYWwUrfmt53PtosxgK2rVcrD5+JrbzQygNlsqFs piRA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:message-id:date:subject:cc :to:from; bh=r0mMRPMhbjJLPm/S3b+Jeo0txFeZF/3R5gTEshdBWSA=; b=CFx07T0hqRaileIQqmq9OQy+PeQbDOHIJYeLdKYvNd+59Vt42zIX6ZhO5DwtD4L6QH SNOAIzQ+RzfiQqEam9c/gIhVckm4CHxi3vYwU0biilsg7vFNXvM1fzbZ/nzihYNytwxS WxubQRYPENRROeJemOgmXBwEB7Q7OnEzxEuGQXLexvHYYUavEFgWKD1ejk3CQpS/n3eI V0pIkwauRNncNVqI5ue+faZ3jmi3fLfE7BN1xFqdAOKN0GuZzXM7DZmCAByma0YMPaG1 Qt9SVGoclgZJnywFigzPsqYkWE/O25o4SNsfU2mvWgE9Gcy26jk/ZbOpE5ZVy0BBujbZ T97A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=mediatek.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w29si808713edd.270.2019.11.03.18.11.41; Sun, 03 Nov 2019 18:12:05 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=mediatek.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728437AbfKDCFc (ORCPT + 99 others); Sun, 3 Nov 2019 21:05:32 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:29767 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728234AbfKDCFb (ORCPT ); Sun, 3 Nov 2019 21:05:31 -0500 X-UUID: 235d6a98566b40138f5536bb1366f053-20191104 X-UUID: 235d6a98566b40138f5536bb1366f053-20191104 Received: from mtkexhb02.mediatek.inc [(172.21.101.103)] by mailgw02.mediatek.com (envelope-from ) (Cellopoint E-mail Firewall v4.1.10 Build 0809 with TLS) with ESMTP id 357250501; Mon, 04 Nov 2019 10:05:24 +0800 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n2.mediatek.inc (172.21.101.56) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 4 Nov 2019 10:05:20 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Mon, 4 Nov 2019 10:05:20 +0800 From: Walter Wu To: Andrey Ryabinin , Alexander Potapenko , Dmitry Vyukov , Matthias Brugger CC: , , , , wsd_upstream , Walter Wu Subject: [PATCH v3 1/2] kasan: detect negative size in memory operation function Date: Mon, 4 Nov 2019 10:05:19 +0800 Message-ID: <20191104020519.27988-1-walter-zh.wu@mediatek.com> X-Mailer: git-send-email 2.18.0 MIME-Version: 1.0 Content-Type: text/plain X-TM-SNTS-SMTP: 1D3F81C588A033BF399029246331A216836E7AD6682CE88A56765C49DA8899102000:8 X-MTK: N Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org KASAN missed detecting size is negative numbers in memset(), memcpy(), and memmove(), it will cause out-of-bounds bug and need to be detected by KASAN. If size is negative numbers, then it has three reasons to be defined as heap-out-of-bounds bug type. 1) 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. 2) If KASAN has new bug type and user-space passes negative size, then there are duplicate reports. So don't produce new bug type in order to prevent duplicate reports by some systems (e.g. syzbot) to report the same bug twice. 3) When size is negative numbers, it may be passed from user-space. So we always print heap-out-of-bounds in order to prevent that kernel-space and user-space have the same bug but have duplicate reports. KASAN report: BUG: KASAN: heap-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 Signed-off-by: Walter Wu Reported-by: Dmitry Vyukov Suggested-by: Dmitry Vyukov Reviewed-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Alexander Potapenko Reported-by: kernel test robot --- mm/kasan/common.c | 18 +++++++++++++----- mm/kasan/generic.c | 5 +++++ mm/kasan/generic_report.c | 18 ++++++++++++++++++ mm/kasan/report.c | 2 +- mm/kasan/tags.c | 5 +++++ mm/kasan/tags_report.c | 18 ++++++++++++++++++ 6 files changed, 60 insertions(+), 6 deletions(-) diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 6814d6d6a023..4ff67e2fd2db 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -99,10 +99,14 @@ bool __kasan_check_write(const volatile void *p, unsigned int size) } EXPORT_SYMBOL(__kasan_check_write); +extern bool report_enabled(void); + #undef memset void *memset(void *addr, int c, size_t len) { - check_memory_region((unsigned long)addr, len, true, _RET_IP_); + if (report_enabled() && + !check_memory_region((unsigned long)addr, len, true, _RET_IP_)) + return NULL; return __memset(addr, c, len); } @@ -110,8 +114,10 @@ void *memset(void *addr, int c, size_t len) #undef memmove void *memmove(void *dest, const void *src, size_t len) { - check_memory_region((unsigned long)src, len, false, _RET_IP_); - check_memory_region((unsigned long)dest, len, true, _RET_IP_); + if (report_enabled() && + (!check_memory_region((unsigned long)src, len, false, _RET_IP_) || + !check_memory_region((unsigned long)dest, len, true, _RET_IP_))) + return NULL; return __memmove(dest, src, len); } @@ -119,8 +125,10 @@ void *memmove(void *dest, const void *src, size_t len) #undef memcpy void *memcpy(void *dest, const void *src, size_t len) { - check_memory_region((unsigned long)src, len, false, _RET_IP_); - check_memory_region((unsigned long)dest, len, true, _RET_IP_); + if (report_enabled() && + (!check_memory_region((unsigned long)src, len, false, _RET_IP_) || + !check_memory_region((unsigned long)dest, len, true, _RET_IP_))) + return NULL; return __memcpy(dest, src, len); } diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 616f9dd82d12..02148a317d27 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -173,6 +173,11 @@ static __always_inline bool check_memory_region_inline(unsigned long addr, if (unlikely(size == 0)) return true; + if (unlikely((long)size < 0)) { + kasan_report(addr, size, write, ret_ip); + return false; + } + if (unlikely((void *)addr < kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) { kasan_report(addr, size, write, ret_ip); diff --git a/mm/kasan/generic_report.c b/mm/kasan/generic_report.c index 36c645939bc9..52a92c7db697 100644 --- a/mm/kasan/generic_report.c +++ b/mm/kasan/generic_report.c @@ -107,6 +107,24 @@ static const char *get_wild_bug_type(struct kasan_access_info *info) const char *get_bug_type(struct kasan_access_info *info) { + /* + * If access_size is negative numbers, then it has three reasons + * to be defined as heap-out-of-bounds bug type. + * 1) 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. + * 2) If KASAN has new bug type and user-space passes negative size, + * then there are duplicate reports. So don't produce new bug type + * in order to prevent duplicate reports by some systems + * (e.g. syzbot) to report the same bug twice. + * 3) When size is negative numbers, it may be passed from user-space. + * So we always print heap-out-of-bounds in order to prevent that + * kernel-space and user-space have the same bug but have duplicate + * reports. + */ + if ((long)info->access_size < 0) + return "heap-out-of-bounds"; + if (addr_has_shadow(info->access_addr)) return get_shadow_bug_type(info); return get_wild_bug_type(info); diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 621782100eaa..c79e28814e8f 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -446,7 +446,7 @@ static void print_shadow_for_address(const void *addr) } } -static bool report_enabled(void) +bool report_enabled(void) { if (current->kasan_depth) return false; diff --git a/mm/kasan/tags.c b/mm/kasan/tags.c index 0e987c9ca052..b829535a3ad7 100644 --- a/mm/kasan/tags.c +++ b/mm/kasan/tags.c @@ -86,6 +86,11 @@ bool check_memory_region(unsigned long addr, size_t size, bool write, if (unlikely(size == 0)) return true; + if (unlikely((long)size < 0)) { + kasan_report(addr, size, write, ret_ip); + return false; + } + tag = get_tag((const void *)addr); /* diff --git a/mm/kasan/tags_report.c b/mm/kasan/tags_report.c index 969ae08f59d7..f7ae474aef3a 100644 --- a/mm/kasan/tags_report.c +++ b/mm/kasan/tags_report.c @@ -36,6 +36,24 @@ const char *get_bug_type(struct kasan_access_info *info) { + /* + * If access_size is negative numbers, then it has three reasons + * to be defined as heap-out-of-bounds bug type. + * 1) 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. + * 2) If KASAN has new bug type and user-space passes negative size, + * then there are duplicate reports. So don't produce new bug type + * in order to prevent duplicate reports by some systems + * (e.g. syzbot) to report the same bug twice. + * 3) When size is negative numbers, it may be passed from user-space. + * So we always print heap-out-of-bounds in order to prevent that + * kernel-space and user-space have the same bug but have duplicate + * reports. + */ + if ((long)info->access_size < 0) + return "heap-out-of-bounds"; + #ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY struct kasan_alloc_meta *alloc_meta; struct kmem_cache *cache; -- 2.18.0