From patchwork Tue Jun 26 16:54:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 10489567 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 26D86602D8 for ; Tue, 26 Jun 2018 16:55:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 168F7283DA for ; Tue, 26 Jun 2018 16:55:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0ACB0285CE; Tue, 26 Jun 2018 16:55:32 +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=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 8F68A283DA for ; Tue, 26 Jun 2018 16:55:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=+gytf6veOuiG8D7lRysutkTGFDgrEKbie2E9MRhk6ho=; b=jGg Z30pimm6ldaYfnIqLC8wXAnge0EbA3Kc7KI1eW0zL/XO1NxdJ2Wp3O7n/cRGJuaP6/ncRyxMxMYIE pfVpUwjb09JiPJVrPLPnPb6YQgD8BAcV6FNfL/U9fviUTo0JRR8O9198ZdWxakwiOqYmh6UjTOSQT ueHOlKd2ZxnbGddOJy5YdqEodck5gCvMvmRcrDoKyLqtoXUGiCqRAz1Uq+Y7j/inWgZNjEFCCw93s MEy+OFo/jdX//ha+KOgjMHYjLkWO7zrJqrEsf49A+nPCevXZEpmVUUoGZlDKnQyYr/7QOr+Zerlhv bL9W90kHIwC8+MNUXvONatURHUTB3NQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fXrFU-00054a-MD; Tue, 26 Jun 2018 16:55:24 +0000 Received: from mail-wm0-x241.google.com ([2a00:1450:400c:c09::241]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fXrFQ-0004GE-H6 for linux-arm-kernel@lists.infradead.org; Tue, 26 Jun 2018 16:55:22 +0000 Received: by mail-wm0-x241.google.com with SMTP id u18-v6so2603969wmc.1 for ; Tue, 26 Jun 2018 09:55:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=eMm/N/nj5zh2Pbck+WVZyIY8xCkAhHcmlZ2hxsy9fGg=; b=Qi0h/iZD5kswxzx3hg1UrPisZ1+zL4YKy9ruX7bvDlrT6pHcpg5utFF99LK5VlJIS+ M4/RjkMpprBNJkshvPsqNiWDASfInNxADDTcjy9cHoJ7deUd9ryN1kkIH7s9CTnqJGF3 c99Da3DpfwAg7w75eISO+RnyJHjLq7xBu+d4s= 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; bh=eMm/N/nj5zh2Pbck+WVZyIY8xCkAhHcmlZ2hxsy9fGg=; b=KKok3zCc4U9Ie4VYWoy1DIT5xjl/ayBMO1M9CRX8PfN4/O4G/hRYa6qM2lpzcuBH77 1Q+3Ys0edRI/QAZry6EXm2yAxL3+IJtmii+JbxJevYMOiZCcjlMgVXtQWZoHVRQvwUcu QCaE+/QFGSITEp3yHI4NFj4pNXELpV9HbDCRDiIovFFTi1/JViNhyTcMr3nhPo8NVXqH utSahZ9cRSgZRkzId1nNA0ZIn5hDugrXWbS0CGJATFTP7Imqcob1clbqqavi/zN51N/S nDfq6BR/M9+zzk284cL0YLY7d+U+WKUtCx17SmLZ4BvHphO3Q4UVWwB9U27bnbJ+j3uF Htvw== X-Gm-Message-State: APt69E32LlZ5IYQRKRJkATjP+dR44Ic5+MwZJoWdE2vWUbGUQKmDnTV0 IPZjye5EsASb3PsuatH2LsSYsVYyiEY= X-Google-Smtp-Source: AAOMgpcMla+vrn/EoW3R99J8PFbrkuwDUvUrMKBZ0eH9fB7RmIq4ZbRndtPpxFyyZwwij1TKydnLrg== X-Received: by 2002:a1c:c3c6:: with SMTP id t189-v6mr2386964wmf.41.1530032108279; Tue, 26 Jun 2018 09:55:08 -0700 (PDT) Received: from rev02.home ([2a01:cb1d:112:6f00:d037:e907:f0a2:a5ea]) by smtp.gmail.com with ESMTPSA id h3-v6sm1492913wro.87.2018.06.26.09.55.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 26 Jun 2018 09:55:07 -0700 (PDT) From: Ard Biesheuvel To: linux-arm-kernel@lists.infradead.org Subject: [RFC PATCH] arm64/mm: unmap the linear alias of module allocations Date: Tue, 26 Jun 2018 18:54:55 +0200 Message-Id: <20180626165455.22636-1-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.11.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180626_095520_588766_CE894633 X-CRM114-Status: GOOD ( 18.97 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, keescook@chromium.org, kernel-hardening@lists.openwall.com, catalin.marinas@arm.com, Ard Biesheuvel , will.deacon@arm.com, yaojun8558363@gmail.com, james.morse@arm.com, labbott@fedoraproject.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP When CONFIG_STRICT_KERNEL_RXW=y [which is the default on arm64], we take great care to ensure that the mappings of modules in the vmalloc space are locked down as much as possible, i.e., executable code is mapped read-only, read-only data is mapped read-only and non-executable, and read-write data is mapped non-executable as well. However, due to the way we map the linear region [aka the kernel direct mapping], those module regions are aliased by read-write mappings, and it is possible for an attacker to modify code or data that was assumed to be immutable in this configuration. So let's ensure that the linear alias of module memory is unmapped upon allocation and remapped when it is freed. The latter requires some special handling involving a workqueue due to the fact that it may be called in softirq context at which time calling find_vm_area() is unsafe. Note that this requires the entire linear region to be mapped down to pages, which may result in a performance regression in some configurations. Signed-off-by: Ard Biesheuvel --- For this RFC, I simply reused set_memory_valid() to do the unmap/remap, but I am aware that this likely breaks hibernation, and perhaps some other things as well, so we should probably remap r/o instead. arch/arm64/kernel/module.c | 57 ++++++++++++++++++++ arch/arm64/mm/mmu.c | 2 +- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 155fd91e78f4..4a1d3c7486f5 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -26,10 +26,66 @@ #include #include #include +#include #include +#include #include #include +#ifdef CONFIG_STRICT_KERNEL_RWX + +static struct workqueue_struct *module_free_wq; + +static int init_workqueue(void) +{ + module_free_wq = alloc_ordered_workqueue("module_free_wq", 0); + WARN_ON(!module_free_wq); + + return 0; +} +pure_initcall(init_workqueue); + +static void remap_linear_module_alias(void *module_region, int enable) +{ + struct vm_struct *vm = find_vm_area(module_region); + struct page **p; + unsigned long size; + + WARN_ON(!vm || !vm->pages); + + for (p = vm->pages, size = vm->size; size > 0; size -= PAGE_SIZE) + set_memory_valid((u64)page_address(*p++), 1, enable); +} + +static void module_free_wq_worker(struct work_struct *work) +{ + remap_linear_module_alias(work, true); + vfree(work); +} + +void module_memfree(void *module_region) +{ + struct work_struct *work; + + if (!module_region) + return; + + /* + * At this point, module_region is a pointer to an allocation of at + * least PAGE_SIZE bytes that is mapped read-write. So instead of + * allocating memory for a data structure containing a work_struct + * instance and a copy of the value of module_region, just reuse the + * allocation directly. + */ + work = module_region; + INIT_WORK(work, module_free_wq_worker); + queue_work(module_free_wq, work); +} + +#else +static void remap_linear_module_alias(void *module_region, int enable) {} +#endif + void *module_alloc(unsigned long size) { gfp_t gfp_mask = GFP_KERNEL; @@ -65,6 +121,7 @@ void *module_alloc(unsigned long size) return NULL; } + remap_linear_module_alias(p, false); return p; } diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 493ff75670ff..e1057ebb672d 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -432,7 +432,7 @@ static void __init map_mem(pgd_t *pgdp) struct memblock_region *reg; int flags = 0; - if (debug_pagealloc_enabled()) + if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX) || debug_pagealloc_enabled()) flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; /*