From 35b6e13d966a5e7b52e063b9434788ee496ca0ba Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 14 Mar 2019 11:30:01 +0000 Subject: [PATCH] uefi: Copy the shimx64.efi binary for known broken firmware Some system firmware helpfully 'deduplicate' the boot loader entries based on the filepath, without taking into account either the label or optional data. This means we have to use a custom copy of shim for firmware updates. --- plugins/uefi/fu-uefi-bootmgr.c | 42 +++++++++++++++++++++++----------- plugins/uefi/fu-uefi-bootmgr.h | 1 + plugins/uefi/fu-uefi-device.c | 2 ++ plugins/uefi/uefi.quirk | 4 ++++ 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/plugins/uefi/fu-uefi-bootmgr.c b/plugins/uefi/fu-uefi-bootmgr.c index a67ea1499..a521f3cdc 100644 --- a/plugins/uefi/fu-uefi-bootmgr.c +++ b/plugins/uefi/fu-uefi-bootmgr.c @@ -297,16 +297,16 @@ fu_uefi_bootmgr_bootnext (const gchar *esp_path, FuUefiBootmgrFlags flags, GError **error) { + const gchar *filepath; gboolean use_fwup_path = FALSE; gsize loader_sz = 0; gssize opt_size = 0; gssize sz, dp_size = 0; guint32 attributes = LOAD_OPTION_ACTIVE; g_autofree guint16 *loader_str = NULL; - g_autofree gchar *fwup_esp_path = NULL; - g_autofree gchar *fwup_fs_basename = NULL; g_autofree gchar *label = NULL; g_autofree gchar *shim_app = NULL; + g_autofree gchar *shim_cpy = NULL; g_autofree guint8 *dp_buf = NULL; g_autofree guint8 *opt = NULL; g_autofree gchar *source_app = NULL; @@ -325,7 +325,21 @@ fu_uefi_bootmgr_bootnext (const gchar *esp_path, shim_app = fu_uefi_get_esp_app_path (esp_path, "shim", error); if (shim_app == NULL) return FALSE; - if (!g_file_test (shim_app, G_FILE_TEST_EXISTS)) { + if (g_file_test (shim_app, G_FILE_TEST_EXISTS)) { + /* use a custom copy of shim for firmware updates */ + if (flags & FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE) { + shim_cpy = fu_uefi_get_esp_app_path (esp_path, "shimfwupd", error); + if (shim_cpy == NULL) + return FALSE; + if (!fu_uefi_cmp_asset (shim_app, shim_cpy)) { + if (!fu_uefi_copy_asset (shim_app, shim_cpy, error)) + return FALSE; + } + filepath = shim_cpy; + } else { + filepath = shim_app; + } + } else { if (fu_uefi_secure_boot_enabled () && (flags & FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB) > 0) { g_set_error_literal (error, @@ -346,9 +360,12 @@ fu_uefi_bootmgr_bootnext (const gchar *esp_path, return FALSE; } - sz = efi_generate_file_device_path (dp_buf, dp_size, use_fwup_path - ? target_app - : shim_app, + /* no shim, so use this directly */ + if (use_fwup_path) + filepath = target_app; + + /* generate device path for target */ + sz = efi_generate_file_device_path (dp_buf, dp_size, filepath, EFIBOOT_OPTIONS_IGNORE_FS_ERROR| EFIBOOT_ABBREV_HD); if (sz < 0) { @@ -356,24 +373,23 @@ fu_uefi_bootmgr_bootnext (const gchar *esp_path, G_IO_ERROR, G_IO_ERROR_FAILED, "efi_generate_file_device_path(%s) failed", - use_fwup_path ? target_app : shim_app); + filepath); return FALSE; } + /* add the fwupdx64.efi ESP path as the shim loadopt data */ dp_size = sz; dp_buf = g_malloc0 (dp_size); - fwup_fs_basename = g_path_get_basename (target_app); - fwup_esp_path = g_strdup_printf ("\\%s", fwup_fs_basename); if (!use_fwup_path) { + g_autofree gchar *fwup_fs_basename = g_path_get_basename (target_app); + g_autofree gchar *fwup_esp_path = g_strdup_printf ("\\%s", fwup_fs_basename); loader_str = fu_uft8_to_ucs2 (fwup_esp_path, -1); loader_sz = fu_ucs2_strlen (loader_str, -1) * 2; if (loader_sz) loader_sz += 2; } - sz = efi_generate_file_device_path (dp_buf, dp_size, use_fwup_path - ? target_app - : shim_app, + sz = efi_generate_file_device_path (dp_buf, dp_size, filepath, EFIBOOT_OPTIONS_IGNORE_FS_ERROR| EFIBOOT_ABBREV_HD); if (sz != dp_size) { @@ -381,7 +397,7 @@ fu_uefi_bootmgr_bootnext (const gchar *esp_path, G_IO_ERROR, G_IO_ERROR_FAILED, "efi_generate_file_device_path(%s) failed", - use_fwup_path ? target_app : shim_app); + filepath); return FALSE; } diff --git a/plugins/uefi/fu-uefi-bootmgr.h b/plugins/uefi/fu-uefi-bootmgr.h index 99eeade6b..012d905fd 100644 --- a/plugins/uefi/fu-uefi-bootmgr.h +++ b/plugins/uefi/fu-uefi-bootmgr.h @@ -15,6 +15,7 @@ G_BEGIN_DECLS typedef enum { FU_UEFI_BOOTMGR_FLAG_NONE = 0, FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB = 1 << 0, + FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE = 1 << 1, FU_UEFI_BOOTMGR_FLAG_LAST } FuUefiBootmgrFlags; diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 218da4a7a..777b231c7 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -424,6 +424,8 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) /* update the firmware before the bootloader runs */ if (fu_device_get_metadata_boolean (device, "RequireShimForSecureBoot")) flags |= FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB; + if (fu_device_has_custom_flag (device, "use-shim-unique")) + flags |= FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE; /* some legacy devices use the old name to deduplicate boot entries */ if (fu_device_has_custom_flag (device, "use-legacy-bootmgr-desc")) diff --git a/plugins/uefi/uefi.quirk b/plugins/uefi/uefi.quirk index a9719fef8..51271158e 100644 --- a/plugins/uefi/uefi.quirk +++ b/plugins/uefi/uefi.quirk @@ -12,3 +12,7 @@ Name = Intel Management Engine [Guid=5b92717b-2cad-4a96-a13b-9d65781df8bf] VersionFormat = intel-me2 Name = Intel Management Engine + +# Star Labs LabTop (Mk III) +[Guid=8265d473-a6c2-42b4-897b-bc220faa2d32] +Flags = use-shim-unique