From c28d32f946f0d1c0780a02ab49dc2c1835370501 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Thu, 18 Apr 2024 15:54:50 +0300 Subject: 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 Signed-off-by: Ilias Apalodimas --- lib/efi_loader/efi_runtime.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/efi_loader/efi_runtime.c') diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index a61c9a77b13..dde083b0966 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -127,6 +127,10 @@ efi_status_t efi_init_runtime_supported(void) EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP | EFI_RT_SUPPORTED_CONVERT_POINTER; + if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) + rt_table->runtime_services_supported |= + EFI_RT_SUPPORTED_SET_VARIABLE; + /* * This value must be synced with efi_runtime_detach_list * as well as efi_runtime_services. -- cgit v1.2.3 From bc3dd2493ef8c3c646aaeb3854a3f83558c50102 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Thu, 18 Apr 2024 15:54:51 +0300 Subject: efi_loader: Add OS notifications for SetVariable at runtime Previous patches enable SetVariable at runtime using a volatile storage backend using EFI_RUNTIME_SERVICES_DATA allocared memory. Since there's no recommendation from the spec on how to notify the OS, add a volatile EFI variable that contains the filename relative to the ESP. OS'es can use that file and update it at runtime $~ efivar -p -n b2ac5fc9-92b7-4acd-aeac-11e818c3130c-RTStorageVolatile GUID: b2ac5fc9-92b7-4acd-aeac-11e818c3130c Name: "RTStorageVolatile" Attributes: Boot Service Access Runtime Service Access Value: 00000000 75 62 6f 6f 74 65 66 69 2e 76 61 72 00 |ubootefi.var. | Reviewed-by: Heinrich Schuchardt Signed-off-by: Ilias Apalodimas --- lib/efi_loader/efi_runtime.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'lib/efi_loader/efi_runtime.c') diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index dde083b0966..c8f7a88ba8d 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,7 @@ static __efi_runtime_data efi_uintn_t efi_descriptor_size; */ efi_status_t efi_init_runtime_supported(void) { + const efi_guid_t efi_guid_efi_rt_var_file = U_BOOT_EFI_RT_VAR_FILE_GUID; efi_status_t ret; struct efi_rt_properties_table *rt_table; @@ -127,9 +129,20 @@ efi_status_t efi_init_runtime_supported(void) EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP | EFI_RT_SUPPORTED_CONVERT_POINTER; - if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) - rt_table->runtime_services_supported |= - EFI_RT_SUPPORTED_SET_VARIABLE; + if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) { + ret = efi_set_variable_int(u"RTStorageVolatile", + &efi_guid_efi_rt_var_file, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + sizeof(EFI_VAR_FILE_NAME), + EFI_VAR_FILE_NAME, false); + if (ret != EFI_SUCCESS) { + log_err("Failed to set RTStorageVolatile\n"); + return ret; + } + rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_SET_VARIABLE; + } /* * This value must be synced with efi_runtime_detach_list -- cgit v1.2.3 From 00da8d65a3baea8c3745367bea99b1d76f8f129c Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Thu, 18 Apr 2024 15:54:52 +0300 Subject: efi_loader: add an EFI variable with the file contents Previous patches enabled SetVariableRT using a RAM backend. Although EBBR [0] defines a variable format we can teach userspace tools and write the altered variables, it's better if we skip the ABI requirements completely. So let's add a new variable, in its own namespace called "VarToFile" which contains a binary dump of the updated RT, BS and, NV variables and will be updated when GetVariable is called. Some adjustments are needed to do that. Currently we discard BS-only variables in EBS(). We need to preserve those on the RAM backend that exposes the variables. Since BS-only variables can't appear at runtime we need to move the memory masking checks from efi_var_collect() to efi_get_next_variable_name_mem()/ efi_get_variable_mem() and do the filtering at runtime. We also need an efi_var_collect() variant available at runtime, in order to construct the "VarToFile" buffer on the fly. All users and applications (for linux) have to do when updating a variable is dd that variable in the file described by "RTStorageVolatile". Linux efivarfs uses a first 4 bytes of the output to represent attributes in little-endian format. So, storing variables works like this: $~ efibootmgr -n 0001 $~ dd if=/sys/firmware/efi/efivars/VarToFile-b2ac5fc9-92b7-4acd-aeac-11e818c3130c of=/boot/efi/ubootefi.var skip=4 bs=1 [0] https://arm-software.github.io/ebbr/index.html#document-chapter5-variable-storage Suggested-by: Ard Biesheuvel # dumping all variables to a variable Co-developed-by: Heinrich Schuchardt # contributed on efi_var_collect_mem() Signed-off-by: Heinrich Schuchardt Signed-off-by: Ilias Apalodimas --- lib/efi_loader/efi_runtime.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'lib/efi_loader/efi_runtime.c') diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index c8f7a88ba8d..73831c527e0 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -130,6 +130,8 @@ efi_status_t efi_init_runtime_supported(void) EFI_RT_SUPPORTED_CONVERT_POINTER; if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) { + u8 s = 0; + ret = efi_set_variable_int(u"RTStorageVolatile", &efi_guid_efi_rt_var_file, EFI_VARIABLE_BOOTSERVICE_ACCESS | @@ -141,6 +143,29 @@ efi_status_t efi_init_runtime_supported(void) log_err("Failed to set RTStorageVolatile\n"); return ret; } + /* + * This variable needs to be visible so users can read it, + * but the real contents are going to be filled during + * GetVariable + */ + ret = efi_set_variable_int(u"VarToFile", + &efi_guid_efi_rt_var_file, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + sizeof(s), + &s, false); + if (ret != EFI_SUCCESS) { + log_err("Failed to set VarToFile\n"); + efi_set_variable_int(u"RTStorageVolatile", + &efi_guid_efi_rt_var_file, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + 0, NULL, false); + + return ret; + } rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_SET_VARIABLE; } -- cgit v1.2.3