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 <ardb@kernel.org> # dumping all variables to a variable
Co-developed-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com> # contributed on efi_var_collect_mem()
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
This commit is contained in:
Ilias Apalodimas
2024-04-18 15:54:52 +03:00
committed by Heinrich Schuchardt
parent bc3dd2493e
commit 00da8d65a3
7 changed files with 146 additions and 65 deletions

View File

@@ -271,13 +271,16 @@ const efi_guid_t *efi_auth_var_get_guid(const u16 *name);
*
* @variable_name_size: size of variable_name buffer in bytes
* @variable_name: name of uefi variable's name in u16
* @mask: bitmask with required attributes of variables to be collected.
* variables are only collected if all of the required
* attributes match. Use 0 to skip matching
* @vendor: vendor's guid
*
* Return: status code
*/
efi_status_t __efi_runtime
efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_name,
efi_guid_t *vendor);
efi_guid_t *vendor, u32 mask);
/**
* efi_get_variable_mem() - Runtime common code across efi variable
* implementations for GetVariable() from
@@ -289,12 +292,15 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_na
* @data_size: size of the buffer to which the variable value is copied
* @data: buffer to which the variable value is copied
* @timep: authentication time (seconds since start of epoch)
* @mask: bitmask with required attributes of variables to be collected.
* variables are only collected if all of the required
* attributes match. Use 0 to skip matching
* Return: status code
*/
efi_status_t __efi_runtime
efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size, void *data,
u64 *timep);
u64 *timep, u32 mask);
/**
* efi_get_variable_runtime() - runtime implementation of GetVariable()
@@ -334,4 +340,10 @@ efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
*/
void efi_var_buf_update(struct efi_var_file *var_buf);
efi_status_t __efi_runtime efi_var_collect_mem(struct efi_var_file *buf,
efi_uintn_t *lenp,
u32 check_attr_mask);
u32 efi_var_entry_len(struct efi_var_entry *var);
#endif