From patchwork Fri Sep 27 03:43:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Walter Wu X-Patchwork-Id: 11163703 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4D0E717D4 for ; Fri, 27 Sep 2019 03:43:51 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 15EAF20872 for ; Fri, 27 Sep 2019 03:43:51 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 15EAF20872 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 312458E002E; Thu, 26 Sep 2019 23:43:50 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 29BE08E002A; Thu, 26 Sep 2019 23:43:50 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 13C778E002E; Thu, 26 Sep 2019 23:43:50 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0149.hostedemail.com [216.40.44.149]) by kanga.kvack.org (Postfix) with ESMTP id DF7598E002A for ; Thu, 26 Sep 2019 23:43:49 -0400 (EDT) Received: from smtpin17.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay02.hostedemail.com (Postfix) with SMTP id 7E1A86D9A for ; Fri, 27 Sep 2019 03:43:49 +0000 (UTC) X-FDA: 75979306578.17.hate47_787e1b5b2b512 X-Spam-Summary: 2,0,0,1db26f33535bdbab,d41d8cd98f00b204,walter-zh.wu@mediatek.com,:aryabinin@virtuozzo.com:glider@google.com:dvyukov@google.com:matthias.bgg@gmail.com:linux-kernel@vger.kernel.org:kasan-dev@googlegroups.com::linux-arm-kernel@lists.infradead.org:linux-mediatek@lists.infradead.org:wsd_upstream@mediatek.com:walter-zh.wu@mediatek.com,RULES_HIT:41:355:379:541:800:960:966:967:973:988:989:1260:1277:1313:1314:1345:1437:1516:1518:1534:1543:1711:1730:1747:1777:1792:1978:1981:2194:2196:2198:2199:2200:2201:2393:2525:2559:2563:2682:2685:2693:2859:2933:2937:2939:2942:2945:2947:2951:2954:3022:3138:3139:3140:3141:3142:3353:3865:3866:3867:3868:3870:3871:3872:3934:3936:3938:3941:3944:3947:3950:3953:3956:3959:4250:4321:4385:5007:6119:6261:7903:8603:9025:10004:10400:11026:11658:11914:12043:12048:12114:12291:12296:12297:12438:12521:12555:12683:12698:12737:12895:12986:13161:13221:13229:13255:14096:14097:14181:14394:14721:21080:21451:21627:30003:30054:30070,0,RBL:210.61.82.183:@medi atek.com X-HE-Tag: hate47_787e1b5b2b512 X-Filterd-Recvd-Size: 4931 Received: from mailgw01.mediatek.com (unknown [210.61.82.183]) by imf32.hostedemail.com (Postfix) with ESMTP for ; Fri, 27 Sep 2019 03:43:47 +0000 (UTC) X-UUID: d4b5f999be8148baadc251c1b858fb6c-20190927 X-UUID: d4b5f999be8148baadc251c1b858fb6c-20190927 Received: from mtkcas08.mediatek.inc [(172.21.101.126)] by mailgw01.mediatek.com (envelope-from ) (Cellopoint E-mail Firewall v4.1.10 Build 0809 with TLS) with ESMTP id 1048956367; Fri, 27 Sep 2019 11:43:41 +0800 Received: from mtkcas07.mediatek.inc (172.21.101.84) by mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 27 Sep 2019 11:43:39 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas07.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Fri, 27 Sep 2019 11:43:39 +0800 From: Walter Wu To: Andrey Ryabinin , Alexander Potapenko , Dmitry Vyukov , Matthias Brugger CC: , , , , , , Walter Wu Subject: [PATCH] kasan: fix the missing underflow in memmove and memcpy with CONFIG_KASAN_GENERIC=y Date: Fri, 27 Sep 2019 11:43:38 +0800 Message-ID: <20190927034338.15813-1-walter-zh.wu@mediatek.com> X-Mailer: git-send-email 2.18.0 MIME-Version: 1.0 X-MTK: N X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: memmove() and memcpy() have missing underflow issues. When -7 <= size < 0, then KASAN will miss to catch the underflow issue. It looks like shadow start address and shadow end address is the same, so it does not actually check anything. The following test is indeed not caught by KASAN: char *p = kmalloc(64, GFP_KERNEL); memset((char *)p, 0, 64); memmove((char *)p, (char *)p + 4, -2); kfree((char*)p); It should be checked here: 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_); return __memmove(dest, src, len); } We fix the shadow end address which is calculated, then generic KASAN get the right shadow end address and detect this underflow issue. [1] https://bugzilla.kernel.org/show_bug.cgi?id=199341 Signed-off-by: Walter Wu Reported-by: Dmitry Vyukov --- lib/test_kasan.c | 36 ++++++++++++++++++++++++++++++++++++ mm/kasan/generic.c | 8 ++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index b63b367a94e8..8bd014852556 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -280,6 +280,40 @@ static noinline void __init kmalloc_oob_in_memset(void) kfree(ptr); } +static noinline void __init kmalloc_oob_in_memmove_underflow(void) +{ + char *ptr; + size_t size = 64; + + pr_info("underflow out-of-bounds in memmove\n"); + ptr = kmalloc(size, GFP_KERNEL); + if (!ptr) { + pr_err("Allocation failed\n"); + return; + } + + memset((char *)ptr, 0, 64); + memmove((char *)ptr, (char *)ptr + 4, -2); + kfree(ptr); +} + +static noinline void __init kmalloc_oob_in_memmove_overflow(void) +{ + char *ptr; + size_t size = 64; + + pr_info("overflow out-of-bounds in memmove\n"); + ptr = kmalloc(size, GFP_KERNEL); + if (!ptr) { + pr_err("Allocation failed\n"); + return; + } + + memset((char *)ptr, 0, 64); + memmove((char *)ptr + size, (char *)ptr, 2); + kfree(ptr); +} + static noinline void __init kmalloc_uaf(void) { char *ptr; @@ -734,6 +768,8 @@ static int __init kmalloc_tests_init(void) kmalloc_oob_memset_4(); kmalloc_oob_memset_8(); kmalloc_oob_memset_16(); + kmalloc_oob_in_memmove_underflow(); + kmalloc_oob_in_memmove_overflow(); kmalloc_uaf(); kmalloc_uaf_memset(); kmalloc_uaf2(); diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 616f9dd82d12..34ca23d59e67 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -131,9 +131,13 @@ static __always_inline bool memory_is_poisoned_n(unsigned long addr, size_t size) { unsigned long ret; + void *shadow_start = kasan_mem_to_shadow((void *)addr); + void *shadow_end = kasan_mem_to_shadow((void *)addr + size - 1) + 1; - ret = memory_is_nonzero(kasan_mem_to_shadow((void *)addr), - kasan_mem_to_shadow((void *)addr + size - 1) + 1); + if ((long)size < 0) + shadow_end = kasan_mem_to_shadow((void *)addr + size); + + ret = memory_is_nonzero(shadow_start, shadow_end); if (unlikely(ret)) { unsigned long last_byte = addr + size - 1;