From patchwork Fri Dec 2 04:22:25 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Ellerman X-Patchwork-Id: 9457779 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id EB7A260236 for ; Fri, 2 Dec 2016 04:22:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DB77B284DE for ; Fri, 2 Dec 2016 04:22:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CF77D284F3; Fri, 2 Dec 2016 04:22:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id E3460284DE for ; Fri, 2 Dec 2016 04:22:47 +0000 (UTC) Received: (qmail 1600 invoked by uid 550); 2 Dec 2016 04:22:45 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Reply-To: kernel-hardening@lists.openwall.com Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 1574 invoked from network); 2 Dec 2016 04:22:43 -0000 From: Michael Ellerman To: keescook@chromium.org Cc: kernel-hardening@lists.openwall.com, linux-kernel@vger.kernel.org Date: Fri, 2 Dec 2016 15:22:25 +1100 Message-Id: <1480652545-4457-1-git-send-email-mpe@ellerman.id.au> X-Mailer: git-send-email 2.7.4 Subject: [kernel-hardening] [PATCH v2] lkdtm: Add tests for LIST_POISON and ZERO_SIZE_PTR X-Virus-Scanned: ClamAV using ClamSMTP This adds two tests, to check that a read or write to LIST_POISON1 and ZERO_SIZE_PTR are blocked. The default values for both (256 and 16) typically fall in the range of valid user space addresses. However in general mmap_min_addr is 64K, which prevents user space from mapping anything at those addresses. However it's feasible that an attacker will be able to find a way to cause an access at an offset from either value, and if that offset is greater than 64K then they can access user space again. To simulate that case, in the test we create a user mapping at approximately mmap_min_addr, and offset the pointer by that amount. This gives the test the greatest chance of failing (ie. an access succeeding). We don't actually use mmap_min_addr, because that would require exporting it to modules, instead we use the default value at compile time as a reasonable approximation. Signed-off-by: Michael Ellerman Acked-by: Kees Cook --- drivers/misc/lkdtm.h | 2 ++ drivers/misc/lkdtm_bugs.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/lkdtm_core.c | 2 ++ 3 files changed, 52 insertions(+) v2: Fix 32-bit compile errors by using int not long. Avoid need to export mmap_min_addr by using CONFIG_DEFAULT_MMAP_MIN_ADDR. diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index fdf954c2107f..cc207f7824f9 100644 --- a/drivers/misc/lkdtm.h +++ b/drivers/misc/lkdtm.h @@ -21,6 +21,8 @@ void lkdtm_SPINLOCKUP(void); void lkdtm_HUNG_TASK(void); void lkdtm_ATOMIC_UNDERFLOW(void); void lkdtm_ATOMIC_OVERFLOW(void); +void lkdtm_ACCESS_LIST_POISON(void); +void lkdtm_ACCESS_ZERO_SIZE_PTR(void); /* lkdtm_heap.c */ void lkdtm_OVERWRITE_ALLOCATION(void); diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c index 30e62dd7e7ca..9ae079ac9a93 100644 --- a/drivers/misc/lkdtm_bugs.c +++ b/drivers/misc/lkdtm_bugs.c @@ -5,7 +5,10 @@ * test source files. */ #include "lkdtm.h" +#include #include +#include +#include /* * Make sure our attempts to over run the kernel stack doesn't trigger @@ -147,3 +150,48 @@ void lkdtm_ATOMIC_OVERFLOW(void) pr_info("attempting bad atomic overflow\n"); atomic_inc(&over); } + +static void test_poison_ptr(void *base, const char *desc) +{ + unsigned int *ptr, bias, val; + unsigned long uaddr; + + /* We'd rather not export mmap_min_addr, so use the default instead */ + bias = PAGE_ALIGN(CONFIG_DEFAULT_MMAP_MIN_ADDR); + + uaddr = vm_mmap(NULL, bias, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, 0); + if (uaddr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory, can't perform test.\n"); + return; + } + + /* + * Creating a mapping and adding mmap_min_addr to the value is cheating + * in a way. But it simulates the case where an attacker is able to + * cause an access at a small offset from the base value, leading to a + * user space access. If an arch doesn't define CONFIG_ILLEGAL_POINTER_VALUE + * then it's likely this will work in the absence of other protections. + */ + ptr = bias + base; + + pr_info("attempting read of %s %p\n", desc, ptr); + val = *ptr; + pr_info("FAIL: Was able to read %s! Got 0x%x\n", desc, val); + + pr_info("attempting write of %s %p\n", desc, ptr); + *ptr = 0xdeadbeefU; + pr_info("FAIL: Was able to write %s! Now = 0x%x\n", desc, *ptr); + + vm_munmap(uaddr, PAGE_SIZE); +} + +void lkdtm_ACCESS_LIST_POISON(void) +{ + test_poison_ptr(LIST_POISON1, "LIST_POISON"); +} + +void lkdtm_ACCESS_ZERO_SIZE_PTR(void) +{ + test_poison_ptr(ZERO_SIZE_PTR, "ZERO_SIZE_PTR"); +} diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index f9154b8d67f6..025a0ee8d8ee 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -220,6 +220,8 @@ struct crashtype crashtypes[] = { CRASHTYPE(WRITE_KERN), CRASHTYPE(ATOMIC_UNDERFLOW), CRASHTYPE(ATOMIC_OVERFLOW), + CRASHTYPE(ACCESS_LIST_POISON), + CRASHTYPE(ACCESS_ZERO_SIZE_PTR), CRASHTYPE(USERCOPY_HEAP_SIZE_TO), CRASHTYPE(USERCOPY_HEAP_SIZE_FROM), CRASHTYPE(USERCOPY_HEAP_FLAG_TO),