mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-14 07:09:57 +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;
|
struct tpm_status tpm_out;
|
||||||
g_autoptr(FuPlugin) plugin_dell = NULL;
|
g_autoptr(FuPlugin) plugin_dell = NULL;
|
||||||
g_autoptr(FuPlugin) plugin_uefi = 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(GError) error = NULL;
|
||||||
g_autoptr(GPtrArray) devices = NULL;
|
g_autoptr(GPtrArray) devices = NULL;
|
||||||
|
|
||||||
@ -244,8 +244,11 @@ fu_plugin_dell_tpm_func (void)
|
|||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
|
|
||||||
/* test override */
|
/* 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,
|
ret = fu_plugin_runner_update (plugin_uefi, device_v20, NULL, blob_fw,
|
||||||
FWUPD_INSTALL_FLAG_FORCE, &error);
|
FWUPD_INSTALL_FLAG_FORCE, &error);
|
||||||
|
g_test_assert_expected_messages ();
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert (ret);
|
g_assert (ret);
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,6 @@ EFI_GUID fwupdate_guid =
|
|||||||
{0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}};
|
{0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}};
|
||||||
EFI_GUID ux_capsule_guid =
|
EFI_GUID ux_capsule_guid =
|
||||||
{0x3b8c8162,0x188c,0x46a4,{0xae,0xc9,0xbe,0x43,0xf1,0xd6,0x56,0x97}};
|
{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;
|
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_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
|
static EFI_STATUS
|
||||||
add_capsule(update_table *update, EFI_CAPSULE_HEADER **capsule_out,
|
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"updates guid: %g\n", &update->info->guid);
|
||||||
dprint(L"File guid: %g\n", fbuf);
|
dprint(L"File guid: %g\n", fbuf);
|
||||||
|
|
||||||
/*
|
cbd_len = fsize;
|
||||||
* See if it has the capsule header, and if not, add one.
|
cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf;
|
||||||
*
|
capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf;
|
||||||
* Unfortunately there's not a good way to do this, so we're just
|
if (!cap_out->Flags && !is_ux_capsule(&update->info->guid)) {
|
||||||
* 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)) {
|
|
||||||
#if defined(__aarch64__)
|
#if defined(__aarch64__)
|
||||||
cap_out->Flags |= update->info->capsule_flags;
|
cap_out->Flags |= update->info->capsule_flags;
|
||||||
#else
|
#else
|
||||||
cap_out->Flags |= update->info->capsule_flags |
|
cap_out->Flags |= update->info->capsule_flags |
|
||||||
CAPSULE_FLAGS_PERSIST_ACROSS_RESET |
|
CAPSULE_FLAGS_PERSIST_ACROSS_RESET |
|
||||||
CAPSULE_FLAGS_INITIATE_RESET;
|
CAPSULE_FLAGS_INITIATE_RESET;
|
||||||
#endif
|
#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)) {
|
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))
|
if (!fu_device_write_firmware (device, blob_fw, error))
|
||||||
return FALSE;
|
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 */
|
/* record boot information to system log for future debugging */
|
||||||
efibootmgr_path = fu_common_find_program_in_path ("efibootmgr", NULL);
|
efibootmgr_path = fu_common_find_program_in_path ("efibootmgr", NULL);
|
||||||
if (efibootmgr_path != NULL) {
|
if (efibootmgr_path != NULL) {
|
||||||
|
@ -28,6 +28,7 @@ struct _FuUefiDevice {
|
|||||||
FuUefiDeviceStatus last_attempt_status;
|
FuUefiDeviceStatus last_attempt_status;
|
||||||
guint32 last_attempt_version;
|
guint32 last_attempt_version;
|
||||||
guint64 fmp_hardware_instance;
|
guint64 fmp_hardware_instance;
|
||||||
|
gboolean missing_header;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE)
|
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);
|
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
|
static gboolean
|
||||||
fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error)
|
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;
|
efi_update_info_t info;
|
||||||
gsize datasz = 0;
|
gsize datasz = 0;
|
||||||
gsize dp_bufsz = 0;
|
gsize dp_bufsz = 0;
|
||||||
|
g_autoptr(GBytes) fixed_fw = NULL;
|
||||||
g_autofree gchar *basename = NULL;
|
g_autofree gchar *basename = NULL;
|
||||||
g_autofree gchar *directory = NULL;
|
g_autofree gchar *directory = NULL;
|
||||||
g_autofree gchar *fn = 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);
|
fn = g_build_filename (directory, "fw", basename, NULL);
|
||||||
if (!fu_common_mkdir_parent (fn, error))
|
if (!fu_common_mkdir_parent (fn, error))
|
||||||
return FALSE;
|
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;
|
return FALSE;
|
||||||
|
|
||||||
/* set the blob header shared with fwupd.efi */
|
/* 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);
|
const gchar *fu_uefi_device_status_to_string (FuUefiDeviceStatus status);
|
||||||
FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self,
|
FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
gboolean fu_uefi_missing_capsule_header (FuDevice *device);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user