mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-14 14:22:13 +00:00
uefi: Append the header on capsules without headers from Linux
This allows using better heuristics and potentially phasing this out in the future.
This commit is contained in:
parent
6131f5df8f
commit
2ac3aca2a7
@ -69,7 +69,7 @@ fu_plugin_dell_tpm_func (void)
|
||||
struct tpm_status tpm_out;
|
||||
g_autoptr(FuPlugin) plugin_dell = NULL;
|
||||
g_autoptr(FuPlugin) plugin_uefi = NULL;
|
||||
g_autoptr(GBytes) blob_fw = g_bytes_new_static ("fw", 2);
|
||||
g_autoptr(GBytes) blob_fw = g_bytes_new_static ("fw", 30);
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GPtrArray) devices = NULL;
|
||||
|
||||
@ -244,8 +244,11 @@ fu_plugin_dell_tpm_func (void)
|
||||
g_clear_error (&error);
|
||||
|
||||
/* test override */
|
||||
g_test_expect_message ("FuPluginUefi", G_LOG_LEVEL_WARNING,
|
||||
"missing or invalid embedded capsule header");
|
||||
ret = fu_plugin_runner_update (plugin_uefi, device_v20, NULL, blob_fw,
|
||||
FWUPD_INSTALL_FLAG_FORCE, &error);
|
||||
g_test_assert_expected_messages ();
|
||||
g_assert_no_error (error);
|
||||
g_assert (ret);
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ EFI_GUID fwupdate_guid =
|
||||
{0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}};
|
||||
EFI_GUID ux_capsule_guid =
|
||||
{0x3b8c8162,0x188c,0x46a4,{0xae,0xc9,0xbe,0x43,0xf1,0xd6,0x56,0x97}};
|
||||
EFI_GUID fmp_capsule_guid =
|
||||
{0x6dcbd5ed,0xe82d,0x4c44,{0xbd,0xa1,0x71,0x94,0x19,0x9a,0xd9,0x2a}};
|
||||
EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE;
|
||||
|
||||
|
||||
@ -1017,7 +1015,6 @@ do_ux_csum(EFI_HANDLE loaded_image, UINT8 *buf, UINTN size)
|
||||
}
|
||||
|
||||
#define is_ux_capsule(guid) (guid_cmp(guid, &ux_capsule_guid) == 0)
|
||||
#define is_fmp_capsule(guid) (guid_cmp(guid, &fmp_capsule_guid) == 0)
|
||||
|
||||
static EFI_STATUS
|
||||
add_capsule(update_table *update, EFI_CAPSULE_HEADER **capsule_out,
|
||||
@ -1047,68 +1044,17 @@ add_capsule(update_table *update, EFI_CAPSULE_HEADER **capsule_out,
|
||||
dprint(L"updates guid: %g\n", &update->info->guid);
|
||||
dprint(L"File guid: %g\n", fbuf);
|
||||
|
||||
/*
|
||||
* See if it has the capsule header, and if not, add one.
|
||||
*
|
||||
* Unfortunately there's not a good way to do this, so we're just
|
||||
* checking if the capsule has the fw_class guid at the right place.
|
||||
*/
|
||||
if ((guid_cmp(&update->info->guid, (efi_guid_t *)fbuf) == 0 ||
|
||||
is_fmp_capsule((efi_guid_t *)fbuf)) &&
|
||||
/*
|
||||
* We're ignoring things that are 40 bytes here, because that's
|
||||
* the size of the variables used in the test code I wrote for
|
||||
* edk2 - It's basically a capsule header with no payload, so
|
||||
* there's nothing real it can do anyway.
|
||||
*
|
||||
* At some point I'll update that to be slightly different and
|
||||
* take the exception out, but it's not pressing.
|
||||
*/
|
||||
fsize != 40) {
|
||||
dprint(L"Image has capsule image embedded\n");
|
||||
cbd_len = fsize;
|
||||
cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf;
|
||||
capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf;
|
||||
if (!cap_out->Flags && !is_ux_capsule(&update->info->guid)) {
|
||||
cbd_len = fsize;
|
||||
cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf;
|
||||
capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf;
|
||||
if (!cap_out->Flags && !is_ux_capsule(&update->info->guid)) {
|
||||
#if defined(__aarch64__)
|
||||
cap_out->Flags |= update->info->capsule_flags;
|
||||
cap_out->Flags |= update->info->capsule_flags;
|
||||
#else
|
||||
cap_out->Flags |= update->info->capsule_flags |
|
||||
CAPSULE_FLAGS_PERSIST_ACROSS_RESET |
|
||||
CAPSULE_FLAGS_INITIATE_RESET;
|
||||
cap_out->Flags |= update->info->capsule_flags |
|
||||
CAPSULE_FLAGS_PERSIST_ACROSS_RESET |
|
||||
CAPSULE_FLAGS_INITIATE_RESET;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
dprint(L"Image does not have embedded header\n");
|
||||
dprint(L"Allocating %d for capsule header.\n",
|
||||
sizeof (*capsule)+fsize);
|
||||
rc = allocate((void **)&capsule, sizeof (*capsule) + fsize);
|
||||
if (EFI_ERROR(rc)) {
|
||||
print(L"Tried to allocate %d\n",
|
||||
sizeof (*capsule) + fsize);
|
||||
print(L"Could not allocate space for update: %r.\n",
|
||||
rc);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
capsule->CapsuleGuid = update->info->guid;
|
||||
capsule->HeaderSize = sizeof (*capsule);
|
||||
if (!is_ux_capsule(&update->info->guid)) {
|
||||
#if defined(__aarch64__)
|
||||
capsule->Flags |= update->info->capsule_flags;
|
||||
#else
|
||||
capsule->Flags = update->info->capsule_flags |
|
||||
CAPSULE_FLAGS_PERSIST_ACROSS_RESET |
|
||||
CAPSULE_FLAGS_INITIATE_RESET;
|
||||
#endif
|
||||
}
|
||||
capsule->CapsuleImageSize = fsize + sizeof (*capsule);
|
||||
|
||||
UINT8 *buffer = (UINT8 *)capsule + capsule->HeaderSize;
|
||||
CopyMem(buffer, fbuf, fsize);
|
||||
cbd_len = capsule->CapsuleImageSize;
|
||||
cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)capsule;
|
||||
cap_out = capsule;
|
||||
free(fbuf, fsize);
|
||||
}
|
||||
|
||||
if (is_ux_capsule(&update->info->guid)) {
|
||||
|
@ -377,6 +377,10 @@ fu_plugin_update (FuPlugin *plugin,
|
||||
if (!fu_device_write_firmware (device, blob_fw, error))
|
||||
return FALSE;
|
||||
|
||||
/* record if we had an invalid header during update */
|
||||
str = fu_uefi_missing_capsule_header (device) ? "True" : "False";
|
||||
fu_plugin_add_report_metadata (plugin, "MissingCapsuleHeader", str);
|
||||
|
||||
/* record boot information to system log for future debugging */
|
||||
efibootmgr_path = fu_common_find_program_in_path ("efibootmgr", NULL);
|
||||
if (efibootmgr_path != NULL) {
|
||||
|
@ -28,6 +28,7 @@ struct _FuUefiDevice {
|
||||
FuUefiDeviceStatus last_attempt_status;
|
||||
guint32 last_attempt_version;
|
||||
guint64 fmp_hardware_instance;
|
||||
gboolean missing_header;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE)
|
||||
@ -289,6 +290,63 @@ fu_uefi_device_build_dp_buf (const gchar *path, gsize *bufsz, GError **error)
|
||||
return g_steal_pointer (&dp_buf);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error)
|
||||
{
|
||||
FuUefiDevice *self = FU_UEFI_DEVICE (device);
|
||||
gsize fw_length;
|
||||
efi_guid_t esrt_guid;
|
||||
efi_guid_t payload_guid;
|
||||
const gchar *data = g_bytes_get_data (fw, &fw_length);
|
||||
self->missing_header = FALSE;
|
||||
|
||||
/* convert to EFI GUIDs */
|
||||
if (efi_str_to_guid (fu_uefi_device_get_guid (self), &esrt_guid) < 0) {
|
||||
g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL,
|
||||
"Invalid ESRT GUID");
|
||||
return NULL;
|
||||
}
|
||||
if (fw_length < sizeof(efi_guid_t)) {
|
||||
g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE,
|
||||
"Invalid payload");
|
||||
return NULL;
|
||||
}
|
||||
memcpy (&payload_guid, data, sizeof(efi_guid_t));
|
||||
|
||||
/* ESRT header matches payload */
|
||||
if (efi_guid_cmp (&esrt_guid, &payload_guid) == 0) {
|
||||
g_debug ("ESRT matches payload GUID");
|
||||
return g_bytes_new_from_bytes (fw, 0, fw_length);
|
||||
/* FMP payload */
|
||||
} else if (fu_uefi_device_get_kind (self) == FU_UEFI_DEVICE_KIND_FMP) {
|
||||
g_debug ("performing FMP update");
|
||||
return g_bytes_new_from_bytes (fw, 0, fw_length);
|
||||
/* Missing, add a header */
|
||||
} else {
|
||||
guint header_size = sizeof(efi_capsule_header_t);
|
||||
guint8 *new_data = g_malloc (fw_length + header_size);
|
||||
guint8 *capsule = new_data + header_size;
|
||||
efi_capsule_header_t *header = (efi_capsule_header_t *) new_data;
|
||||
|
||||
g_warning ("missing or invalid embedded capsule header");
|
||||
self->missing_header = TRUE;
|
||||
header->flags = self->capsule_flags;
|
||||
header->header_size = header_size;
|
||||
header->capsule_image_size = fw_length + header_size;
|
||||
memcpy (&header->guid, &esrt_guid, sizeof (efi_guid_t));
|
||||
memcpy (capsule, data, fw_length);
|
||||
|
||||
return g_bytes_new_take (new_data, fw_length + header_size);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_uefi_missing_capsule_header (FuDevice *device)
|
||||
{
|
||||
FuUefiDevice *self = FU_UEFI_DEVICE (device);
|
||||
return self->missing_header;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error)
|
||||
{
|
||||
@ -299,6 +357,7 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error)
|
||||
efi_update_info_t info;
|
||||
gsize datasz = 0;
|
||||
gsize dp_bufsz = 0;
|
||||
g_autoptr(GBytes) fixed_fw = NULL;
|
||||
g_autofree gchar *basename = NULL;
|
||||
g_autofree gchar *directory = NULL;
|
||||
g_autofree gchar *fn = NULL;
|
||||
@ -320,7 +379,10 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error)
|
||||
fn = g_build_filename (directory, "fw", basename, NULL);
|
||||
if (!fu_common_mkdir_parent (fn, error))
|
||||
return FALSE;
|
||||
if (!fu_common_set_contents_bytes (fn, fw, error))
|
||||
fixed_fw = fu_uefi_device_fixup_firmware (device, fw, error);
|
||||
if (fixed_fw == NULL)
|
||||
return FALSE;
|
||||
if (!fu_common_set_contents_bytes (fn, fixed_fw, error))
|
||||
return FALSE;
|
||||
|
||||
/* set the blob header shared with fwupd.efi */
|
||||
|
@ -57,6 +57,7 @@ const gchar *fu_uefi_device_kind_to_string (FuUefiDeviceKind kind);
|
||||
const gchar *fu_uefi_device_status_to_string (FuUefiDeviceStatus status);
|
||||
FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self,
|
||||
GError **error);
|
||||
gboolean fu_uefi_missing_capsule_header (FuDevice *device);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user