diff --git a/src/boot/shim.c b/src/boot/shim.c index 97410d6669..10a0642ac3 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 c40a9aad65..22981bc00d 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 2c8cc36ea5..fa552d6f46 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) {