From patchwork Mon Aug 14 12:54:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 9898869 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 14910602BA for ; Mon, 14 Aug 2017 13:00:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F0B4328617 for ; Mon, 14 Aug 2017 13:00:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E584628628; Mon, 14 Aug 2017 13:00:08 +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.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID 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 AD94428617 for ; Mon, 14 Aug 2017 13:00:07 +0000 (UTC) Received: (qmail 30142 invoked by uid 550); 14 Aug 2017 12:56:14 -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: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 29899 invoked from network); 14 Aug 2017 12:56:09 -0000 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=tf7BsFIQW2DHd7yFEV5AgQHJS9eW5n24kjJm5+mIIY8=; b=D04NWZ8eAz6WUN7/qQnY/yEbaSVqMATLphSxw5cEV+XO8C4CJfWAXFnry+0uoKjEUA zjdFol69zKtrnxL/+v1hdUIaB2Un4Nt0al10iSCr+oKzY4SMqzKdSboeS3wq8kV6vzee NGYgGaV7pwSs/YnSsCtGsMhB45WQeTHOoCNbc= 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=tf7BsFIQW2DHd7yFEV5AgQHJS9eW5n24kjJm5+mIIY8=; b=HlW9XA5zJwXYYTG9vJqhApCv3gpu7JoShWPlwng5/sM5sb6ZSFlTHKbHhPVTrTXCML Cvfbjid543vYxfNjQnuZO3WhytbsWSR1y+4s7ATOe75iq9SYFxgCPs5OVH3siJ6SSo+e +PyenV0LwnswUClUwmaJeRi3D6w69XNEqpPhvWpLwqwfrGk2ENBejeL0sX/yv1QmLws6 4td1zV0IcxVsIltQPEEDQdFLPu0NeUrqnimjr8lCQr4Zq3P/NxvZOWb4quhtlGMzDiE9 YxY4sYBeuaEB7RzY9R+0qHSlpSNfrj590asaCVojJLbtG+MiJ7JXroEz1K53pJdww1fx xgrw== X-Gm-Message-State: AHYfb5hK51deyhr2jaZcDqAPXXNiFpH9+rHQRUEJj/kg1NntontJlCQd dgepMZzMByls5vxzl6cT3g== X-Received: by 10.223.199.7 with SMTP id k7mr5899067wrg.216.1502715358083; Mon, 14 Aug 2017 05:55:58 -0700 (PDT) From: Ard Biesheuvel To: kernel-hardening@lists.openwall.com Cc: linux-arm-kernel@lists.infradead.org, Ard Biesheuvel , Arnd Bergmann , Nicolas Pitre , Russell King , Kees Cook , Thomas Garnier , Marc Zyngier , Mark Rutland , Tony Lindgren , Matt Fleming , Dave Martin Date: Mon, 14 Aug 2017 13:54:10 +0100 Message-Id: <20170814125411.22604-30-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170814125411.22604-1-ard.biesheuvel@linaro.org> References: <20170814125411.22604-1-ard.biesheuvel@linaro.org> Subject: [kernel-hardening] [PATCH 29/30] efi/libstub: arm: reserve bootloader supplied initrd in memory map X-Virus-Scanned: ClamAV using ClamSMTP Under KASLR, the EFI stub may allocate the kernel anywhere in the physical address space, which could be right on top of an initrd if it was supplied by the bootloader (i.e., GRUB) in /chosen rather than passed via the initrd= command line option. So allocate the pages explicitly, this ensures that the random memory allocation routine will disregard the region. Note that this means that we need to defer the handle_kernel_image() call. Cc: Matt Fleming Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/arm-stub.c | 51 ++++++++++++-------- drivers/firmware/efi/libstub/efistub.h | 3 ++ drivers/firmware/efi/libstub/fdt.c | 42 ++++++++++++++++ 3 files changed, 75 insertions(+), 21 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 8181ac179d14..f5ef5ccd5f45 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -133,6 +133,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, unsigned long reserve_size = 0; enum efi_secureboot_mode secure_boot; struct screen_info *si; + bool have_chosen_initrd; /* Check if we were booted by the EFI firmware */ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) @@ -183,15 +184,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, si = setup_graphics(sys_table); - status = handle_kernel_image(sys_table, image_addr, &image_size, - &reserve_addr, - &reserve_size, - dram_base, image); - if (status != EFI_SUCCESS) { - pr_efi_err(sys_table, "Failed to relocate kernel\n"); - goto fail_free_cmdline; - } - secure_boot = efi_get_secureboot(sys_table); /* @@ -209,7 +201,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, if (status != EFI_SUCCESS) { pr_efi_err(sys_table, "Failed to load device tree!\n"); - goto fail_free_image; + goto fail_free_cmdline; } } @@ -222,16 +214,33 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, pr_efi(sys_table, "Using DTB from configuration table\n"); } - if (!fdt_addr) + if (!fdt_addr) { pr_efi(sys_table, "Generating empty DTB\n"); + have_chosen_initrd = false; + } else { + status = efi_reserve_dtb_initrd(sys_table, (void *)fdt_addr); + have_chosen_initrd = (status != EFI_NOT_FOUND); + } - status = handle_cmdline_files(sys_table, image, cmdline_ptr, "initrd=", - efi_get_max_initrd_addr(dram_base, - *image_addr), - (unsigned long *)&initrd_addr, - (unsigned long *)&initrd_size); - if (status != EFI_SUCCESS) - pr_efi_err(sys_table, "Failed initrd from command line!\n"); + status = handle_kernel_image(sys_table, image_addr, &image_size, + &reserve_addr, &reserve_size, + dram_base, image); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, "Failed to relocate kernel\n"); + goto fail_free_fdt; + } + + if (!have_chosen_initrd) { + status = handle_cmdline_files(sys_table, image, cmdline_ptr, + "initrd=", + efi_get_max_initrd_addr(dram_base, + *image_addr), + (unsigned long *)&initrd_addr, + (unsigned long *)&initrd_size); + if (status != EFI_SUCCESS) + pr_efi_err(sys_table, + "Failed initrd from command line!\n"); + } efi_random_get_seed(sys_table); @@ -272,11 +281,11 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, pr_efi_err(sys_table, "Failed to update FDT and exit boot services\n"); efi_free(sys_table, initrd_size, initrd_addr); - efi_free(sys_table, fdt_size, fdt_addr); - -fail_free_image: efi_free(sys_table, image_size, *image_addr); efi_free(sys_table, reserve_size, reserve_addr); + +fail_free_fdt: + efi_free(sys_table, fdt_size, fdt_addr); fail_free_cmdline: free_screen_info(sys_table, si); efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr); diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index aaf2aeb785ea..35b514d7d962 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -68,4 +68,7 @@ efi_status_t check_platform_features(efi_system_table_t *sys_table_arg); efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg); +efi_status_t efi_reserve_dtb_initrd(efi_system_table_t *sys_table_arg, + const void *fdt); + #endif diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index 8830fa601e45..54408c95e094 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -385,3 +385,45 @@ void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size) return fdt; } + +efi_status_t efi_reserve_dtb_initrd(efi_system_table_t *sys_table_arg, + const void *fdt) +{ + int chosen, len; + const void *prop; + efi_physical_addr_t start, end; + unsigned long num_pages; + efi_status_t status; + + chosen = fdt_path_offset(fdt, "/chosen"); + if (chosen == -FDT_ERR_NOTFOUND) + return EFI_NOT_FOUND; + + prop = fdt_getprop(fdt, chosen, "linux,initrd-start", &len); + if (!prop) + return EFI_NOT_FOUND; + + start = (len == sizeof(fdt32_t)) ? fdt32_to_cpu(*(fdt32_t *)prop) + : fdt64_to_cpu(*(fdt64_t *)prop); + + prop = fdt_getprop(fdt, chosen, "linux,initrd-end", &len); + if (!prop) + return EFI_NOT_FOUND; + + end = (len == sizeof(fdt32_t)) ? fdt32_to_cpu(*(fdt32_t *)prop) + : fdt64_to_cpu(*(fdt64_t *)prop); + + start = round_down(start, EFI_PAGE_SIZE); + num_pages = round_up(end - start, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + + status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, + EFI_LOADER_DATA, num_pages, &start); + + if (status != EFI_SUCCESS) + pr_efi_err(sys_table_arg, + "Failed to reserve initrd area found in /chosen\n"); + else + pr_efi(sys_table_arg, "Using initrd found in /chosen\n"); + + return status; +}