From patchwork Mon Sep 7 17:46:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trammell Hudson X-Patchwork-Id: 11761819 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A8144746 for ; Mon, 7 Sep 2020 17:48:14 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 775D9206E7 for ; Mon, 7 Sep 2020 17:48:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=trmm.net header.i=@trmm.net header.b="AjKuYmwS" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 775D9206E7 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=trmm.net Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1kFLEG-0002Ys-2E; Mon, 07 Sep 2020 17:46:56 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1kFLEE-0002Ye-VE for xen-devel@lists.xenproject.org; Mon, 07 Sep 2020 17:46:54 +0000 X-Inumbo-ID: 5bc2ff02-f6fb-4809-a3bd-87236e372553 Received: from mail2.protonmail.ch (unknown [185.70.40.22]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 5bc2ff02-f6fb-4809-a3bd-87236e372553; Mon, 07 Sep 2020 17:46:53 +0000 (UTC) Date: Mon, 07 Sep 2020 17:46:41 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=trmm.net; s=protonmail; t=1599500811; bh=M8vjImy5Ow/dD+WsfLzC2ffSj0SnoqTopAklRr8u49M=; h=Date:To:From:Reply-To:Subject:From; b=AjKuYmwSAdcSa3f+vxrT0LhY3pRNGDHIZshLGUWHMl6wpASybXOX1oGmC+kSE6rAt cgfn6RNbHkJCbSy65KoaSFG28saVtGkb7PBOqJ5K6MXK1wnuprw+u6eKD7ZEyEjrf2 K8KYTr8hnjZTHg49HCafudChNPL6dJ5p1UTrSYWA= To: Xen-devel From: Trammell Hudson Subject: [PATCH v3 1/4] x86/xen.lds.S: Work around binutils build id alignment bug Message-ID: <1maNbi9dxlGrwq08QJuuvznixBLaxtncQfen8KjdEVuQqbIGuqATOOXStaKY7MktWJ5H2tfslm0WIpv6w3SEL4D3uGKkn2hXhAw7TiShMCI=@trmm.net> MIME-Version: 1.0 X-Spam-Status: No, score=-1.2 required=10.0 tests=ALL_TRUSTED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF shortcircuit=no autolearn=disabled version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on mailout.protonmail.ch X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Reply-To: Trammell Hudson Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" binutils in most distrbutions have a bug in find_section_by_vma() that causes objcopy round section addresses incorrectly and that think the .buildid section overlaps with the .rodata. Aligning the sections allows these older verisons of the tools to work on the xen.efi executable image. Mailing list discussion: https://sourceware.org/pipermail/binutils/2020-August/112746.html Fixed in: https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=610ed3e08f13b3886fd7194fb7a248dee8724685 Signed-off-by: Trammell hudson --- xen/arch/x86/xen.lds.S | 1 + 1 file changed, 1 insertion(+) -- 2.25.1 diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index 0273f79152..ba691b1890 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -156,6 +156,7 @@ SECTIONS __note_gnu_build_id_end = .; } :note :text #elif defined(BUILD_ID_EFI) + . = ALIGN(32); /* workaround binutils section overlap bug */ DECL_SECTION(.buildid) { __note_gnu_build_id_start = .; *(.buildid) From patchwork Mon Sep 7 17:47:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trammell Hudson X-Patchwork-Id: 11761821 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4F760746 for ; Mon, 7 Sep 2020 17:48:25 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 237792080A for ; Mon, 7 Sep 2020 17:48:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=trmm.net header.i=@trmm.net header.b="lxfEvt80" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 237792080A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=trmm.net Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1kFLF4-0002gQ-Gh; Mon, 07 Sep 2020 17:47:46 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1kFLF2-0002gG-RK for xen-devel@lists.xenproject.org; Mon, 07 Sep 2020 17:47:44 +0000 X-Inumbo-ID: 0305cb4c-d723-442b-b147-b43af5b45721 Received: from mail-40134.protonmail.ch (unknown [185.70.40.134]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 0305cb4c-d723-442b-b147-b43af5b45721; Mon, 07 Sep 2020 17:47:43 +0000 (UTC) Date: Mon, 07 Sep 2020 17:47:36 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=trmm.net; s=protonmail; t=1599500862; bh=2U4wML9SR0idO3N3KS6/SVyXY7iQli99vxZrFKrhoLo=; h=Date:To:From:Reply-To:Subject:From; b=lxfEvt80URGmahtae9+u0dHwU3u6MoHFh6cASs0Xp25CJNKSnT7MTEQ46YeSSoALi fz/xXwfq3/kx3qNizihXQ8ilpIVHP1ZYaXTRPQWXFWw736VfZHKu4eqIWHJxaaOlCL gav6q2G+IWdnP251UdVQSQwvQ/2TS+nEWdxx7lvc= To: Xen-devel From: Trammell Hudson Subject: [PATCH v3 2/4] efi/boot.c: add file.need_to_free and split display_file_info() Message-ID: MIME-Version: 1.0 X-Spam-Status: No, score=-1.2 required=10.0 tests=ALL_TRUSTED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF shortcircuit=no autolearn=disabled version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on mailout.protonmail.ch X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Reply-To: Trammell Hudson Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" add file.need_to_free and split display_file_info() Signed-off-by: Trammell hudson --- xen/common/efi/boot.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) -- 2.25.1 diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 4022a672c9..f5bdc4b1df 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -102,6 +102,7 @@ union string { struct file { UINTN size; + bool need_to_free; union { EFI_PHYSICAL_ADDRESS addr; void *ptr; @@ -279,13 +280,13 @@ void __init noreturn blexit(const CHAR16 *str) if ( !efi_bs ) efi_arch_halt(); - if ( cfg.addr ) + if ( cfg.addr && cfg.need_to_free ) efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); - if ( kernel.addr ) + if ( kernel.addr && kernel.need_to_free ) efi_bs->FreePages(kernel.addr, PFN_UP(kernel.size)); - if ( ramdisk.addr ) + if ( ramdisk.addr && ramdisk.need_to_free ) efi_bs->FreePages(ramdisk.addr, PFN_UP(ramdisk.size)); - if ( xsm.addr ) + if ( xsm.addr && xsm.need_to_free ) efi_bs->FreePages(xsm.addr, PFN_UP(xsm.size)); efi_arch_blexit(); @@ -538,6 +539,21 @@ static char * __init split_string(char *s) return NULL; } +static void __init display_file_info(CHAR16 *name, struct file *file, char *options) +{ + if ( file == &cfg ) + return; + + PrintStr(name); + PrintStr(L": "); + DisplayUint(file->addr, 2 * sizeof(file->addr)); + PrintStr(L"-"); + DisplayUint(file->addr + file->size, 2 * sizeof(file->addr)); + PrintStr(newline); + + efi_arch_handle_module(file, name, options); +} + static bool __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, struct file *file, char *options) { @@ -572,6 +588,7 @@ static bool __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, HYPERVISOR_VIRT_END - DIRECTMAP_VIRT_START); ret = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData, PFN_UP(size), &file->addr); + file->need_to_free = true; } if ( EFI_ERROR(ret) ) { @@ -581,16 +598,7 @@ static bool __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, else { file->size = size; - if ( file != &cfg ) - { - PrintStr(name); - PrintStr(L": "); - DisplayUint(file->addr, 2 * sizeof(file->addr)); - PrintStr(L"-"); - DisplayUint(file->addr + size, 2 * sizeof(file->addr)); - PrintStr(newline); - efi_arch_handle_module(file, name, options); - } + display_file_info(name, file, options); ret = FileHandle->Read(FileHandle, &file->size, file->ptr); if ( !EFI_ERROR(ret) && file->size != size ) From patchwork Mon Sep 7 17:48:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trammell Hudson X-Patchwork-Id: 11761839 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2C99E59D for ; Mon, 7 Sep 2020 17:49:36 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EA43C206E7 for ; Mon, 7 Sep 2020 17:49:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=trmm.net header.i=@trmm.net header.b="R+MIgv58" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EA43C206E7 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=trmm.net Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1kFLFz-0002mn-Rc; Mon, 07 Sep 2020 17:48:43 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1kFLFy-0002mb-8a for xen-devel@lists.xenproject.org; Mon, 07 Sep 2020 17:48:42 +0000 X-Inumbo-ID: e9a92c28-1512-41fe-845d-a516ab4f9cbb Received: from mail-40131.protonmail.ch (unknown [185.70.40.131]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id e9a92c28-1512-41fe-845d-a516ab4f9cbb; Mon, 07 Sep 2020 17:48:40 +0000 (UTC) Date: Mon, 07 Sep 2020 17:48:29 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=trmm.net; s=protonmail; t=1599500918; bh=BWoRX8nsSJry2t+KxnV5XLSxdghnoTi7NBFQ+IEcJJ0=; h=Date:To:From:Reply-To:Subject:From; b=R+MIgv58xyowPu/kUhOpw83RAT97q0exOEUIcw0WTV517tAnJO5Hl/fgytNHYFVOQ tlj3X/4QgqA/OFxiV1I8OyAJPI0/BjLXYGchlcbUb4zr3hXLi6PcQw3Ia7A+qBj1HW +pW8/VG2qRLaVj7wAogFGniLqGJROBb7++0WPNIs= To: Xen-devel From: Trammell Hudson Subject: [PATCH v3 3/4] efi: Enable booting unified hypervisor/kernel/initrd images Message-ID: MIME-Version: 1.0 X-Spam-Status: No, score=-1.2 required=10.0 tests=ALL_TRUSTED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF shortcircuit=no autolearn=disabled version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on mailout.protonmail.ch X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Reply-To: Trammell Hudson Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" This patch adds support for bundling the xen.efi hypervisor, the xen.cfg configuration file, the Linux kernel and initrd, as well as the XSM, and architectural specific files into a single "unified" EFI executable. This allows an administrator to update the components independently without requiring rebuilding xen, as well as to replace the components in an existing image. The resulting EFI executable can be invoked directly from the UEFI Boot Manager, removing the need to use a separate loader like grub as well as removing dependencies on local filesystem access. And since it is a single file, it can be signed and validated by UEFI Secure Boot without requring the shim protocol. It is inspired by systemd-boot's unified kernel technique and borrows the function to locate PE sections from systemd's LGPL'ed code. During EFI boot, Xen looks at its own loaded image to locate the PE sections for the Xen configuration (`.config`), dom0 kernel (`.kernel`), dom0 initrd (`.initrd`), and XSM config (`.xsm`), which are included after building xen.efi using objcopy to add named sections for each input file. For x86, the CPU ucode can be included in a section named `.ucode`, which is loaded in the efi_arch_cfg_file_late() stage of the boot process. On ARM systems the Device Tree can be included in a section named `.dtb`, which is loaded during the efi_arch_cfg_file_early() stage of the boot process. Signed-off-by: Trammell hudson --- .gitignore | 1 + docs/misc/efi.pandoc | 47 ++++++++++++ xen/arch/arm/efi/efi-boot.h | 22 ++++-- xen/arch/x86/efi/Makefile | 2 +- xen/arch/x86/efi/efi-boot.h | 7 +- xen/common/efi/boot.c | 72 +++++++++++++----- xen/common/efi/efi.h | 3 + xen/common/efi/pe.c | 141 ++++++++++++++++++++++++++++++++++++ 8 files changed, 266 insertions(+), 29 deletions(-) create mode 100644 xen/common/efi/pe.c -- 2.25.1 diff --git a/.gitignore b/.gitignore index 823f4743dc..1c79b9f90a 100644 --- a/.gitignore +++ b/.gitignore @@ -296,6 +296,7 @@ xen/arch/x86/efi/mkreloc xen/arch/*/xen.lds xen/arch/*/asm-offsets.s xen/arch/*/efi/boot.c +xen/arch/*/efi/pe.c xen/arch/*/efi/compat.c xen/arch/*/efi/ebmalloc.c xen/arch/*/efi/efi.h diff --git a/docs/misc/efi.pandoc b/docs/misc/efi.pandoc index 23c1a2732d..c882b1f8f8 100644 --- a/docs/misc/efi.pandoc +++ b/docs/misc/efi.pandoc @@ -116,3 +116,50 @@ Filenames must be specified relative to the location of the EFI binary. Extra options to be passed to Xen can also be specified on the command line, following a `--` separator option. + +## Unified Xen kernel image + +The "Unified" kernel image can be generated by adding additional +sections to the Xen EFI executable with objcopy, similar to how +[systemd-boot uses the stub to add them to the Linux kernel](https://wiki.archlinux.org/index.php/systemd-boot#Preparing_a_unified_kernel_image) + +The sections for the xen configuration file, the dom0 kernel, dom0 initrd, +XSM and CPU microcode should be added after the Xen `.pad` section, the +ending address of which can be located with: + +``` +objdump -h xen.efi \ + | perl -ane '/\.pad/ && printf "0x%016x\n", hex($F[2]) + hex($F[3])' +``` + +All the sections are optional (`.config`, `.kernel`, `.initrd`, `.xsm`, +`.ucode` (x86) and `.dtb` (ARM)) and the order does not matter. +The addresses do not need to be contiguous, although they should not +be overlapping. + +``` +objcopy \ + --add-section .config=xen.cfg \ + --change-section-vma .config=0xffff82d041000000 + --add-section .ucode=ucode.bin \ + --change-section-vma .ucode=0xffff82d041010000 \ + --add-section .xsm=xsm.cfg \ + --change-section-vma .xsm=0xffff82d041080000 \ + --add-section .kernel=vmlinux \ + --change-section-vma .kernel=0xffff82d041100000 \ + --add-section .ramdisk=initrd.img \ + --change-section-vma .initrd=0xffff82d042000000 \ + xen.efi \ + xen.unified.efi +``` + +The unified executable can be signed with sbsigntool to make +it usable with UEFI secure boot: + +``` +sbsign \ + --key signing.key \ + --cert cert.pem \ + --output xen.signed.efi \ + xen.unified.efi +``` diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h index 6527cb0bdf..154e605fee 100644 --- a/xen/arch/arm/efi/efi-boot.h +++ b/xen/arch/arm/efi/efi-boot.h @@ -375,27 +375,33 @@ static void __init noreturn efi_arch_post_exit_boot(void) efi_xen_start(fdt, fdt_totalsize(fdt)); } -static void __init efi_arch_cfg_file_early(EFI_FILE_HANDLE dir_handle, char *section) +static void __init efi_arch_cfg_file_early(EFI_LOADED_IMAGE *image, EFI_FILE_HANDLE dir_handle, char *section) { union string name; /* * The DTB must be processed before any other entries in the configuration - * file, as the DTB is updated as modules are loaded. + * file, as the DTB is updated as modules are loaded. Prefer the one + * stored as a PE section in a unified image, and fall back to a file + * on disk if the section is not present. */ - name.s = get_value(&cfg, section, "dtb"); - if ( name.s ) + if ( !read_section(image, ".dtb", &dtbfile, NULL) ) { - split_string(name.s); - read_file(dir_handle, s2w(&name), &dtbfile, NULL); - efi_bs->FreePool(name.w); + name.s = get_value(&cfg, section, "dtb"); + if ( name.s ) + { + split_string(name.s); + read_file(dir_handle, s2w(&name), &dtbfile, NULL); + efi_bs->FreePool(name.w); + } } + fdt = fdt_increase_size(&dtbfile, cfg.size + EFI_PAGE_SIZE); if ( !fdt ) blexit(L"Unable to create new FDT"); } -static void __init efi_arch_cfg_file_late(EFI_FILE_HANDLE dir_handle, char *section) +static void __init efi_arch_cfg_file_late(EFI_LOADED_IMAGE *image, EFI_FILE_HANDLE dir_handle, char *section) { } diff --git a/xen/arch/x86/efi/Makefile b/xen/arch/x86/efi/Makefile index 770438a029..e857c0f2cc 100644 --- a/xen/arch/x86/efi/Makefile +++ b/xen/arch/x86/efi/Makefile @@ -8,7 +8,7 @@ cmd_objcopy_o_ihex = $(OBJCOPY) -I ihex -O binary $< $@ boot.init.o: buildid.o -EFIOBJ := boot.init.o ebmalloc.o compat.o runtime.o +EFIOBJ := boot.init.o pe.init.o ebmalloc.o compat.o runtime.o $(call cc-option-add,cflags-stack-boundary,CC,-mpreferred-stack-boundary=4) $(EFIOBJ): CFLAGS-stack-boundary := $(cflags-stack-boundary) diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 7188c9a551..ecc1bbd17d 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -272,14 +272,17 @@ static void __init noreturn efi_arch_post_exit_boot(void) unreachable(); } -static void __init efi_arch_cfg_file_early(EFI_FILE_HANDLE dir_handle, char *section) +static void __init efi_arch_cfg_file_early(EFI_LOADED_IMAGE *image, EFI_FILE_HANDLE dir_handle, char *section) { } -static void __init efi_arch_cfg_file_late(EFI_FILE_HANDLE dir_handle, char *section) +static void __init efi_arch_cfg_file_late(EFI_LOADED_IMAGE *image, EFI_FILE_HANDLE dir_handle, char *section) { union string name; + if ( read_section(image, ".ucode", &ucode, NULL) ) + return; + name.s = get_value(&cfg, section, "ucode"); if ( !name.s ) name.s = get_value(&cfg, "global", "ucode"); diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index f5bdc4b1df..452b5f4362 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -121,6 +121,8 @@ static CHAR16 *s2w(union string *str); static char *w2s(const union string *str); static bool read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, struct file *file, char *options); +static bool read_section(EFI_LOADED_IMAGE *image, + char *name, struct file *file, char *options); static size_t wstrlen(const CHAR16 * s); static int set_color(u32 mask, int bpp, u8 *pos, u8 *sz); static bool match_guid(const EFI_GUID *guid1, const EFI_GUID *guid2); @@ -622,6 +624,26 @@ static bool __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, return true; } +static bool __init read_section(EFI_LOADED_IMAGE *image, + char *const name, struct file *file, char *options) +{ + /* skip the leading "." in the section name */ + union string name_string = { .s = name + 1 }; + + file->ptr = (void *)pe_find_section(image->ImageBase, image->ImageSize, + name, &file->size); + if ( !file->ptr ) + return false; + + file->need_to_free = false; + + s2w(&name_string); + display_file_info(name_string.w, file, options); + efi_bs->FreePool(name_string.w); + + return true; +} + static void __init pre_parse(const struct file *cfg) { char *ptr = cfg->ptr, *end = ptr + cfg->size; @@ -1206,9 +1228,13 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) /* Get the file system interface. */ dir_handle = get_parent_handle(loaded_image, &file_name); - /* Read and parse the config file. */ - if ( !cfg_file_name ) + if ( read_section(loaded_image, ".config", &cfg, NULL) ) + { + PrintStr(L"Using unified config file\r\n"); + } + else if ( !cfg_file_name ) { + /* Read and parse the config file. */ CHAR16 *tail; while ( (tail = point_tail(file_name)) != NULL ) @@ -1257,29 +1283,39 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) if ( !name.s ) blexit(L"No Dom0 kernel image specified."); - efi_arch_cfg_file_early(dir_handle, section.s); + efi_arch_cfg_file_early(loaded_image, dir_handle, section.s); option_str = split_string(name.s); - read_file(dir_handle, s2w(&name), &kernel, option_str); - efi_bs->FreePool(name.w); - - if ( !EFI_ERROR(efi_bs->LocateProtocol(&shim_lock_guid, NULL, - (void **)&shim_lock)) && - (status = shim_lock->Verify(kernel.ptr, kernel.size)) != EFI_SUCCESS ) - PrintErrMesg(L"Dom0 kernel image could not be verified", status); - name.s = get_value(&cfg, section.s, "ramdisk"); - if ( name.s ) + if ( !read_section(loaded_image, ".kernel", &kernel, option_str) ) { - read_file(dir_handle, s2w(&name), &ramdisk, NULL); + read_file(dir_handle, s2w(&name), &kernel, option_str); efi_bs->FreePool(name.w); + + if ( !EFI_ERROR(efi_bs->LocateProtocol(&shim_lock_guid, NULL, + (void **)&shim_lock)) && + (status = shim_lock->Verify(kernel.ptr, kernel.size)) != EFI_SUCCESS ) + PrintErrMesg(L"Dom0 kernel image could not be verified", status); } - name.s = get_value(&cfg, section.s, "xsm"); - if ( name.s ) + if ( !read_section(loaded_image, ".ramdisk", &ramdisk, NULL) ) { - read_file(dir_handle, s2w(&name), &xsm, NULL); - efi_bs->FreePool(name.w); + name.s = get_value(&cfg, section.s, "ramdisk"); + if ( name.s ) + { + read_file(dir_handle, s2w(&name), &ramdisk, NULL); + efi_bs->FreePool(name.w); + } + } + + if ( !read_section(loaded_image, ".xsm", &xsm, NULL) ) + { + name.s = get_value(&cfg, section.s, "xsm"); + if ( name.s ) + { + read_file(dir_handle, s2w(&name), &xsm, NULL); + efi_bs->FreePool(name.w); + } } /* @@ -1315,7 +1351,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) } } - efi_arch_cfg_file_late(dir_handle, section.s); + efi_arch_cfg_file_late(loaded_image, dir_handle, section.s); efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); cfg.addr = 0; diff --git a/xen/common/efi/efi.h b/xen/common/efi/efi.h index 4845d84913..c9b741bf27 100644 --- a/xen/common/efi/efi.h +++ b/xen/common/efi/efi.h @@ -47,3 +47,6 @@ const CHAR16 *wmemchr(const CHAR16 *s, CHAR16 c, UINTN n); /* EFI boot allocator. */ void *ebmalloc(size_t size); void free_ebmalloc_unused_mem(void); + +const void * pe_find_section(const UINT8 *image_base, const size_t image_size, + const char *section_name, UINTN *size_out); diff --git a/xen/common/efi/pe.c b/xen/common/efi/pe.c new file mode 100644 index 0000000000..097c6848a8 --- /dev/null +++ b/xen/common/efi/pe.c @@ -0,0 +1,141 @@ +/* + * xen/common/efi/pe.c + * + * PE executable header parser. + * + * Derived from https://github.com/systemd/systemd/blob/master/src/boot/efi/pe.c + * commit 07d5ed536ec0a76b08229c7a80b910cb9acaf6b1 + * + * Copyright (C) 2015 Kay Sievers + * Copyright (C) 2020 Trammell Hudson + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + + +#include "efi.h" + +struct DosFileHeader { + UINT8 Magic[2]; + UINT16 LastSize; + UINT16 nBlocks; + UINT16 nReloc; + UINT16 HdrSize; + UINT16 MinAlloc; + UINT16 MaxAlloc; + UINT16 ss; + UINT16 sp; + UINT16 Checksum; + UINT16 ip; + UINT16 cs; + UINT16 RelocPos; + UINT16 nOverlay; + UINT16 reserved[4]; + UINT16 OEMId; + UINT16 OEMInfo; + UINT16 reserved2[10]; + UINT32 ExeHeader; +} __attribute__((packed)); + +#define PE_HEADER_MACHINE_ARM64 0xaa64 +#define PE_HEADER_MACHINE_X64 0x8664 +#define PE_HEADER_MACHINE_I386 0x014c + +struct PeFileHeader { + UINT16 Machine; + UINT16 NumberOfSections; + UINT32 TimeDateStamp; + UINT32 PointerToSymbolTable; + UINT32 NumberOfSymbols; + UINT16 SizeOfOptionalHeader; + UINT16 Characteristics; +} __attribute__((packed)); + +struct PeHeader { + UINT8 Magic[4]; + struct PeFileHeader FileHeader; +} __attribute__((packed)); + +struct PeSectionHeader { + UINT8 Name[8]; + UINT32 VirtualSize; + UINT32 VirtualAddress; + UINT32 SizeOfRawData; + UINT32 PointerToRawData; + UINT32 PointerToRelocations; + UINT32 PointerToLinenumbers; + UINT16 NumberOfRelocations; + UINT16 NumberOfLinenumbers; + UINT32 Characteristics; +} __attribute__((packed)); + +const void * __init pe_find_section(const CHAR8 * image, const UINTN image_size, + const char * section_name, UINTN * size_out) +{ + const struct DosFileHeader * dos = (const void*) image; + const struct PeHeader * pe; + const struct PeSectionHeader * sect; + const UINTN name_len = strlen(section_name); + UINTN offset = 0; + + if ( name_len > sizeof(sect->Name) ) + return NULL; + + if ( image_size < sizeof(*dos) ) + return NULL; + if ( memcmp(dos->Magic, "MZ", 2) != 0 ) + return NULL; + + offset = dos->ExeHeader; + pe = (const void *) &image[offset]; + + offset += sizeof(*pe); + if ( image_size < offset ) + return NULL; + + if ( memcmp(pe->Magic, "PE\0\0", 4) != 0 ) + return NULL; + + /* PE32+ Subsystem type */ +#if defined(__arm__) || defined (__aarch64__) + if ( pe->FileHeader.Machine != PE_HEADER_MACHINE_ARM64 ) + return NULL; +#elif defined(__x86_64__) + if ( pe->FileHeader.Machine != PE_HEADER_MACHINE_X64 ) + return NULL; +#else + /* unknown architecture */ + return NULL; +#endif + + offset += pe->FileHeader.SizeOfOptionalHeader; + + for ( UINTN i = 0 ; i < pe->FileHeader.NumberOfSections ; i++ ) + { + sect = (const void *) &image[offset]; + if ( image_size < offset + sizeof(*sect) ) + return NULL; + + if ( memcmp(sect->Name, section_name, name_len) != 0 || + image_size < sect->VirtualSize + sect->VirtualAddress ) + { + offset += sizeof(*sect); + continue; + } + + if ( size_out ) + *size_out = sect->VirtualSize; + + return &image[sect->VirtualAddress]; + } + + return NULL; +} From patchwork Mon Sep 7 17:49:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trammell Hudson X-Patchwork-Id: 11761855 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2228F746 for ; Mon, 7 Sep 2020 17:50:10 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E7E8F206E7 for ; Mon, 7 Sep 2020 17:50:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=trmm.net header.i=@trmm.net header.b="qgk1rqwR" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E7E8F206E7 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=trmm.net Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1kFLGV-0002r2-4Q; Mon, 07 Sep 2020 17:49:15 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1kFLGT-0002qq-Cx for xen-devel@lists.xenproject.org; Mon, 07 Sep 2020 17:49:13 +0000 X-Inumbo-ID: 7ea4ca1a-f346-4a3e-aa93-d1d2d446ea92 Received: from mail-40133.protonmail.ch (unknown [185.70.40.133]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 7ea4ca1a-f346-4a3e-aa93-d1d2d446ea92; Mon, 07 Sep 2020 17:49:11 +0000 (UTC) Date: Mon, 07 Sep 2020 17:49:01 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=trmm.net; s=protonmail; t=1599500950; bh=kO1ttbfruYlXqfeMQ+l83Ln2EGyL+ZF8veTCN3S60wU=; h=Date:To:From:Reply-To:Subject:From; b=qgk1rqwR/LNPrljzImX1kXK0alp6j/UgtxGbA8iZjyFjgIEaGPbsEz8lM6Tw5v+jD aEZNeftUcMVGF/Ikf18BRFtrYilnazjk2BVgvRFTHFh5B0DrVjsLF1T6Hf0jG5yn3u 5Lpc16TT1CMFxFDlCxEXHoGgHQa8AA2EZrfxnbQc= To: Xen-devel From: Trammell Hudson Subject: [PATCH v3 4/4] efi: Do not use command line if secure boot is enabled. Message-ID: <7O9RuKkcGcH8q9SVMZQR4G8LORrYZSW_koA6MlG29xOMmq5wjsSzjOWBoZtFJ3U4Av1FLjPCw7iz0DqQrwLS3PxrUAOcZmNklpkGi87L2x4=@trmm.net> MIME-Version: 1.0 X-Spam-Status: No, score=-1.2 required=10.0 tests=ALL_TRUSTED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF shortcircuit=no autolearn=disabled version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on mailout.protonmail.ch X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Reply-To: Trammell Hudson Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" If secure boot is enabled, the Xen command line arguments are ignored. If a unified Xen image is used, then the bundled configuration, dom0 kernel, and initrd are prefered over the ones listed in the config file. Unlike the shim based verification, the PE signature on a unified image covers the all of the Xen+config+kernel+initrd modules linked into the unified image. This also ensures that properly configured platforms will measure the entire runtime into the TPM for unsealing secrets or remote attestation. Signed-off-by: Trammell Hudson --- xen/common/efi/boot.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) -- 2.25.1 diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 452b5f4362..5aaebd5f20 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -947,6 +947,26 @@ static void __init setup_efi_pci(void) efi_bs->FreePool(handles); } +/* + * Logic should remain sync'ed with linux/arch/x86/xen/efi.c + * Secure Boot is enabled iff 'SecureBoot' is set and the system is + * not in Setup Mode. + */ +static bool __init efi_secure_boot(void) +{ + static const __initconst EFI_GUID global_guid = EFI_GLOBAL_VARIABLE; + uint8_t secboot, setupmode; + UINTN secboot_size = sizeof(secboot); + UINTN setupmode_size = sizeof(setupmode); + + if ( efi_rs->GetVariable(L"SecureBoot", (EFI_GUID *)&global_guid, NULL, &secboot_size, &secboot) != EFI_SUCCESS ) + return false; + if ( efi_rs->GetVariable(L"SetupMode", (EFI_GUID *)&global_guid, NULL, &setupmode_size, &setupmode) != EFI_SUCCESS ) + return false; + + return secboot == 1 && setupmode == 0; +} + static void __init efi_variables(void) { EFI_STATUS status; @@ -1123,8 +1143,8 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) static EFI_GUID __initdata shim_lock_guid = SHIM_LOCK_PROTOCOL_GUID; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; - unsigned int i, argc; - CHAR16 **argv, *file_name, *cfg_file_name = NULL, *options = NULL; + unsigned int i, argc = 0; + CHAR16 **argv = NULL, *file_name, *cfg_file_name = NULL, *options = NULL; UINTN gop_mode = ~0; EFI_SHIM_LOCK_PROTOCOL *shim_lock; EFI_GRAPHICS_OUTPUT_PROTOCOL *gop = NULL; @@ -1132,6 +1152,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) bool base_video = false; char *option_str; bool use_cfg_file; + bool secure = false; __set_bit(EFI_BOOT, &efi_flags); __set_bit(EFI_LOADER, &efi_flags); @@ -1150,8 +1171,10 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) PrintErrMesg(L"No Loaded Image Protocol", status); efi_arch_load_addr_check(loaded_image); + secure = efi_secure_boot(); - if ( use_cfg_file ) + /* If UEFI Secure Boot is enabled, do not parse the command line */ + if ( use_cfg_file && !secure ) { UINTN offset = 0; @@ -1209,6 +1232,8 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) PrintStr(L"Xen " __stringify(XEN_VERSION) "." __stringify(XEN_SUBVERSION) XEN_EXTRAVERSION " (c/s " XEN_CHANGESET ") EFI loader\r\n"); + if ( secure ) + PrintStr(L"UEFI Secure Boot enabled\r\n"); efi_arch_relocate_image(0);