efi: Prefer shim image loader protocol if it exists
shim has all the facilities to load and authenticate PE images against
MOK or the system firmware's cert store, but only exposes its
verification routine via the shim lock protocol, leaving it to loaders
such as GRUB to implement PE loading from scratch when booting Linux via
its EFI stub.
Now that shim exposes load/startimage equivalents, let's use these and
boot in EFI mode in cases where shim is active.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index fb4d12e..9992153 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -54,6 +54,9 @@
static grub_guid_t load_file2_guid = GRUB_EFI_LOAD_FILE2_PROTOCOL_GUID;
static grub_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
+static grub_guid_t shim_image_loader_guid = GRUB_SHIM_IMAGE_LOADER_GUID;
+
+static grub_efi_shim_image_loader_protocol_t *shim_image_loader = NULL;
static initrd_media_device_path_t initrd_lf2_device_path = {
{
@@ -184,7 +187,7 @@
{
grub_efi_memory_mapped_device_path_t *mempath;
grub_efi_handle_t image_handle;
- grub_efi_boot_services_t *b;
+ grub_efi_shim_image_loader_protocol_t *b;
grub_efi_status_t status;
grub_efi_loaded_image_t *loaded_image;
int len;
@@ -204,7 +207,7 @@
mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
mempath[1].header.length = sizeof (grub_efi_device_path_t);
- b = grub_efi_system_table->boot_services;
+ b = shim_image_loader;
status = b->load_image (0, grub_efi_image_handle,
(grub_efi_device_path_t *) mempath,
(void *) addr, size, &image_handle);
@@ -459,10 +462,12 @@
grub_dl_ref (my_mod);
- if (grub_is_shim_lock_enabled () == true)
+ shim_image_loader = grub_efi_locate_protocol (&shim_image_loader_guid, 0);
+
+ if (grub_is_shim_lock_enabled () == true && shim_image_loader == NULL)
{
#if defined(__i386__) || defined(__x86_64__)
- grub_dprintf ("linux", "shim_lock enabled, falling back to legacy Linux kernel loader\n");
+ grub_dprintf ("linux", "shim_lock enabled but no shim image loader installed, falling back to legacy Linux kernel loader\n");
err = grub_cmd_linux_x86_legacy (cmd, argc, argv);
@@ -471,10 +476,16 @@
else
goto fail;
#else
- grub_dprintf ("linux", "shim_lock enabled, trying Linux kernel EFI stub loader\n");
+ grub_dprintf ("linux", "shim_lock enabled but no shim image loader installed, trying Linux kernel EFI stub loader\n");
#endif
}
+ if (shim_image_loader == NULL)
+ {
+ shim_image_loader =
+ (grub_efi_shim_image_loader_protocol_t *)&grub_efi_system_table->boot_services->load_image;
+ }
+
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index f3c50ed..3094337 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -379,6 +379,11 @@
{0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } \
}
+#define GRUB_SHIM_IMAGE_LOADER_GUID \
+ { 0x1f492041, 0xfadb, 0x4e59, \
+ { 0x9e, 0x57, 0x7c, 0xaf, 0xe7, 0x3a, 0x55, 0xab } \
+ }
+
struct grub_efi_sal_system_table
{
grub_uint32_t signature;
@@ -1781,6 +1786,32 @@
};
typedef struct grub_efi_shim_lock_protocol grub_efi_shim_lock_protocol_t;
+struct grub_efi_shim_image_loader_protocol
+{
+ grub_efi_status_t
+ (__grub_efi_api *load_image) (grub_efi_boolean_t boot_policy,
+ grub_efi_handle_t parent_image_handle,
+ grub_efi_device_path_t *file_path,
+ void *source_buffer,
+ grub_efi_uintn_t source_size,
+ grub_efi_handle_t *image_handle);
+
+ grub_efi_status_t
+ (__grub_efi_api *start_image) (grub_efi_handle_t image_handle,
+ grub_efi_uintn_t *exit_data_size,
+ grub_efi_char16_t **exit_data);
+
+ grub_efi_status_t
+ (__grub_efi_api *exit) (grub_efi_handle_t image_handle,
+ grub_efi_status_t exit_status,
+ grub_efi_uintn_t exit_data_size,
+ grub_efi_char16_t *exit_data);
+
+ grub_efi_status_t
+ (__grub_efi_api *unload_image) (grub_efi_handle_t image_handle);
+};
+typedef struct grub_efi_shim_image_loader_protocol grub_efi_shim_image_loader_protocol_t;
+
typedef grub_guid_t grub_efi_rng_algorithm_t;
struct grub_efi_rng_protocol