From: Tobias Heider Date: Mon, 25 Aug 2025 14:07:54 +0000 (+0200) Subject: stub: fix file path handling for loaded kernel X-Git-Tag: v259-rc1~532 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f4051650657cd337ceba67b773f0e3bf854cbaff;p=thirdparty%2Fsystemd.git stub: fix file path handling for loaded kernel - Actually pass the new memory file path to parent_loaded_image->FilePath - Restore old parent_loaded_image if Linux returns - Pass the same kernel_file_path in load_via_boot_services path - s/Re-use/Patch in comment explaining what we are doing Fixes #38566 --- diff --git a/src/boot/linux.c b/src/boot/linux.c index 92a2b0afc5c..2dda03a7800 100644 --- a/src/boot/linux.c +++ b/src/boot/linux.c @@ -20,9 +20,6 @@ #include "shim.h" #include "util.h" -#define STUB_PAYLOAD_GUID \ - { 0x55c5d1f8, 0x04cd, 0x46b5, { 0x8a, 0x20, 0xe5, 0x6c, 0xbb, 0x30, 0x52, 0xd0 } } - typedef struct { MEMMAP_DEVICE_PATH memmap_path; EFI_DEVICE_PATH end_path; @@ -56,22 +53,12 @@ static EFI_STATUS load_via_boot_services( uint32_t compat_entry_point, const char16_t *cmdline, const struct iovec *kernel, - const struct iovec *initrd) { + const struct iovec *initrd, + KERNEL_FILE_PATH *kernel_file_path) { _cleanup_(unload_imagep) EFI_HANDLE kernel_image = NULL; EFI_LOADED_IMAGE_PROTOCOL* loaded_image = NULL; EFI_STATUS err; - VENDOR_DEVICE_PATH device_node = { - .Header = { - .Type = MEDIA_DEVICE_PATH, - .SubType = MEDIA_VENDOR_DP, - .Length = sizeof(device_node), - }, - .Guid = STUB_PAYLOAD_GUID, - }; - - _cleanup_free_ EFI_DEVICE_PATH* file_path = device_path_replace_node(parent_loaded_image->FilePath, NULL, &device_node.Header); - /* When running with shim < v16 and booting a UKI directly from it, without a second stage loader, * the shim verify protocol needs to be called or it will raise a security violation when starting * the image (e.g.: Fedora Cloud Base UKI). TODO: drop once support for shim < v16 is not needed. */ @@ -81,13 +68,13 @@ static EFI_STATUS load_via_boot_services( &(ValidationContext) { .addr = kernel->iov_base, .len = kernel->iov_len, - .device_path = file_path, + .device_path = &kernel_file_path->memmap_path.Header, }); err = BS->LoadImage(/* BootPolicy= */false, parent, - file_path, + &kernel_file_path->memmap_path.Header, kernel->iov_base, kernel->iov_len, &kernel_image); @@ -204,17 +191,27 @@ EFI_STATUS linux_exec( if (err != EFI_SUCCESS) return log_error_status(err, "Bad kernel image: %m"); - /* Re-use the parent_image(_handle) and parent_loaded_image for the kernel image we are about to execute. - * We have to do this, because if kernel stub code passes its own handle to certain firmware functions, - * the firmware could cast EFI_LOADED_IMAGE_PROTOCOL * to a larger struct to access its own private data, - * and if we allocated a smaller struct, that could cause problems. - * This is modeled exactly after GRUB behaviour, which has proven to be functional. */ EFI_LOADED_IMAGE_PROTOCOL *parent_loaded_image; err = BS->HandleProtocol( parent_image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &parent_loaded_image); if (err != EFI_SUCCESS) return log_error_status(err, "Cannot get parent loaded image: %m"); + _cleanup_free_ KERNEL_FILE_PATH *kernel_file_path = xnew(KERNEL_FILE_PATH, 1); + *kernel_file_path = (KERNEL_FILE_PATH) { + .memmap_path = { + .Header = { + .Type = HARDWARE_DEVICE_PATH, + .SubType = HW_MEMMAP_DP, + .Length = sizeof(MEMMAP_DEVICE_PATH), + }, + .MemoryType = EfiLoaderData, + .StartingAddress = POINTER_TO_PHYSICAL_ADDRESS(kernel->iov_base), + .EndingAddress = POINTER_TO_PHYSICAL_ADDRESS(kernel->iov_base) + kernel->iov_len, + }, + .end_path = DEVICE_PATH_END_NODE, + }; + /* If shim provides LoadImage, it comes from the new SHIM_IMAGE_LOADER interface added in shim 16, * and implements the following: * - shim hashes PE sections of PE binaries it authenticates and stores the hashes in a global @@ -241,7 +238,8 @@ EFI_STATUS linux_exec( compat_entry_point, cmdline, kernel, - initrd); + initrd, + kernel_file_path); err = pe_kernel_check_no_relocation(kernel->iov_base); if (err != EFI_SUCCESS) @@ -300,26 +298,13 @@ EFI_STATUS linux_exec( } } - _cleanup_free_ KERNEL_FILE_PATH *kernel_file_path = xnew(KERNEL_FILE_PATH, 1); - - *kernel_file_path = (KERNEL_FILE_PATH) { - .memmap_path = { - .Header = { - .Type = HARDWARE_DEVICE_PATH, - .SubType = HW_MEMMAP_DP, - .Length = sizeof(MEMMAP_DEVICE_PATH), - }, - .MemoryType = EfiLoaderData, - .StartingAddress = POINTER_TO_PHYSICAL_ADDRESS(kernel->iov_base), - .EndingAddress = POINTER_TO_PHYSICAL_ADDRESS(kernel->iov_base) + kernel->iov_len, - }, - .end_path = { - .Type = END_DEVICE_PATH_TYPE, - .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE, - .Length = sizeof(EFI_DEVICE_PATH), - }, - }; - + /* Patch the parent_image(_handle) and parent_loaded_image for the kernel image we are about to execute. + * We have to do this, because if kernel stub code passes its own handle to certain firmware functions, + * the firmware could cast EFI_LOADED_IMAGE_PROTOCOL * to a larger struct to access its own private data, + * and if we allocated a smaller struct, that could cause problems. + * This is modeled exactly after GRUB behaviour, which has proven to be functional. */ + EFI_LOADED_IMAGE_PROTOCOL original_parent_loaded_image = *parent_loaded_image; + parent_loaded_image->FilePath = &kernel_file_path->memmap_path.Header; parent_loaded_image->ImageBase = loaded_kernel; parent_loaded_image->ImageSize = kernel_size_in_memory; @@ -346,6 +331,9 @@ EFI_STATUS linux_exec( err = compat_entry(parent_image, ST); } + /* Restore */ + *parent_loaded_image = original_parent_loaded_image; + /* On failure we'll free the buffers. EDK2 requires the memory buffers to be writable and * non-executable, as in some configurations it will overwrite them with a fixed pattern, so if the * attributes are not restored FreePages() will crash. */