u-boot/lib/efi_selftest/efi_selftest_variables_runtime.c
Ilias Apalodimas c28d32f946 efi_loader: conditionally enable SetvariableRT
When we store EFI variables on file we don't allow SetVariable at runtime,
since the OS doesn't know how to access or write that file.  At the same
time keeping the U-Boot drivers alive in runtime sections and performing
writes from the firmware is dangerous -- if at all possible.

For GetVariable at runtime we copy runtime variables in RAM and expose them
to the OS. Add a Kconfig option and provide SetVariable at runtime using
the same memory backend. The OS will be responsible for syncing the RAM
contents to the file, otherwise any changes made during runtime won't
persist reboots.

It's worth noting that the variable store format is defined in EBBR [0]
and authenticated variables are explicitly prohibited, since they have
to be stored on a medium that's tamper and rollback protected.

- pre-patch
$~ mount | grep efiva
efivarfs on /sys/firmware/efi/efivars type efivarfs (ro,nosuid,nodev,noexec,relatime)

$~ efibootmgr -n 0001
Could not set BootNext: Read-only file system

- post-patch
$~ mount | grep efiva
efivarfs on /sys/firmware/efi/efivars type efivarfs (rw,nosuid,nodev,noexec,relatime)

$~ efibootmgr -n 0001
BootNext: 0001
BootCurrent: 0000
BootOrder: 0000,0001
Boot0000* debian        HD(1,GPT,bdae5610-3331-4e4d-9466-acb5caf0b4a6,0x800,0x100000)/File(EFI\debian\grubaa64.efi)
Boot0001* virtio 0      VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b,0000000000000000)/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b,850000001f000000)/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b,1600850000000000){auto_created_boot_option}

$~ efivar -p -n 8be4df61-93ca-11d2-aa0d-00e098032b8c-BootNext
GUID: 8be4df61-93ca-11d2-aa0d-00e098032b8c
Name: "BootNext"
Attributes:
        Non-Volatile
        Boot Service Access
        Runtime Service Access
Value:
00000000  01 00

FWTS runtime results
Skipped tests are for SetVariable which is now supported
'Passed' test is for QueryVariableInfo which is not yet supported

Test: UEFI miscellaneous runtime service interface tests.
  Test for UEFI miscellaneous runtime service interfaces  6 skipped
  Stress test for UEFI miscellaneous runtime service i..  1 skipped
  Test GetNextHighMonotonicCount with invalid NULL par..  1 skipped
  Test UEFI miscellaneous runtime services unsupported..  1 passed
Test: UEFI Runtime service variable interface tests.
  Test UEFI RT service get variable interface.            1 passed
  Test UEFI RT service get next variable name interface.  4 passed
  Test UEFI RT service set variable interface.            8 passed
  Test UEFI RT service query variable info interface.     1 skipped
  Test UEFI RT service variable interface stress test.    2 passed
  Test UEFI RT service set variable interface stress t..  4 passed
  Test UEFI RT service query variable info interface s..  1 skipped
  Test UEFI RT service get variable interface, invalid..  5 passed
  Test UEFI RT variable services unsupported status.      1 passed, 3 skipped

[0] https://arm-software.github.io/ebbr/index.html#document-chapter5-variable-storage

Reviewed-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
2024-04-20 08:22:24 +02:00

101 lines
2.6 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* efi_selftest_variables_runtime
*
* Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* This unit test checks the runtime services for variables after
* ExitBootServices():
* GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.
*/
#include <efi_selftest.h>
#define EFI_ST_MAX_DATA_SIZE 16
#define EFI_ST_MAX_VARNAME_SIZE 40
static struct efi_boot_services *boottime;
static struct efi_runtime_services *runtime;
static const efi_guid_t guid_vendor0 = EFI_GLOBAL_VARIABLE_GUID;
/*
* Setup unit test.
*
* @handle handle of the loaded image
* @systable system table
*/
static int setup(const efi_handle_t img_handle,
const struct efi_system_table *systable)
{
boottime = systable->boottime;
runtime = systable->runtime;
return EFI_ST_SUCCESS;
}
/**
* execute() - execute unit test
*
* As runtime support is not implmented expect EFI_UNSUPPORTED to be returned.
*/
static int execute(void)
{
efi_status_t ret;
efi_uintn_t len;
u32 attr;
u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c,
0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,};
u8 data[EFI_ST_MAX_DATA_SIZE];
u16 varname[EFI_ST_MAX_VARNAME_SIZE];
efi_guid_t guid;
u64 max_storage, rem_storage, max_size;
ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS,
&max_storage, &rem_storage,
&max_size);
if (ret != EFI_UNSUPPORTED) {
efi_st_error("QueryVariableInfo failed\n");
return EFI_ST_FAILURE;
}
ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
3, v + 4);
if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
/* At runtime only non-volatile variables may be set. */
if (ret != EFI_INVALID_PARAMETER) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
} else {
if (ret != EFI_UNSUPPORTED) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
}
len = EFI_ST_MAX_DATA_SIZE;
ret = runtime->get_variable(u"PlatformLangCodes", &guid_vendor0,
&attr, &len, data);
if (ret != EFI_SUCCESS) {
efi_st_error("GetVariable failed\n");
return EFI_ST_FAILURE;
}
memset(&guid, 0, 16);
*varname = 0;
len = 2 * EFI_ST_MAX_VARNAME_SIZE;
ret = runtime->get_next_variable_name(&len, varname, &guid);
if (ret != EFI_SUCCESS) {
efi_st_error("GetNextVariableName failed\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
EFI_UNIT_TEST(variables_run) = {
.name = "variables at runtime",
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute,
};