From: Valentin David Date: Sat, 18 Apr 2026 13:09:00 +0000 (+0200) Subject: boot: Try to load UKI from simple filesystem before LoadImage X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5580db885c08b45bec5f665cbb0b114fa2538736;p=thirdparty%2Fsystemd.git boot: Try to load UKI from simple filesystem before LoadImage When the source buffer is NULL, the firmware is supposed to try to load the UKI with simple filesystem protocol then load file 2 protocol. But it seems on some versions of AMI, it does not use simple filesystem protocol, and then fails to load if the ESP was loaded from an El Torito boot catalog. Trying to load the source buffer from the simple filesystem protocol protocols seems work around this limitation. Shim for example, also loads the source buffer before calling LoadImage. So it seems to be a safe thing to do. We could also maybe in the future use load file 2 protocol if simple filesystem failed in the first place. --- diff --git a/src/boot/shim.c b/src/boot/shim.c index 97410d66696..10a0642ac3b 100644 --- a/src/boot/shim.c +++ b/src/boot/shim.c @@ -8,7 +8,6 @@ * https://github.com/mjg59/efitools */ -#include "device-path-util.h" #include "efi-efivars.h" #include "secure-boot.h" #include "shim.h" @@ -56,24 +55,7 @@ static bool shim_validate( if (!device_path) return false; - EFI_HANDLE device_handle; - EFI_DEVICE_PATH *file_dp = (EFI_DEVICE_PATH *) device_path; - err = BS->LocateDevicePath( - MAKE_GUID_PTR(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL), &file_dp, &device_handle); - if (err != EFI_SUCCESS) - return false; - - _cleanup_file_close_ EFI_FILE *root = NULL; - err = open_volume(device_handle, &root); - if (err != EFI_SUCCESS) - return false; - - _cleanup_free_ char16_t *dp_str = NULL; - err = device_path_to_str(file_dp, &dp_str); - if (err != EFI_SUCCESS) - return false; - - err = file_read(root, dp_str, 0, 0, &file_buffer_owned, &file_size); + err = load_file_from_simple_filesystem(device_path, &file_buffer_owned, &file_size); if (err != EFI_SUCCESS) return false; @@ -111,12 +93,21 @@ EFI_STATUS shim_load_image( if (have_shim) install_security_override(shim_validate, NULL); + _cleanup_free_ char *source_buffer = NULL; + size_t source_size = 0; + + /* For some AMI firmware, BS->LoadImage() does not read correctly when the file comes the ESP on an + * optical drive. But the simple filesystem protocol does work. So we try to load it. If that does + * not work, we let BS->LoadImage() try instead. + */ + (void) load_file_from_simple_filesystem(device_path, &source_buffer, &source_size); + EFI_STATUS ret = BS->LoadImage( /* BootPolicy= */ boot_policy, parent, (EFI_DEVICE_PATH *) device_path, - /* SourceBuffer= */ NULL, - /* SourceSize= */ 0, + source_buffer, + source_size, ret_image); if (have_shim) uninstall_security_override(); diff --git a/src/boot/util.c b/src/boot/util.c index c40a9aad65b..22981bc00db 100644 --- a/src/boot/util.c +++ b/src/boot/util.c @@ -195,6 +195,32 @@ EFI_STATUS file_read( return file_handle_read(handle, offset, size, ret, ret_size); } +EFI_STATUS load_file_from_simple_filesystem(const EFI_DEVICE_PATH *device_path, char **file_buffer, size_t *file_size) { + EFI_STATUS err; + EFI_HANDLE device_handle; + EFI_DEVICE_PATH *file_dp = (EFI_DEVICE_PATH *) device_path; + + assert(device_path); + assert(file_buffer); + assert(file_size); + + err = BS->LocateDevicePath(MAKE_GUID_PTR(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL), &file_dp, &device_handle); + if (err != EFI_SUCCESS) + return err; + + _cleanup_file_close_ EFI_FILE *root = NULL; + err = open_volume(device_handle, &root); + if (err != EFI_SUCCESS) + return err; + + _cleanup_free_ char16_t *dp_str = NULL; + err = device_path_to_str(file_dp, &dp_str); + if (err != EFI_SUCCESS) + return err; + + return file_read(root, dp_str, 0, 0, file_buffer, file_size); +} + void set_attribute_safe(size_t attr) { /* Various UEFI implementations suppress color changes from a color to the same color. Often, we want * to force out the color change though, hence change the color here once, and then back. We simply diff --git a/src/boot/util.h b/src/boot/util.h index 2c8cc36ea58..fa552d6f46c 100644 --- a/src/boot/util.h +++ b/src/boot/util.h @@ -138,6 +138,7 @@ char16_t *mangle_stub_cmdline(char16_t *cmdline); EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf); EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, uint64_t offset, size_t size, char **ret, size_t *ret_size); +EFI_STATUS load_file_from_simple_filesystem(const EFI_DEVICE_PATH *device_path, char **file_buffer, size_t *file_size); EFI_STATUS file_handle_read(EFI_FILE *handle, uint64_t offset, size_t size, char **ret, size_t *ret_size); static inline void file_closep(EFI_FILE **handle) {