1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-27 01:55:22 +03:00

Merge pull request #33574 from poettering/get-efi-var-raw

efi: efi variable refactoring
This commit is contained in:
Lennart Poettering 2024-07-02 21:16:37 +02:00 committed by GitHub
commit 6f5c8f44f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 319 additions and 299 deletions

View File

@ -7,6 +7,7 @@
#include "devicetree.h"
#include "drivers.h"
#include "efivars-fundamental.h"
#include "efivars.h"
#include "export-vars.h"
#include "graphics.h"
#include "initrd.h"
@ -490,7 +491,7 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
query_screen_resolution(&screen_width, &screen_height);
secure = secure_boot_mode();
(void) efivar_get(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", &device_part_uuid);
(void) efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", &device_part_uuid);
printf(" systemd-boot version: " GIT_VERSION "\n");
if (loaded_image_path)
@ -1104,14 +1105,14 @@ static bool menu_run(
/* Update EFI vars after we left the menu to reduce NVRAM writes. */
if (default_efivar_saved != config->idx_default_efivar)
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderEntryDefault", config->entry_default_efivar, EFI_VARIABLE_NON_VOLATILE);
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryDefault", config->entry_default_efivar, EFI_VARIABLE_NON_VOLATILE);
if (console_mode_efivar_saved != config->console_mode_efivar) {
if (config->console_mode_efivar == CONSOLE_MODE_KEEP)
efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderConfigConsoleMode", EFI_VARIABLE_NON_VOLATILE);
else
efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"LoaderConfigConsoleMode",
config->console_mode_efivar, EFI_VARIABLE_NON_VOLATILE);
efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"LoaderConfigConsoleMode",
config->console_mode_efivar, EFI_VARIABLE_NON_VOLATILE);
}
if (timeout_efivar_saved != config->timeout_sec_efivar) {
@ -1122,15 +1123,15 @@ static bool menu_run(
case TIMEOUT_MENU_DISABLED:
assert_not_reached();
case TIMEOUT_MENU_FORCE:
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout", u"menu-force", EFI_VARIABLE_NON_VOLATILE);
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout", u"menu-force", EFI_VARIABLE_NON_VOLATILE);
break;
case TIMEOUT_MENU_HIDDEN:
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout", u"menu-hidden", EFI_VARIABLE_NON_VOLATILE);
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout", u"menu-hidden", EFI_VARIABLE_NON_VOLATILE);
break;
default:
assert(config->timeout_sec_efivar < UINT32_MAX);
efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout",
config->timeout_sec_efivar, EFI_VARIABLE_NON_VOLATILE);
efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout",
config->timeout_sec_efivar, EFI_VARIABLE_NON_VOLATILE);
}
}
@ -1396,7 +1397,7 @@ static EFI_STATUS boot_entry_bump_counters(BootEntry *entry) {
/* Let's tell the OS that we renamed this file, so that it knows what to rename to the counter-less name on
* success */
new_path = xasprintf("%ls\\%ls", entry->path, entry->next_name);
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderBootCountPath", new_path, 0);
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderBootCountPath", new_path, 0);
/* If the file we just renamed is the loader path, then let's update that. */
if (streq16(entry->loader, old_path)) {
@ -1526,7 +1527,7 @@ static EFI_STATUS efivar_get_timeout(const char16_t *var, uint64_t *ret_value) {
assert(var);
assert(ret_value);
err = efivar_get(MAKE_GUID_PTR(LOADER), var, &value);
err = efivar_get_str16(MAKE_GUID_PTR(LOADER), var, &value);
if (err != EFI_SUCCESS)
return err;
@ -1553,7 +1554,7 @@ static EFI_STATUS efivar_get_timeout(const char16_t *var, uint64_t *ret_value) {
static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
_cleanup_free_ char *content = NULL;
size_t content_size, value = 0; /* avoid false maybe-uninitialized warning */
size_t content_size;
EFI_STATUS err;
assert(root_dir);
@ -1602,16 +1603,17 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
} else if (err != EFI_NOT_FOUND)
log_error_status(err, "Error reading LoaderConfigTimeoutOneShot EFI variable: %m");
err = efivar_get_uint_string(MAKE_GUID_PTR(LOADER), u"LoaderConfigConsoleMode", &value);
if (err == EFI_SUCCESS)
uint64_t value;
err = efivar_get_uint64_str16(MAKE_GUID_PTR(LOADER), u"LoaderConfigConsoleMode", &value);
if (err == EFI_SUCCESS && value <= INT64_MAX)
config->console_mode_efivar = value;
err = efivar_get(MAKE_GUID_PTR(LOADER), u"LoaderEntryOneShot", &config->entry_oneshot);
err = efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryOneShot", &config->entry_oneshot);
if (err == EFI_SUCCESS)
/* Unset variable now, after all it's "one shot". */
(void) efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderEntryOneShot", EFI_VARIABLE_NON_VOLATILE);
(void) efivar_get(MAKE_GUID_PTR(LOADER), u"LoaderEntryDefault", &config->entry_default_efivar);
(void) efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryDefault", &config->entry_default_efivar);
strtolower16(config->entry_default_config);
strtolower16(config->entry_default_efivar);
@ -1621,7 +1623,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
config->use_saved_entry = streq16(config->entry_default_config, u"@saved");
config->use_saved_entry_efivar = streq16(config->entry_default_efivar, u"@saved");
if (config->use_saved_entry || config->use_saved_entry_efivar)
(void) efivar_get(MAKE_GUID_PTR(LOADER), u"LoaderEntryLastBooted", &config->entry_saved);
(void) efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryLastBooted", &config->entry_saved);
}
static void config_load_type1_entries(
@ -2014,7 +2016,7 @@ static EFI_STATUS boot_windows_bitlocker(void) {
/* There can be gaps in Boot#### entries. Instead of iterating over the full
* EFI var list or uint16_t namespace, just look for "Windows Boot Manager" in BootOrder. */
err = efivar_get_raw(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"BootOrder", (char **) &boot_order, &boot_order_size);
err = efivar_get_raw(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"BootOrder", (void**) &boot_order, &boot_order_size);
if (err != EFI_SUCCESS || boot_order_size % sizeof(uint16_t) != 0)
return err;
@ -2023,7 +2025,7 @@ static EFI_STATUS boot_windows_bitlocker(void) {
size_t buf_size;
_cleanup_free_ char16_t *name = xasprintf("Boot%04x", boot_order[i]);
err = efivar_get_raw(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), name, &buf, &buf_size);
err = efivar_get_raw(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), name, (void**) &buf, &buf_size);
if (err != EFI_SUCCESS)
continue;
@ -2472,7 +2474,7 @@ static void save_selected_entry(const Config *config, const BootEntry *entry) {
assert(entry->loader || !entry->call);
/* Always export the selected boot entry to the system in a volatile var. */
(void) efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderEntrySelected", entry->id, 0);
(void) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntrySelected", entry->id, 0);
/* Do not save or delete if this was a oneshot boot. */
if (streq16(config->entry_oneshot, entry->id))
@ -2483,7 +2485,7 @@ static void save_selected_entry(const Config *config, const BootEntry *entry) {
if (streq16(config->entry_saved, entry->id))
return;
(void) efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderEntryLastBooted", entry->id, EFI_VARIABLE_NON_VOLATILE);
(void) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryLastBooted", entry->id, EFI_VARIABLE_NON_VOLATILE);
} else
/* Delete the non-volatile var if not needed. */
(void) efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderEntryLastBooted", EFI_VARIABLE_NON_VOLATILE);
@ -2563,7 +2565,7 @@ static void export_loader_variables(
assert(loaded_image);
(void) efivar_set_time_usec(MAKE_GUID_PTR(LOADER), u"LoaderTimeInitUSec", init_usec);
(void) efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderInfo", u"systemd-boot " GIT_VERSION, 0);
(void) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderInfo", u"systemd-boot " GIT_VERSION, 0);
(void) efivar_set_uint64_le(MAKE_GUID_PTR(LOADER), u"LoaderFeatures", loader_features, 0);
}

247
src/boot/efi/efivars.c Normal file
View File

@ -0,0 +1,247 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "efi-string.h"
#include "efivars.h"
#include "ticks.h"
#include "util.h"
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags) {
assert(vendor);
assert(name);
assert(buf || size == 0);
flags |= EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
return RT->SetVariable((char16_t *) name, (EFI_GUID *) vendor, flags, size, (void *) buf);
}
EFI_STATUS efivar_set_str16(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags) {
assert(vendor);
assert(name);
return efivar_set_raw(vendor, name, value, value ? strsize16(value) : 0, flags);
}
EFI_STATUS efivar_set_uint64_str16(const EFI_GUID *vendor, const char16_t *name, uint64_t i, uint32_t flags) {
assert(vendor);
assert(name);
_cleanup_free_ char16_t *str = xasprintf("%" PRIu64, i);
return efivar_set_str16(vendor, name, str, flags);
}
EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t value, uint32_t flags) {
uint8_t buf[4];
assert(vendor);
assert(name);
buf[0] = (uint8_t)(value >> 0U & 0xFF);
buf[1] = (uint8_t)(value >> 8U & 0xFF);
buf[2] = (uint8_t)(value >> 16U & 0xFF);
buf[3] = (uint8_t)(value >> 24U & 0xFF);
return efivar_set_raw(vendor, name, buf, sizeof(buf), flags);
}
EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags) {
uint8_t buf[8];
assert(vendor);
assert(name);
buf[0] = (uint8_t)(value >> 0U & 0xFF);
buf[1] = (uint8_t)(value >> 8U & 0xFF);
buf[2] = (uint8_t)(value >> 16U & 0xFF);
buf[3] = (uint8_t)(value >> 24U & 0xFF);
buf[4] = (uint8_t)(value >> 32U & 0xFF);
buf[5] = (uint8_t)(value >> 40U & 0xFF);
buf[6] = (uint8_t)(value >> 48U & 0xFF);
buf[7] = (uint8_t)(value >> 56U & 0xFF);
return efivar_set_raw(vendor, name, buf, sizeof(buf), flags);
}
EFI_STATUS efivar_unset(const EFI_GUID *vendor, const char16_t *name, uint32_t flags) {
EFI_STATUS err;
assert(vendor);
assert(name);
/* We could be wiping a non-volatile variable here and the spec makes no guarantees that won't incur
* in an extra write (and thus wear out). So check and clear only if needed. */
err = efivar_get_raw(vendor, name, NULL, NULL);
if (err == EFI_SUCCESS)
return efivar_set_raw(vendor, name, NULL, 0, flags);
return err;
}
EFI_STATUS efivar_get_str16(const EFI_GUID *vendor, const char16_t *name, char16_t **ret) {
_cleanup_free_ char16_t *buf = NULL;
EFI_STATUS err;
char16_t *val;
size_t size;
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, (void**) &buf, &size);
if (err != EFI_SUCCESS)
return err;
/* Make sure there are no incomplete characters in the buffer */
if ((size % sizeof(char16_t)) != 0)
return EFI_INVALID_PARAMETER;
if (!ret)
return EFI_SUCCESS;
/* Return buffer directly if it happens to be NUL terminated already */
if (size >= sizeof(char16_t) && buf[size / sizeof(char16_t) - 1] == 0) {
*ret = TAKE_PTR(buf);
return EFI_SUCCESS;
}
/* Make sure a terminating NUL is available at the end */
val = xmalloc(size + sizeof(char16_t));
memcpy(val, buf, size);
val[size / sizeof(char16_t) - 1] = 0; /* NUL terminate */
*ret = val;
return EFI_SUCCESS;
}
EFI_STATUS efivar_get_uint64_str16(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret) {
EFI_STATUS err;
assert(vendor);
assert(name);
_cleanup_free_ char16_t *val = NULL;
err = efivar_get_str16(vendor, name, &val);
if (err != EFI_SUCCESS)
return err;
uint64_t u;
if (!parse_number16(val, &u, NULL))
return EFI_INVALID_PARAMETER;
if (ret)
*ret = u;
return EFI_SUCCESS;
}
EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret) {
_cleanup_free_ uint8_t *buf = NULL;
size_t size;
EFI_STATUS err;
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, (void**) &buf, &size);
if (err != EFI_SUCCESS)
return err;
if (size != sizeof(uint32_t))
return EFI_BUFFER_TOO_SMALL;
if (ret)
*ret = (uint32_t) buf[0] << 0U | (uint32_t) buf[1] << 8U | (uint32_t) buf[2] << 16U |
(uint32_t) buf[3] << 24U;
return EFI_SUCCESS;
}
EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret) {
_cleanup_free_ uint8_t *buf = NULL;
size_t size;
EFI_STATUS err;
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, (void**) &buf, &size);
if (err != EFI_SUCCESS)
return err;
if (size != sizeof(uint64_t))
return EFI_BUFFER_TOO_SMALL;
if (ret)
*ret = (uint64_t) buf[0] << 0U | (uint64_t) buf[1] << 8U | (uint64_t) buf[2] << 16U |
(uint64_t) buf[3] << 24U | (uint64_t) buf[4] << 32U | (uint64_t) buf[5] << 40U |
(uint64_t) buf[6] << 48U | (uint64_t) buf[7] << 56U;
return EFI_SUCCESS;
}
EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, void **ret, size_t *ret_size) {
EFI_STATUS err;
assert(vendor);
assert(name);
size_t size = 0;
err = RT->GetVariable((char16_t *) name, (EFI_GUID *) vendor, NULL, &size, NULL);
if (err != EFI_BUFFER_TOO_SMALL)
return err;
_cleanup_free_ void *buf = xmalloc(size);
err = RT->GetVariable((char16_t *) name, (EFI_GUID *) vendor, NULL, &size, buf);
if (err != EFI_SUCCESS)
return err;
if (ret)
*ret = TAKE_PTR(buf);
if (ret_size)
*ret_size = size;
return EFI_SUCCESS;
}
EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret) {
_cleanup_free_ uint8_t *b = NULL;
size_t size;
EFI_STATUS err;
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, (void**) &b, &size);
if (err != EFI_SUCCESS)
return err;
if (ret)
*ret = *b > 0;
return EFI_SUCCESS;
}
void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec) {
assert(vendor);
assert(name);
if (usec == 0)
usec = time_usec();
if (usec == 0)
return;
_cleanup_free_ char16_t *str = xasprintf("%" PRIu64, usec);
efivar_set_str16(vendor, name, str, 0);
}
uint64_t get_os_indications_supported(void) {
uint64_t osind;
EFI_STATUS err;
/* Returns the supported OS indications. If we can't acquire it, returns a zeroed out mask, i.e. no
* supported features. */
err = efivar_get_uint64_le(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"OsIndicationsSupported", &osind);
if (err != EFI_SUCCESS)
return 0;
return osind;
}

30
src/boot/efi/efivars.h Normal file
View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "efi.h"
/*
* Allocated random UUID, intended to be shared across tools that implement
* the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the
* associated EFI variables.
*/
#define LOADER_GUID \
{ 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } }
EFI_STATUS efivar_set_str16(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags);
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags);
EFI_STATUS efivar_set_uint64_str16(const EFI_GUID *vendor, const char16_t *name, uint64_t i, uint32_t flags);
EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t value, uint32_t flags);
EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags);
void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec);
EFI_STATUS efivar_unset(const EFI_GUID *vendor, const char16_t *name, uint32_t flags);
EFI_STATUS efivar_get_str16(const EFI_GUID *vendor, const char16_t *name, char16_t **ret);
EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, void **ret, size_t *ret_size);
EFI_STATUS efivar_get_uint64_str16(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret);
EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret);
EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret);
EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret);
uint64_t get_os_indications_supported(void);

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "device-path-util.h"
#include "efivars.h"
#include "export-vars.h"
#include "part-discovery.h"
#include "util.h"
@ -12,7 +13,7 @@ void export_common_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", NULL, NULL) != EFI_SUCCESS) {
_cleanup_free_ char16_t *uuid = disk_get_part_uuid(loaded_image->DeviceHandle);
if (uuid)
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", uuid, 0);
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", uuid, 0);
}
/* If LoaderImageIdentifier is not set, assume the image with this stub was loaded directly from the
@ -25,20 +26,20 @@ void export_common_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
loaded_image->FilePath) {
_cleanup_free_ char16_t *s = NULL;
if (device_path_to_str(loaded_image->FilePath, &s) == EFI_SUCCESS)
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderImageIdentifier", s, 0);
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderImageIdentifier", s, 0);
}
/* if LoaderFirmwareInfo is not set, let's set it */
if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", NULL, NULL) != EFI_SUCCESS) {
_cleanup_free_ char16_t *s = NULL;
s = xasprintf("%ls %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", s, 0);
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", s, 0);
}
/* ditto for LoaderFirmwareType */
if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", NULL, NULL) != EFI_SUCCESS) {
_cleanup_free_ char16_t *s = NULL;
s = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", s, 0);
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", s, 0);
}
}

View File

@ -258,6 +258,7 @@ libefi_sources = files(
'devicetree.c',
'drivers.c',
'efi-string.c',
'efivars.c',
'export-vars.c',
'graphics.c',
'initrd.c',

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "efivars.h"
#include "memory-util-fundamental.h"
#include "proto/rng.h"
#include "random-seed.h"
@ -55,7 +56,7 @@ static EFI_STATUS acquire_system_token(void **ret, size_t *ret_size) {
assert(ret);
assert(ret_size);
err = efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderSystemToken", &data, &size);
err = efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderSystemToken", (void**) &data, &size);
if (err != EFI_SUCCESS) {
if (err != EFI_NOT_FOUND)
log_error_status(err, "Failed to read LoaderSystemToken EFI variable: %m");

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "console.h"
#include "efivars.h"
#include "proto/security-arch.h"
#include "secure-boot.h"
#include "util.h"

View File

@ -9,6 +9,7 @@
*/
#include "device-path-util.h"
#include "efivars.h"
#include "secure-boot.h"
#include "shim.h"
#include "util.h"

View File

@ -3,6 +3,7 @@
#include "cpio.h"
#include "device-path-util.h"
#include "devicetree.h"
#include "efivars.h"
#include "export-vars.h"
#include "graphics.h"
#include "iovec-util-fundamental.h"
@ -156,7 +157,7 @@ static void export_stub_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
/* add StubInfo (this is one is owned by the stub, hence we unconditionally override this with our
* own data) */
(void) efivar_set(MAKE_GUID_PTR(LOADER), u"StubInfo", u"systemd-stub " GIT_VERSION, 0);
(void) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"StubInfo", u"systemd-stub " GIT_VERSION, 0);
(void) efivar_set_uint64_le(MAKE_GUID_PTR(LOADER), u"StubFeatures", stub_features, 0);
}
@ -745,13 +746,13 @@ static void export_pcr_variables(
* successfully, and encode in it which PCR was used. */
if (sections_measured > 0)
(void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelImage", TPM2_PCR_KERNEL_BOOT, 0);
(void) efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"StubPcrKernelImage", TPM2_PCR_KERNEL_BOOT, 0);
if (parameters_measured > 0)
(void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelParameters", TPM2_PCR_KERNEL_CONFIG, 0);
(void) efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"StubPcrKernelParameters", TPM2_PCR_KERNEL_CONFIG, 0);
if (sysext_measured > 0)
(void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDSysExts", TPM2_PCR_SYSEXTS, 0);
(void) efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDSysExts", TPM2_PCR_SYSEXTS, 0);
if (confext_measured > 0)
(void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDConfExts", TPM2_PCR_KERNEL_CONFIG, 0);
(void) efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDConfExts", TPM2_PCR_KERNEL_CONFIG, 0);
}
static void install_embedded_devicetree(

View File

@ -7,233 +7,7 @@
#include "ticks.h"
#include "util.h"
#include "version.h"
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags) {
assert(vendor);
assert(name);
assert(buf || size == 0);
flags |= EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
return RT->SetVariable((char16_t *) name, (EFI_GUID *) vendor, flags, size, (void *) buf);
}
EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags) {
assert(vendor);
assert(name);
return efivar_set_raw(vendor, name, value, value ? strsize16(value) : 0, flags);
}
EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t i, uint32_t flags) {
assert(vendor);
assert(name);
_cleanup_free_ char16_t *str = xasprintf("%zu", i);
return efivar_set(vendor, name, str, flags);
}
EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t value, uint32_t flags) {
uint8_t buf[4];
assert(vendor);
assert(name);
buf[0] = (uint8_t)(value >> 0U & 0xFF);
buf[1] = (uint8_t)(value >> 8U & 0xFF);
buf[2] = (uint8_t)(value >> 16U & 0xFF);
buf[3] = (uint8_t)(value >> 24U & 0xFF);
return efivar_set_raw(vendor, name, buf, sizeof(buf), flags);
}
EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags) {
uint8_t buf[8];
assert(vendor);
assert(name);
buf[0] = (uint8_t)(value >> 0U & 0xFF);
buf[1] = (uint8_t)(value >> 8U & 0xFF);
buf[2] = (uint8_t)(value >> 16U & 0xFF);
buf[3] = (uint8_t)(value >> 24U & 0xFF);
buf[4] = (uint8_t)(value >> 32U & 0xFF);
buf[5] = (uint8_t)(value >> 40U & 0xFF);
buf[6] = (uint8_t)(value >> 48U & 0xFF);
buf[7] = (uint8_t)(value >> 56U & 0xFF);
return efivar_set_raw(vendor, name, buf, sizeof(buf), flags);
}
EFI_STATUS efivar_unset(const EFI_GUID *vendor, const char16_t *name, uint32_t flags) {
EFI_STATUS err;
assert(vendor);
assert(name);
/* We could be wiping a non-volatile variable here and the spec makes no guarantees that won't incur
* in an extra write (and thus wear out). So check and clear only if needed. */
err = efivar_get_raw(vendor, name, NULL, NULL);
if (err == EFI_SUCCESS)
return efivar_set_raw(vendor, name, NULL, 0, flags);
return err;
}
EFI_STATUS efivar_get(const EFI_GUID *vendor, const char16_t *name, char16_t **ret) {
_cleanup_free_ char16_t *buf = NULL;
EFI_STATUS err;
char16_t *val;
size_t size;
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, (char **) &buf, &size);
if (err != EFI_SUCCESS)
return err;
/* Make sure there are no incomplete characters in the buffer */
if ((size % sizeof(char16_t)) != 0)
return EFI_INVALID_PARAMETER;
if (!ret)
return EFI_SUCCESS;
/* Return buffer directly if it happens to be NUL terminated already */
if (size >= sizeof(char16_t) && buf[size / sizeof(char16_t) - 1] == 0) {
*ret = TAKE_PTR(buf);
return EFI_SUCCESS;
}
/* Make sure a terminating NUL is available at the end */
val = xmalloc(size + sizeof(char16_t));
memcpy(val, buf, size);
val[size / sizeof(char16_t) - 1] = 0; /* NUL terminate */
*ret = val;
return EFI_SUCCESS;
}
EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t *ret) {
_cleanup_free_ char16_t *val = NULL;
EFI_STATUS err;
uint64_t u;
assert(vendor);
assert(name);
err = efivar_get(vendor, name, &val);
if (err != EFI_SUCCESS)
return err;
if (!parse_number16(val, &u, NULL) || u > SIZE_MAX)
return EFI_INVALID_PARAMETER;
if (ret)
*ret = u;
return EFI_SUCCESS;
}
EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret) {
_cleanup_free_ char *buf = NULL;
size_t size;
EFI_STATUS err;
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, &buf, &size);
if (err != EFI_SUCCESS)
return err;
if (size != sizeof(uint32_t))
return EFI_BUFFER_TOO_SMALL;
if (ret)
*ret = (uint32_t) buf[0] << 0U | (uint32_t) buf[1] << 8U | (uint32_t) buf[2] << 16U |
(uint32_t) buf[3] << 24U;
return EFI_SUCCESS;
}
EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret) {
_cleanup_free_ char *buf = NULL;
size_t size;
EFI_STATUS err;
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, &buf, &size);
if (err != EFI_SUCCESS)
return err;
if (size != sizeof(uint64_t))
return EFI_BUFFER_TOO_SMALL;
if (ret)
*ret = (uint64_t) buf[0] << 0U | (uint64_t) buf[1] << 8U | (uint64_t) buf[2] << 16U |
(uint64_t) buf[3] << 24U | (uint64_t) buf[4] << 32U | (uint64_t) buf[5] << 40U |
(uint64_t) buf[6] << 48U | (uint64_t) buf[7] << 56U;
return EFI_SUCCESS;
}
EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, char **ret, size_t *ret_size) {
EFI_STATUS err;
assert(vendor);
assert(name);
size_t size = 0;
err = RT->GetVariable((char16_t *) name, (EFI_GUID *) vendor, NULL, &size, NULL);
if (err != EFI_BUFFER_TOO_SMALL)
return err;
_cleanup_free_ void *buf = xmalloc(size);
err = RT->GetVariable((char16_t *) name, (EFI_GUID *) vendor, NULL, &size, buf);
if (err != EFI_SUCCESS)
return err;
if (ret)
*ret = TAKE_PTR(buf);
if (ret_size)
*ret_size = size;
return EFI_SUCCESS;
}
EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret) {
_cleanup_free_ char *b = NULL;
size_t size;
EFI_STATUS err;
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, &b, &size);
if (err != EFI_SUCCESS)
return err;
if (ret)
*ret = *b > 0;
return EFI_SUCCESS;
}
void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec) {
assert(vendor);
assert(name);
if (usec == 0)
usec = time_usec();
if (usec == 0)
return;
_cleanup_free_ char16_t *str = xasprintf("%" PRIu64, usec);
efivar_set(vendor, name, str, 0);
}
#include "efivars.h"
void convert_efi_path(char16_t *path) {
assert(path);
@ -544,20 +318,6 @@ EFI_STATUS open_directory(
return EFI_SUCCESS;
}
uint64_t get_os_indications_supported(void) {
uint64_t osind;
EFI_STATUS err;
/* Returns the supported OS indications. If we can't acquire it, returns a zeroed out mask, i.e. no
* supported features. */
err = efivar_get_uint64_le(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"OsIndicationsSupported", &osind);
if (err != EFI_SUCCESS)
return 0;
return osind;
}
__attribute__((noinline)) void notify_debugger(const char *identity, volatile bool wait) {
#ifdef EFI_DEBUG
printf("%s@%p %s\n", identity, __executable_start, GIT_VERSION);

View File

@ -81,22 +81,6 @@ static inline Pages xmalloc_pages(
};
}
EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags);
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags);
EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t i, uint32_t flags);
EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t value, uint32_t flags);
EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags);
void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec);
EFI_STATUS efivar_unset(const EFI_GUID *vendor, const char16_t *name, uint32_t flags);
EFI_STATUS efivar_get(const EFI_GUID *vendor, const char16_t *name, char16_t **ret);
EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, char **ret, size_t *ret_size);
EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t *ret);
EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret);
EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret);
EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret);
void convert_efi_path(char16_t *path);
char16_t *xstr8_to_path(const char *stra);
char16_t *mangle_stub_cmdline(char16_t *cmdline);
@ -116,14 +100,6 @@ static inline void unload_imagep(EFI_HANDLE *image) {
(void) BS->UnloadImage(*image);
}
/*
* Allocated random UUID, intended to be shared across tools that implement
* the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the
* associated EFI variables.
*/
#define LOADER_GUID \
{ 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } }
/* Note that GUID is evaluated multiple times! */
#define GUID_FORMAT_STR "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"
#define GUID_FORMAT_VAL(g) (g).Data1, (g).Data2, (g).Data3, (g).Data4[0], (g).Data4[1], \
@ -162,8 +138,6 @@ static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) {
return (void *) (uintptr_t) addr;
}
uint64_t get_os_indications_supported(void);
/* If EFI_DEBUG, print our name and version and also report the address of the image base so a debugger can
* be attached. See debug-sd-boot.sh for how this can be done. */
void notify_debugger(const char *identity, bool wait);

View File

@ -8,6 +8,7 @@
#include "device-path-util.h"
#include "drivers.h"
#include "efi-string.h"
#include "efivars.h"
#include "proto/device-path.h"
#include "string-util-fundamental.h"
#include "util.h"
@ -80,7 +81,7 @@ EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir) {
_cleanup_free_ EFI_DEVICE_PATH *dp = NULL;
_cleanup_free_ char16_t *order_str = xasprintf("VMMBootOrder%04zx", order);
dp_err = efivar_get_raw(MAKE_GUID_PTR(VMM_BOOT_ORDER), order_str, (char **) &dp, NULL);
dp_err = efivar_get_raw(MAKE_GUID_PTR(VMM_BOOT_ORDER), order_str, (void**) &dp, NULL);
for (size_t i = 0; i < n_handles; i++) {
_cleanup_(file_closep) EFI_FILE *root_dir = NULL, *efi_dir = NULL;