From: Ard Biesheuvel <[email protected]> Invoke the Secure Launch protocol exposed by the boot loader at the appropriate time to perform a measured launch of the decompressed kernel after ExitBootServices().
Co-developed-by: Ross Philipson <[email protected]> Signed-off-by: Ard Biesheuvel <[email protected]> Signed-off-by: Ross Philipson <[email protected]> --- drivers/firmware/efi/libstub/Makefile | 1 + drivers/firmware/efi/libstub/efistub.h | 24 ++++++++++++++ drivers/firmware/efi/libstub/x86-slaunch.c | 38 ++++++++++++++++++++++ drivers/firmware/efi/libstub/x86-stub.c | 27 ++++++++++++--- 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 drivers/firmware/efi/libstub/x86-slaunch.c diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index e386ffd009b7..fd5eaf3142b2 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -86,6 +86,7 @@ lib-$(CONFIG_ARM) += arm32-stub.o lib-$(CONFIG_ARM64) += kaslr.o arm64.o arm64-stub.o smbios.o lib-$(CONFIG_X86) += x86-stub.o smbios.o lib-$(CONFIG_X86_64) += x86-5lvl.o +lib-$(CONFIG_SECURE_LAUNCH) += x86-slaunch.o lib-$(CONFIG_RISCV) += kaslr.o riscv.o riscv-stub.o lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 979a21818cc1..18301ba3ae0f 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -1267,4 +1267,28 @@ void arch_accept_memory(phys_addr_t start, phys_addr_t end); efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size); efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen); +#ifdef CONFIG_SECURE_LAUNCH +efi_status_t efi_secure_launch_init(efi_handle_t image_handle); +efi_status_t efi_secure_launch_prepare(struct boot_params *boot_params, + phys_addr_t base); +void efi_secure_launch(void); +#else +static inline +efi_status_t efi_secure_launch_init(efi_handle_t image_handle) +{ + return EFI_UNSUPPORTED; +} + +static inline +efi_status_t efi_secure_launch_prepare(struct boot_params *boot_params, + phys_addr_t base) +{ + return EFI_SUCCESS; +} + +static inline void efi_secure_launch(void) +{ +} +#endif + #endif diff --git a/drivers/firmware/efi/libstub/x86-slaunch.c b/drivers/firmware/efi/libstub/x86-slaunch.c new file mode 100644 index 000000000000..98ff15f94996 --- /dev/null +++ b/drivers/firmware/efi/libstub/x86-slaunch.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/efi.h> +#include <linux/pci.h> +#include <linux/stddef.h> +#include <linux/slr_efi.h> +#include <linux/slaunch.h> + +#include <asm/boot.h> +#include <asm/bootparam.h> +#include <asm/efi.h> + +#include "efistub.h" + +static struct efi_slaunch_protocol *slaunch; + +efi_status_t efi_secure_launch_init(efi_handle_t image_handle) +{ + return efi_bs_call(handle_protocol, image_handle, + &EFI_SLAUNCH_PROTOCOL_GUID, (void **)&slaunch); +} + +efi_status_t efi_secure_launch_prepare(struct boot_params *boot_params, + phys_addr_t base) +{ + if (!slaunch) + return EFI_SUCCESS; + + return slaunch->setup_dlme(slaunch, base, mle_header_offset, (u64)boot_params); +} + +void efi_secure_launch(void) +{ + if (!slaunch) + return; + + slaunch->launch(slaunch); +} diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c index cef32e2c82d8..339e63ae84ef 100644 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@ -833,7 +833,8 @@ static efi_status_t parse_options(const char *cmdline) } static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry, - struct boot_params *boot_params) + struct boot_params *boot_params, + unsigned long alloc_limit) { unsigned long virt_addr = LOAD_PHYSICAL_ADDR; unsigned long addr, alloc_size, entry; @@ -877,8 +878,7 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry, status = efi_random_alloc(alloc_size, CONFIG_PHYSICAL_ALIGN, &addr, seed[0], EFI_LOADER_CODE, - LOAD_PHYSICAL_ADDR, - EFI_X86_KERNEL_ALLOC_LIMIT); + LOAD_PHYSICAL_ADDR, alloc_limit); if (status != EFI_SUCCESS) return status; @@ -890,6 +890,10 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry, *kernel_entry = addr + entry; + status = efi_secure_launch_prepare(boot_params, addr); + if (status != EFI_SUCCESS) + return status; + return efi_adjust_memory_range_protection(addr, kernel_text_size) ?: efi_adjust_memory_range_protection(addr + kernel_inittext_offset, kernel_inittext_size); @@ -914,6 +918,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle, struct boot_params *boot_params) { + unsigned long alloc_limit = EFI_X86_KERNEL_ALLOC_LIMIT; efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; const struct linux_efi_initrd *initrd = NULL; unsigned long kernel_entry; @@ -925,6 +930,17 @@ void __noreturn efi_stub_entry(efi_handle_t handle, if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) efi_exit(handle, EFI_INVALID_PARAMETER); + status = efi_secure_launch_init(handle); + switch (status) { + case EFI_SUCCESS: + alloc_limit = U32_MAX; + break; + case EFI_UNSUPPORTED: + break; + default: + efi_exit(handle, status); + } + if (!IS_ENABLED(CONFIG_EFI_HANDOVER_PROTOCOL) || !boot_params) { status = efi_allocate_bootparams(handle, &boot_params); if (status != EFI_SUCCESS) @@ -974,7 +990,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle, if (efi_mem_encrypt > 0) hdr->xloadflags |= XLF_MEM_ENCRYPTION; - status = efi_decompress_kernel(&kernel_entry, boot_params); + status = efi_decompress_kernel(&kernel_entry, boot_params, alloc_limit); if (status != EFI_SUCCESS) { efi_err("Failed to decompress kernel\n"); goto fail; @@ -1029,6 +1045,9 @@ void __noreturn efi_stub_entry(efi_handle_t handle, goto fail; } + /* If a Secure Launch is in progress, this never returns */ + efi_secure_launch(); + /* * Call the SEV init code while still running with the firmware's * GDT/IDT, so #VC exceptions will be handled by EFI. -- 2.47.3

