From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6C4B3C47420 for ; Tue, 29 Sep 2020 18:36:05 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id C804B21548 for ; Tue, 29 Sep 2020 18:36:04 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C804B21548 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=linux.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 596E16B0070; Tue, 29 Sep 2020 14:36:04 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 56DCB6B0071; Tue, 29 Sep 2020 14:36:04 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 4841C6B0072; Tue, 29 Sep 2020 14:36:04 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0095.hostedemail.com [216.40.44.95]) by kanga.kvack.org (Postfix) with ESMTP id 339A36B0070 for ; Tue, 29 Sep 2020 14:36:04 -0400 (EDT) Received: from smtpin29.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with ESMTP id E3D50180AD801 for ; Tue, 29 Sep 2020 18:36:03 +0000 (UTC) X-FDA: 77316953406.29.walk68_2b090952718c Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin29.hostedemail.com (Postfix) with ESMTP id 05A7B1808BDB7 for ; Tue, 29 Sep 2020 18:36:02 +0000 (UTC) X-HE-Tag: walk68_2b090952718c X-Filterd-Recvd-Size: 9728 Received: from mail-wm1-f67.google.com (mail-wm1-f67.google.com [209.85.128.67]) by imf24.hostedemail.com (Postfix) with ESMTP for ; Tue, 29 Sep 2020 18:36:02 +0000 (UTC) Received: by mail-wm1-f67.google.com with SMTP id x23so5638459wmi.3 for ; Tue, 29 Sep 2020 11:36:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1AriX1I1xNfjnxfNSmAKzK7wEz9F3HLx249hrusGBIU=; b=BGDNHVWZcbG6pphKP3mQJ8JWERVnvFj/GCs5hWEFK65jIkT4JRzEDrraap3pq5aDTR iQBD724p687Gj4l47omG3aHYZ4MsPkw5WFP5v2wVvlIrEy/cZOIz23qcVjym7gtYwfdN XVH1PWeouHChzLsX4PKtZkneOxULk8n2/HgeEddBmhOOQ8T8tk/GxzS/UHmS6nHUo5eg tGs0Eyay6vKOEgYTfdULi4xtnZ2Dclxq5jlJ6Wq9euBgFHLpS54V2gogSf/P2HXYXldL 80ygfEh5tupfjHbBGvhpg1LIXLbrkToWMcWwdQDiz7gK22XLVFRkni+wLEXdejIly/eC qhlw== X-Gm-Message-State: AOAM533HQlUu7jK1Hx5T8VN62cuuImqNgyPzG+hIIpIED5bWRTLbM44t 84c8YtZ/uF7m+hxnEEOpmDs= X-Google-Smtp-Source: ABdhPJw8R3kY6IgJeu8H0uvfxSq+fvJCLPzv970QVYzDqIIZL9GZMM3MlhWS8bLeqHe+hKlVyU728w== X-Received: by 2002:a1c:6a08:: with SMTP id f8mr6140532wmc.151.1601404561398; Tue, 29 Sep 2020 11:36:01 -0700 (PDT) Received: from localhost.localdomain ([185.248.161.177]) by smtp.gmail.com with ESMTPSA id b188sm12151271wmb.2.2020.09.29.11.35.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2020 11:36:00 -0700 (PDT) From: Alexander Popov To: Kees Cook , Jann Horn , Will Deacon , Andrey Ryabinin , Alexander Potapenko , Dmitry Vyukov , Christoph Lameter , Pekka Enberg , David Rientjes , Joonsoo Kim , Andrew Morton , Masahiro Yamada , Masami Hiramatsu , Steven Rostedt , Peter Zijlstra , Krzysztof Kozlowski , Patrick Bellasi , David Howells , Eric Biederman , Johannes Weiner , Laura Abbott , Arnd Bergmann , Greg Kroah-Hartman , Daniel Micay , Andrey Konovalov , Matthew Wilcox , Pavel Machek , Valentin Schneider , kasan-dev@googlegroups.com, linux-mm@kvack.org, kernel-hardening@lists.openwall.com, linux-kernel@vger.kernel.org, Alexander Popov Cc: notify@kernel.org Subject: [PATCH RFC v2 5/6] lkdtm: Add heap quarantine tests Date: Tue, 29 Sep 2020 21:35:12 +0300 Message-Id: <20200929183513.380760-6-alex.popov@linux.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200929183513.380760-1-alex.popov@linux.com> References: <20200929183513.380760-1-alex.popov@linux.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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: Add tests for CONFIG_SLAB_QUARANTINE. The HEAP_SPRAY test aims to reallocate a recently freed heap object. It allocates and frees an object from a separate kmem_cache and then allocates 400000 similar objects from it. I.e. this test performs an original heap spraying technique for use-after-free exploitation. If CONFIG_SLAB_QUARANTINE is disabled, the freed object is instantly reallocated and overwritten, which is required for a successful attack. The PUSH_THROUGH_QUARANTINE test allocates and frees an object from a separate kmem_cache and then performs kmem_cache_alloc()+kmem_cache_free(= ) 400000 times. This test pushes the object through the heap quarantine and reallocates it after it returns back to the allocator freelist. If CONFIG_SLAB_QUARANTINE is enabled, this test should show that the randomized quarantine will release the freed object at an unpredictable moment, which makes use-after-free exploitation much harder. Signed-off-by: Alexander Popov --- drivers/misc/lkdtm/core.c | 2 + drivers/misc/lkdtm/heap.c | 110 +++++++++++++++++++++++++++++++++++++ drivers/misc/lkdtm/lkdtm.h | 2 + 3 files changed, 114 insertions(+) diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index a5e344df9166..6be5ca49ae6b 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -126,6 +126,8 @@ static const struct crashtype crashtypes[] =3D { CRASHTYPE(SLAB_FREE_DOUBLE), CRASHTYPE(SLAB_FREE_CROSS), CRASHTYPE(SLAB_FREE_PAGE), + CRASHTYPE(HEAP_SPRAY), + CRASHTYPE(PUSH_THROUGH_QUARANTINE), CRASHTYPE(SOFTLOCKUP), CRASHTYPE(HARDLOCKUP), CRASHTYPE(SPINLOCKUP), diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c index 1323bc16f113..f666a08d9462 100644 --- a/drivers/misc/lkdtm/heap.c +++ b/drivers/misc/lkdtm/heap.c @@ -10,6 +10,7 @@ static struct kmem_cache *double_free_cache; static struct kmem_cache *a_cache; static struct kmem_cache *b_cache; +static struct kmem_cache *spray_cache; =20 /* * This tries to stay within the next largest power-of-2 kmalloc cache @@ -204,6 +205,112 @@ static void ctor_a(void *region) { } static void ctor_b(void *region) { } +static void ctor_spray(void *region) +{ } + +#define SPRAY_LENGTH 400000 +#define SPRAY_ITEM_SIZE 333 + +void lkdtm_HEAP_SPRAY(void) +{ + int *addr; + int **spray_addrs =3D NULL; + unsigned long i =3D 0; + + addr =3D kmem_cache_alloc(spray_cache, GFP_KERNEL); + if (!addr) { + pr_info("Can't allocate memory in spray_cache cache\n"); + return; + } + + memset(addr, 0xA5, SPRAY_ITEM_SIZE); + kmem_cache_free(spray_cache, addr); + pr_info("Allocated and freed spray_cache object %p of size %d\n", + addr, SPRAY_ITEM_SIZE); + + spray_addrs =3D kcalloc(SPRAY_LENGTH, sizeof(int *), GFP_KERNEL); + if (!spray_addrs) { + pr_info("Unable to allocate memory for spray_addrs\n"); + return; + } + + pr_info("Original heap spraying: allocate %d objects of size %d...\n", + SPRAY_LENGTH, SPRAY_ITEM_SIZE); + for (i =3D 0; i < SPRAY_LENGTH; i++) { + spray_addrs[i] =3D kmem_cache_alloc(spray_cache, GFP_KERNEL); + if (!spray_addrs[i]) { + pr_info("Can't allocate memory in spray_cache cache\n"); + break; + } + + memset(spray_addrs[i], 0x42, SPRAY_ITEM_SIZE); + + if (spray_addrs[i] =3D=3D addr) { + pr_info("FAIL: attempt %lu: freed object is reallocated\n", i); + break; + } + } + + if (i =3D=3D SPRAY_LENGTH) + pr_info("OK: original heap spraying hasn't succeed\n"); + + for (i =3D 0; i < SPRAY_LENGTH; i++) { + if (spray_addrs[i]) + kmem_cache_free(spray_cache, spray_addrs[i]); + } + + kfree(spray_addrs); +} + +/* + * Pushing an object through the quarantine requires both allocating and + * freeing memory. Objects are released from the quarantine on new memor= y + * allocations, but only when the quarantine size is over the limit. + * And the quarantine size grows on new memory freeing. + * + * This test should show that the randomized quarantine will release the + * freed object at an unpredictable moment. + */ +void lkdtm_PUSH_THROUGH_QUARANTINE(void) +{ + int *addr; + int *push_addr; + unsigned long i; + + addr =3D kmem_cache_alloc(spray_cache, GFP_KERNEL); + if (!addr) { + pr_info("Can't allocate memory in spray_cache cache\n"); + return; + } + + memset(addr, 0xA5, SPRAY_ITEM_SIZE); + kmem_cache_free(spray_cache, addr); + pr_info("Allocated and freed spray_cache object %p of size %d\n", + addr, SPRAY_ITEM_SIZE); + + pr_info("Push through quarantine: allocate and free %d objects of size = %d...\n", + SPRAY_LENGTH, SPRAY_ITEM_SIZE); + for (i =3D 0; i < SPRAY_LENGTH; i++) { + push_addr =3D kmem_cache_alloc(spray_cache, GFP_KERNEL); + if (!push_addr) { + pr_info("Can't allocate memory in spray_cache cache\n"); + break; + } + + memset(push_addr, 0x42, SPRAY_ITEM_SIZE); + kmem_cache_free(spray_cache, push_addr); + + if (push_addr =3D=3D addr) { + pr_info("Target object is reallocated at attempt %lu\n", i); + break; + } + } + + if (i =3D=3D SPRAY_LENGTH) { + pr_info("Target object is NOT reallocated in %d attempts\n", + SPRAY_LENGTH); + } +} =20 void __init lkdtm_heap_init(void) { @@ -211,6 +318,8 @@ void __init lkdtm_heap_init(void) 64, 0, 0, ctor_double_free); a_cache =3D kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a); b_cache =3D kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b); + spray_cache =3D kmem_cache_create("lkdtm-heap-spray", + SPRAY_ITEM_SIZE, 0, 0, ctor_spray); } =20 void __exit lkdtm_heap_exit(void) @@ -218,4 +327,5 @@ void __exit lkdtm_heap_exit(void) kmem_cache_destroy(double_free_cache); kmem_cache_destroy(a_cache); kmem_cache_destroy(b_cache); + kmem_cache_destroy(spray_cache); } diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index 8878538b2c13..d6b4b0708359 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -45,6 +45,8 @@ void lkdtm_READ_BUDDY_AFTER_FREE(void); void lkdtm_SLAB_FREE_DOUBLE(void); void lkdtm_SLAB_FREE_CROSS(void); void lkdtm_SLAB_FREE_PAGE(void); +void lkdtm_HEAP_SPRAY(void); +void lkdtm_PUSH_THROUGH_QUARANTINE(void); =20 /* lkdtm_perms.c */ void __init lkdtm_perms_init(void); --=20 2.26.2