From patchwork Wed Mar 15 09:59:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 9625145 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 088FF60244 for ; Wed, 15 Mar 2017 09:58:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E380928304 for ; Wed, 15 Mar 2017 09:58:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D6E35283BA; Wed, 15 Mar 2017 09:58:45 +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=-1.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.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 2E32E28304 for ; Wed, 15 Mar 2017 09:58:45 +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:References: In-Reply-To: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:List-Owner; bh=2ywaB6M8ETPZL1lnZ/VTvohpBlyEcpzo4FUVWwbTNnc=; b=aSopWpORODdoQbNBckcCRlK07v ojSdDzKV067ipAZNt/Oz98dgmWGkZS2LvsJRaUsn+8mn2Ha8XPCULTxv087iw0jD5rJZCT46spvW1 xmc9Ierb49o4vIkDqRnE4Munrybstq4dQZflzwN+pYP8/+/7XFFrnpUiMOVnV9H88IRX5io/5EJzW tZsL05fl1NAEBLjg37+vJGSuMeBIm21n3GQwtIal4SaKqqx55Xn6FLQrR086NEd1nokj6xBrjM1wZ PilxLCGYTJoy3BSkGcc+8TOLUe32c//yavXZLWuwcnqSiw+UlDdhdJudpfl/Jz252Ch4uXmsbi1lQ K2APRLIA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1co5hX-0004V1-6w; Wed, 15 Mar 2017 09:58:39 +0000 Received: from mail-pf0-x229.google.com ([2607:f8b0:400e:c00::229]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1co5gl-0003Pp-S1 for linux-arm-kernel@lists.infradead.org; Wed, 15 Mar 2017 09:57:56 +0000 Received: by mail-pf0-x229.google.com with SMTP id v190so6865366pfb.1 for ; Wed, 15 Mar 2017 02:57:31 -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:in-reply-to:references; bh=evdGhm1mwliyfaDp5OFdnbgM1esBMlT7EKLc2zyKx48=; b=CAPyvDlLPJgphectUTCsLMjWensphgAzqndEUkkvvfATRUQm8VuDPZyHSbV/VH19Jh DOia3/hotfZi9CLGIDMHTe2mY6NoZs0lCVC8fVPBUGzRlMI5YwvWoZS7rMJB58YCAQsM 1HhUjWOq0GTwJXXBywx2XSbccciIFc1l23AyQ= 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; bh=evdGhm1mwliyfaDp5OFdnbgM1esBMlT7EKLc2zyKx48=; b=mdL7bCJn076kqpJ2XY5/g4536od3zo59LLq+tMy2mbzcPOHNNheyJEpVcS+3Ldizl6 oTN9pUgmUmGhBdI8lcoMIsPetfpZnpFUw082dhYRkE5HWm/kX5ch7NYSkNzY2IMDyil3 WFgmme1R6YhoBehlrRIr+hobTW574lWqOYSHSaeXjzyBgrGHLGUHwxVxOkFZIzmKXoLL DeQPFvbkLZO5AsNB6Aj1US+FYqfhwDu1yny9nYATP5CJvW9mM0UiHbDCt5MFaNICLWyf JXfPWamNabwBZLIbF5nF4ZrhabqY65ORGHGuRVLQvcq34izH9CKQS8RepyBvMNtk+Ozc 9mTw== X-Gm-Message-State: AFeK/H0sJPCKpLbe0MhrwIdNlrb7PtHNETcrDgjGjaY+miXYwWofE/9Z+6Bl2A+z3yBZVw7k X-Received: by 10.99.55.85 with SMTP id g21mr2708074pgn.65.1489571850942; Wed, 15 Mar 2017 02:57:30 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id v143sm3212911pgb.47.2017.03.15.02.57.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 15 Mar 2017 02:57:30 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com Subject: [PATCH v33 06/14] arm64: kdump: protect crash dump kernel memory Date: Wed, 15 Mar 2017 18:59:35 +0900 Message-Id: <20170315095941.25119-4-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20170315095656.24992-1-takahiro.akashi@linaro.org> References: <20170315095656.24992-1-takahiro.akashi@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170315_025752_123371_AFABF78F X-CRM114-Status: GOOD ( 18.63 ) 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, geoff@infradead.org, kexec@lists.infradead.org, AKASHI Takahiro , james.morse@arm.com, bauerman@linux.vnet.ibm.com, dyoung@redhat.com, linux-arm-kernel@lists.infradead.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 arch_kexec_protect_crashkres() and arch_kexec_unprotect_crashkres() are meant to be called by kexec_load() in order to protect the memory allocated for crash dump kernel once the image is loaded. The protection is implemented by unmapping the relevant segments in crash dump kernel memory, rather than making it read-only as other archs do, to prevent any corruption due to potential cache alias (with different attributes) problem. Page-level mappings are consistently used here so that we can change the attributes of segments in page granularity as well as shrink the region also in page granularity through /sys/kernel/kexec_crash_size and putting the freed memory back to buddy system. Signed-off-by: AKASHI Takahiro --- arch/arm64/kernel/machine_kexec.c | 35 ++++++++++++--- arch/arm64/mm/mmu.c | 90 ++++++++++++++++++++------------------- 2 files changed, 75 insertions(+), 50 deletions(-) diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c index bc96c8a7fc79..02e4f929db3b 100644 --- a/arch/arm64/kernel/machine_kexec.c +++ b/arch/arm64/kernel/machine_kexec.c @@ -14,6 +14,7 @@ #include #include +#include #include #include "cpu-reset.h" @@ -22,8 +23,6 @@ extern const unsigned char arm64_relocate_new_kernel[]; extern const unsigned long arm64_relocate_new_kernel_size; -static unsigned long kimage_start; - /** * kexec_image_info - For debugging output. */ @@ -64,8 +63,6 @@ void machine_kexec_cleanup(struct kimage *kimage) */ int machine_kexec_prepare(struct kimage *kimage) { - kimage_start = kimage->start; - kexec_image_info(kimage); if (kimage->type != KEXEC_TYPE_CRASH && cpus_are_stuck_in_kernel()) { @@ -183,7 +180,7 @@ void machine_kexec(struct kimage *kimage) kexec_list_flush(kimage); /* Flush the new image if already in place. */ - if (kimage->head & IND_DONE) + if ((kimage != kexec_crash_image) && (kimage->head & IND_DONE)) kexec_segment_flush(kimage); pr_info("Bye!\n"); @@ -201,7 +198,7 @@ void machine_kexec(struct kimage *kimage) */ cpu_soft_restart(1, reboot_code_buffer_phys, kimage->head, - kimage_start, 0); + kimage->start, 0); BUG(); /* Should never get here. */ } @@ -210,3 +207,29 @@ void machine_crash_shutdown(struct pt_regs *regs) { /* Empty routine needed to avoid build errors. */ } + +void arch_kexec_protect_crashkres(void) +{ + int i; + + kexec_segment_flush(kexec_crash_image); + + for (i = 0; i < kexec_crash_image->nr_segments; i++) + create_pgd_mapping(&init_mm, kexec_crash_image->segment[i].mem, + __phys_to_virt(kexec_crash_image->segment[i].mem), + kexec_crash_image->segment[i].memsz, + PAGE_KERNEL_INVALID, true); + + + flush_tlb_all(); +} + +void arch_kexec_unprotect_crashkres(void) +{ + int i; + + for (i = 0; i < kexec_crash_image->nr_segments; i++) + create_pgd_mapping(&init_mm, kexec_crash_image->segment[i].mem, + __phys_to_virt(kexec_crash_image->segment[i].mem), + kexec_crash_image->segment[i].memsz, PAGE_KERNEL, true); +} diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index cb359a3927ef..51aca31cd9b7 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -337,56 +339,31 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt, NULL, debug_pagealloc_enabled()); } -static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end) +static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, + phys_addr_t end, pgprot_t prot, + bool page_mappings_only) +{ + __create_pgd_mapping(pgd, start, __phys_to_virt(start), end - start, + prot, early_pgtable_alloc, + page_mappings_only); +} + +static void __init map_mem(pgd_t *pgd) { phys_addr_t kernel_start = __pa_symbol(_text); phys_addr_t kernel_end = __pa_symbol(__init_begin); + struct memblock_region *reg; /* - * Take care not to create a writable alias for the - * read-only text and rodata sections of the kernel image. + * Temporarily marked as NOMAP to skip mapping in the next for-loop */ + memblock_mark_nomap(kernel_start, kernel_end - kernel_start); - /* No overlap with the kernel text/rodata */ - if (end < kernel_start || start >= kernel_end) { - __create_pgd_mapping(pgd, start, __phys_to_virt(start), - end - start, PAGE_KERNEL, - early_pgtable_alloc, - debug_pagealloc_enabled()); - return; - } - - /* - * This block overlaps the kernel text/rodata mappings. - * Map the portion(s) which don't overlap. - */ - if (start < kernel_start) - __create_pgd_mapping(pgd, start, - __phys_to_virt(start), - kernel_start - start, PAGE_KERNEL, - early_pgtable_alloc, - debug_pagealloc_enabled()); - if (kernel_end < end) - __create_pgd_mapping(pgd, kernel_end, - __phys_to_virt(kernel_end), - end - kernel_end, PAGE_KERNEL, - early_pgtable_alloc, - debug_pagealloc_enabled()); - - /* - * Map the linear alias of the [_text, __init_begin) interval as - * read-only/non-executable. This makes the contents of the - * region accessible to subsystems such as hibernate, but - * protects it from inadvertent modification or execution. - */ - __create_pgd_mapping(pgd, kernel_start, __phys_to_virt(kernel_start), - kernel_end - kernel_start, PAGE_KERNEL_RO, - early_pgtable_alloc, debug_pagealloc_enabled()); -} - -static void __init map_mem(pgd_t *pgd) -{ - struct memblock_region *reg; +#ifdef CONFIG_KEXEC_CORE + if (crashk_res.end) + memblock_mark_nomap(crashk_res.start, + resource_size(&crashk_res)); +#endif /* map all the memory banks */ for_each_memblock(memory, reg) { @@ -398,8 +375,33 @@ static void __init map_mem(pgd_t *pgd) if (memblock_is_nomap(reg)) continue; - __map_memblock(pgd, start, end); + __map_memblock(pgd, start, end, + PAGE_KERNEL, debug_pagealloc_enabled()); + } + + /* + * Map the linear alias of the [_text, __init_begin) interval as + * read-only/non-executable. This makes the contents of the + * region accessible to subsystems such as hibernate, but + * protects it from inadvertent modification or execution. + */ + __map_memblock(pgd, kernel_start, kernel_end, + PAGE_KERNEL_RO, debug_pagealloc_enabled()); + memblock_clear_nomap(kernel_start, kernel_end - kernel_start); + +#ifdef CONFIG_KEXEC_CORE + /* + * User page-level mappings here so that we can shrink the region + * in page granularity and put back unused memory to buddy system + * through /sys/kernel/kexec_crash_size interface. + */ + if (crashk_res.end) { + __map_memblock(pgd, crashk_res.start, crashk_res.end + 1, + PAGE_KERNEL, true); + memblock_clear_nomap(crashk_res.start, + resource_size(&crashk_res)); } +#endif } void mark_rodata_ro(void)