Received: by 2002:a25:824b:0:0:0:0:0 with SMTP id d11csp2917296ybn; Thu, 26 Sep 2019 20:46:57 -0700 (PDT) X-Google-Smtp-Source: APXvYqwrjYm/fYCM2YWd2Ux5ZYhP+MnlCWWvDzAUzTyrAZI6SqxLbAvTqD9dFBRfZwCAUtRJ4MNe X-Received: by 2002:a17:906:fd1:: with SMTP id c17mr6019087ejk.45.1569556017811; Thu, 26 Sep 2019 20:46:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1569556017; cv=none; d=google.com; s=arc-20160816; b=Aue4fDD9Tr2SNC2TN6etk5j8FLPH7OjTdVuEtBhoSyKcewGlR3fQBs39KevRQVt26N GWPbCM14LHsF2gBlmXyxGe+McsdKfBh7ncphUonL6zsp2ppbRe0gzC5s1pByrthbiUkh ZZzOe/YcYm5TWwfo1cLlyV5OAaF2YabjpL7aWjAWyMIzYG7iNxt3WmTZQtBIRiYSpJko Fv1E+ORWGW46t+wNY6a40gdU3zLOPUVrD9rcp/xEQ9wkCj3mFRnnFwvlAsEGCF9OkrKa nlmhzyLCRKsQ7RCrWTx8f1wS5vr+n7YdfZOSvy+tC94klIx8DALK1dxsQcoym1bO1o0O uN1g== 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=kTvqOGNkX1dajKcz0lk7XHXa8sAJ1Oe5fe/wKGsY1fI=; b=ZdRd1ILs+OSgQw4k45HHONTu+fUzIYCANfMCyDx5PY7LDYv+IEc6iJJSRe+5KFKLNS 62uJh3ZdKf78ea4i44wQ3Uqdfx5LMYvyfTEV/dOFt3Kyn0b+RoGfMF9vT6NWeFySey58 CM8qrPXr7R3OUXCpvcARC6vP7uSj7Av6Gu2vPl9GMQBNrnDbf36h7nixDU+XzR2ZsZtD x2pExyi94HPk50O5yYRwRjFOIgLfIXK6KSRAviYESYMvIUGPIlSDkea2mJCzCJTk3N1E CWWs5yY96FO97+Na/U2HaaopzlFy808Tcmep4sNfozR7nGTWX87sKC/A4L6m9x70+KHs odTQ== 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 dv21si2039335ejb.241.2019.09.26.20.46.17; Thu, 26 Sep 2019 20:46:57 -0700 (PDT) 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 S1728617AbfI0Dnu (ORCPT + 99 others); Thu, 26 Sep 2019 23:43:50 -0400 Received: from mailgw01.mediatek.com ([210.61.82.183]:6891 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726145AbfI0Dnu (ORCPT ); Thu, 26 Sep 2019 23:43:50 -0400 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 Content-Type: text/plain X-MTK: N Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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; -- 2.18.0