mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-03 13:16:01 +00:00
uefi: Use fu_efivar_get_data() to fix setting BootNext correctly
Fixes https://github.com/fwupd/fwupd/issues/2169
This commit is contained in:
parent
43053d2a13
commit
81b5defaa6
@ -322,6 +322,53 @@ fu_efivar_get_data (const gchar *guid, const gchar *name, guint8 **data,
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_efivar_get_names:
|
||||
* @guid: Globally unique identifier
|
||||
* @error: A #GError
|
||||
*
|
||||
* Gets the list of names where the GUID matches. An error is set if there are
|
||||
* no names matching the GUID.
|
||||
*
|
||||
* Returns: (transfer container) (element-type utf8): array of names
|
||||
*
|
||||
* Since: 1.4.7
|
||||
**/
|
||||
GPtrArray *
|
||||
fu_efivar_get_names (const gchar *guid, GError **error)
|
||||
{
|
||||
const gchar *name_guid;
|
||||
g_autofree gchar *path = fu_efivar_get_path ();
|
||||
g_autoptr(GDir) dir = NULL;
|
||||
g_autoptr(GPtrArray) names = g_ptr_array_new_with_free_func (g_free);
|
||||
|
||||
/* find names with matching GUID */
|
||||
dir = g_dir_open (path, 0, error);
|
||||
if (dir == NULL)
|
||||
return NULL;
|
||||
while ((name_guid = g_dir_read_name (dir)) != NULL) {
|
||||
gsize name_guidsz = strlen (name_guid);
|
||||
if (name_guidsz < 38)
|
||||
continue;
|
||||
if (g_strcmp0 (name_guid + name_guidsz - 36, guid) == 0) {
|
||||
g_ptr_array_add (names,
|
||||
g_strndup (name_guid, name_guidsz - 37));
|
||||
}
|
||||
}
|
||||
|
||||
/* nothing found */
|
||||
if (names->len == 0) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_FOUND,
|
||||
"no names for GUID %s", guid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return g_steal_pointer (&names);
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_efivar_set_data:
|
||||
* @guid: Globally unique identifier
|
||||
|
@ -43,5 +43,7 @@ gboolean fu_efivar_delete (const gchar *guid,
|
||||
gboolean fu_efivar_delete_with_glob (const gchar *guid,
|
||||
const gchar *name_glob,
|
||||
GError **error);
|
||||
GPtrArray *fu_efivar_get_names (const gchar *guid,
|
||||
GError **error);
|
||||
gboolean fu_efivar_secure_boot_enabled (void);
|
||||
gboolean fu_efivar_secure_boot_enabled_full(GError **error);
|
||||
|
@ -1808,6 +1808,7 @@ fu_efivar_func (void)
|
||||
guint32 attr = 0;
|
||||
g_autofree guint8 *data = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GPtrArray) names = NULL;
|
||||
|
||||
/* check supported */
|
||||
ret = fu_efivar_supported (&error);
|
||||
@ -1818,6 +1819,12 @@ fu_efivar_func (void)
|
||||
g_assert_false (fu_efivar_exists (FU_EFIVAR_GUID_EFI_GLOBAL, "NotGoingToExist"));
|
||||
g_assert_true (fu_efivar_exists (FU_EFIVAR_GUID_EFI_GLOBAL, "SecureBoot"));
|
||||
|
||||
/* list a few keys */
|
||||
names = fu_efivar_get_names (FU_EFIVAR_GUID_EFI_GLOBAL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (names);
|
||||
g_assert_cmpint (names->len, ==, 2);
|
||||
|
||||
/* write and read a key */
|
||||
ret = fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, "Test",
|
||||
(guint8 *) "1", 1,
|
||||
|
@ -610,6 +610,12 @@ LIBFWUPDPLUGIN_1.4.6 {
|
||||
local: *;
|
||||
} LIBFWUPDPLUGIN_1.4.5;
|
||||
|
||||
LIBFWUPDPLUGIN_1.4.7 {
|
||||
global:
|
||||
fu_efivar_get_names;
|
||||
local: *;
|
||||
} LIBFWUPDPLUGIN_1.4.6;
|
||||
|
||||
LIBFWUPDPLUGIN_1.5.0 {
|
||||
global:
|
||||
fu_common_cpuid;
|
||||
@ -659,4 +665,4 @@ LIBFWUPDPLUGIN_1.5.0 {
|
||||
fu_udev_device_get_subsystem_model;
|
||||
fu_udev_device_get_subsystem_vendor;
|
||||
local: *;
|
||||
} LIBFWUPDPLUGIN_1.4.6;
|
||||
} LIBFWUPDPLUGIN_1.4.7;
|
||||
|
@ -93,23 +93,26 @@ static gboolean
|
||||
fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_size, GError **error)
|
||||
{
|
||||
const gchar *desc;
|
||||
efi_guid_t *guid = NULL;
|
||||
const gchar *name;
|
||||
efi_load_option *loadopt = NULL;
|
||||
gchar *name = NULL;
|
||||
gint rc;
|
||||
gsize var_data_size = 0;
|
||||
guint32 attr;
|
||||
guint16 boot_next = G_MAXUINT16;
|
||||
g_autofree guint8 *var_data = NULL;
|
||||
g_autofree guint8 *set_entries = g_malloc0 (G_MAXUINT16);
|
||||
g_autoptr(GPtrArray) names = NULL;
|
||||
|
||||
while ((rc = efi_get_next_variable_name (&guid, &name)) > 0) {
|
||||
names = fu_efivar_get_names (FU_EFIVAR_GUID_EFI_GLOBAL, error);
|
||||
if (names == NULL)
|
||||
return FALSE;
|
||||
for (guint i = 0; i < names->len; i++) {
|
||||
gint scanned = 0;
|
||||
guint16 entry = 0;
|
||||
g_autofree guint8 *var_data_tmp = NULL;
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
|
||||
if (efi_guid_cmp (guid, &efi_guid_global) != 0)
|
||||
continue;
|
||||
name = g_ptr_array_index (names, i);
|
||||
rc = sscanf (name, "Boot%hX%n", &entry, &scanned);
|
||||
if (rc < 0) {
|
||||
g_set_error (error,
|
||||
@ -126,9 +129,11 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si
|
||||
/* mark this as used */
|
||||
set_entries[entry] = 1;
|
||||
|
||||
rc = efi_get_variable (*guid, name, &var_data_tmp, &var_data_size, &attr);
|
||||
if (rc < 0) {
|
||||
g_debug ("efi_get_variable(%s) failed: %s", name, strerror(rc));
|
||||
if (!fu_efivar_get_data (FU_EFIVAR_GUID_EFI_GLOBAL, name,
|
||||
&var_data_tmp, &var_data_size,
|
||||
&attr, &error_local)) {
|
||||
g_debug ("failed to get data for name %s: %s",
|
||||
name, error_local->message);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -150,13 +155,6 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si
|
||||
efi_error_clear ();
|
||||
break;
|
||||
}
|
||||
if (rc < 0) {
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"failed to find boot variable");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* already exists */
|
||||
if (var_data != NULL) {
|
||||
@ -165,12 +163,10 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si
|
||||
memcmp (var_data, opt, opt_size) != 0) {
|
||||
g_debug ("%s -> '%s' : updating existing boot entry", name, desc);
|
||||
efi_loadopt_attr_set (loadopt, LOAD_OPTION_ACTIVE);
|
||||
rc = efi_set_variable (*guid, name, opt, opt_size, attr, 0644);
|
||||
if (rc < 0) {
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"could not set boot variable active");
|
||||
if (!fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL,
|
||||
name, opt, opt_size, attr, error)) {
|
||||
g_prefix_error (error,
|
||||
"could not set boot variable active: ");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
@ -195,17 +191,15 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si
|
||||
}
|
||||
boot_next_name = g_strdup_printf ("Boot%04X", (guint) boot_next);
|
||||
g_debug ("%s -> creating new entry", boot_next_name);
|
||||
rc = efi_set_variable (efi_guid_global, boot_next_name, opt, opt_size,
|
||||
EFI_VARIABLE_NON_VOLATILE |
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
0644);
|
||||
if (rc < 0) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"could not set boot variable %s: %d",
|
||||
boot_next_name, rc);
|
||||
if (!fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL,
|
||||
boot_next_name, opt, opt_size,
|
||||
FU_EFIVAR_ATTR_NON_VOLATILE |
|
||||
FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS |
|
||||
FU_EFIVAR_ATTR_RUNTIME_ACCESS,
|
||||
error)) {
|
||||
g_prefix_error (error,
|
||||
"could not set boot variable %s: ",
|
||||
boot_next_name);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@ -215,17 +209,15 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si
|
||||
return FALSE;
|
||||
|
||||
/* set the boot next */
|
||||
rc = efi_set_variable (efi_guid_global, "BootNext", (guint8 *)&boot_next, 2,
|
||||
EFI_VARIABLE_NON_VOLATILE |
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
0644);
|
||||
if (rc < 0) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"could not set BootNext(%" G_GUINT16_FORMAT ")",
|
||||
boot_next);
|
||||
if (!fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL,
|
||||
"BootNext", (guint8 *)&boot_next, 2,
|
||||
FU_EFIVAR_ATTR_NON_VOLATILE |
|
||||
FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS |
|
||||
FU_EFIVAR_ATTR_RUNTIME_ACCESS,
|
||||
error)) {
|
||||
g_prefix_error (error,
|
||||
"could not set BootNext(%" G_GUINT16_FORMAT "): ",
|
||||
boot_next);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
Loading…
Reference in New Issue
Block a user