Skip to content

Conversation

apalos
Copy link
Contributor

@apalos apalos commented Jun 19, 2025

Embedded boards have hardware limitations when storing and managing EFI variables. Some hardware comes with an eMMC & an RPMB partition which they use to store the EFI variables securely. However, the vast majority of boards (using U-Boot), stores the EFI variables in a file in the ESP.

This has a few limitations

  • UEFI secure boot cannot be enabled as it can be very easily overridden
  • SetVariable at runtime is impossible to support

Distros and capsule updates on-disk do rely on the that service though and U-Boot does implement a workaround.

U-Boot enables SetVariableRT in the RTPROP table and creates a memory backend, so the linux kernel can naturally read and write variables via the efivarfs filesystem. Those reads and writes end up in memory though. So they are visible while the OS is live and are lost in the event of a reboot.

At the same time it also creates two EFI RO variables. RTStorageVolatile -- Holds the filename the variables are stored relative to
the ESP
VarToFile -- Holds a binary dump of all the EFI variables that should be
preserved (BS, NV, RT).

By using these two variables we can persist the changes after reboots by doing
dd if=/sys/firmware/efi/efivars/VarToFile-b2ac5fc9-92b7-4acd-aeac-11e818c3130c of=/boot/efi/ubootefi.var skip=4 bs=1

So let's plug this functionality into the efivafs backend and enable it automatically if those variables are detected.

Embedded boards have hardware limitations when storing and managing EFI
variables. Some hardware comes with an eMMC & an RPMB partition which they
use to store the EFI variables securely. However, the vast majority of
boards (using U-Boot), stores the EFI variables in a file in the ESP.

This has a few limitations
- UEFI secure boot cannot be enabled as it can be very easily
  overridden
- SetVariable at runtime is impossible to support

Distros and capsule updates on-disk do rely on the that service though
and U-Boot does implement a workaround.

U-Boot enables SetVariableRT in the RTPROP table and creates a memory backend,
so the linux kernel can naturally read and write variables via the efivarfs
filesystem. Those reads and writes end up in memory though. So they are visible
while the OS is live and are lost in the event of a reboot.

At the same time it also creates two EFI RO variables.
RTStorageVolatile -- Holds the filename  the variables are stored relative to
                     the ESP
VarToFile -- Holds a binary dump of all the EFI variables that should be
             preserved (BS, NV, RT).

By using these two variables we can persist the changes after reboots by
doing
dd if=/sys/firmware/efi/efivars/VarToFile-b2ac5fc9-92b7-4acd-aeac-11e818c3130c of=/boot/efi/ubootefi.var skip=4 bs=1

So let's plug this functionality into the efivafs backend and enable it
automatically if those variables are detected.

Signed-off-by: Ilias Apalodimas <[email protected]>
@apalos
Copy link
Contributor Author

apalos commented Jun 19, 2025

@vathpela I don't know if my testing was sufficient. I compiled efivar and copied over libefivar.so.1. I assume efibootmgr works because I changed the library.

Create a variable with printf "\x07\x00\x00\x00\xab" > myvar-12345678-1234-1234-1234-123456789ab

When U-Boot does not support setvariableRT the functionality seems unchanged

$~ sudo ./src/efivar -w -n 8be4df61-93ca-11d2-aa0d-00e098032b8c-test -f myvar-12345678-1234-1234-1234-123456789ab
efivar: Read-only file system
$~ sudo efibootmgr -n 0001
Could not set BootNext: Read-only file system

With SetVariableRT enabled

Hit any key to stop autoboot:  0
=> printenv -e test
Error: "test" not defined
=>

Boot OS
[....]

$~ sudo ./src/efivar -w -n 8be4df61-93ca-11d2-aa0d-00e098032b8c-test -f myvar-12345678-1234-1234-1234-123456789ab
$ sudo efivar -l 
8be4df61-93ca-11d2-aa0d-00e098032b8c-test
[...]
[...]
$~ sudo efivar -p -n 8be4df61-93ca-11d2-aa0d-00e098032b8c-test
8be4df61-93ca-11d2-aa0d-00e098032b8c-test
GUID: 8be4df61-93ca-11d2-aa0d-00e098032b8c -n 8be4df61-93ca-11d2-aa0d-00e098032b8c-test
Name: "test"
Attributes:
        Non-Volatile
        Boot Service Access
        Runtime Service Access
Value:
00000000  07 00 00 00 ab                                    |.....           |

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

and after the reboot

=> printenv -e test
test:
    8be4df61-93ca-11d2-aa0d-00e098032b8c (EFI_GLOBAL_VARIABLE_GUID)
    NV|BS|RT, DataSize = 0x5
    00000000: 07 00 00 00 ab                                   .....
=> printenv -e BootNext
BootNext:
    8be4df61-93ca-11d2-aa0d-00e098032b8c (EFI_GLOBAL_VARIABLE_GUID)
    NV|BS|RT, DataSize = 0x2
    00000000: 02 00                                            ..
=>

@vathpela vathpela merged commit 68daa04 into rhboot:main Jun 23, 2025
5 checks passed
@obbardc obbardc mentioned this pull request Aug 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants