[PATCH v1 3/4] efi_loader: add an EFI variable with the variable file contents
Ilias Apalodimas
ilias.apalodimas at linaro.org
Mon Apr 8 11:40:53 CEST 2024
On Mon, 8 Apr 2024 at 11:29, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
>
> On 4/8/24 10:12, Ilias Apalodimas wrote:
> > Hi Heinrich
> >
> > On Mon, 8 Apr 2024 at 09:41, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
> >>
> >> On 4/6/24 16:01, Ilias Apalodimas wrote:
> >>> 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.
> >>>
> >>> Some adjustments are needed to do that. Currently we discard BS-only
> >>> variables in EBS(). We need to preserve those on the OS RAM backend
> >>> that exposes the variables. Since BS-only variables can't appear at RT
> >>> 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 to make efi_var_collect() available
> >>> at runtime, in order to construct the "VarToFile" buffer with BS, RT &
> >>> NV variables.
> >>>
> >>> 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
> >>
> >> This change actually doubles the amount of memory needed to store a
> >> variable at runtime. How do you reflect this in QueryVariableInfo()?
> >>
> >
> > It doesn't double it. Only BS, RT, NV variables are added to VarToFile.
> > QueryVariableInfo isn't supported at runtime, but with the current
> > code we have at boot time the VarToFile would be included in the
> > calculations.
>
> VarToFile does not exist at boot time. Nothing stops the user from
> writing NV variables to fill up the memory buffer. VarToFile will be as
> large as the sum of NV variables and will not fit into the buffer when
> efi_variables_boot_exit_notify() is invoked.
Yes, tbh when I was initially writing this, I was allocating 2x the
variable size buffer to get away from this limitation. But I
eventually decided variables for embedded would be small enough to not
suffer from this that much.
Anyway, I can either allocate 2x size and adjust some code size checks
or move the variable filling in GetVariable as you suggested earlier.
Any preference?
Thanks
/Ilias
>
> >
> >>>
> >>> Suggested-by:Ard Biesheuvel <ardb at kernel.org> # dumping all variables to a variable
> >>> Signed-off-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>
> >>> ---
> >>> include/efi_variable.h | 15 +++-
> >>> lib/efi_loader/efi_boottime.c | 2 +
> >>> lib/efi_loader/efi_var_common.c | 43 +++++------
> >>> lib/efi_loader/efi_var_file.c | 1 -
> >>> lib/efi_loader/efi_var_mem.c | 90 ++++++++++-------------
> >>> lib/efi_loader/efi_variable.c | 118 ++++++++++++++++++++++++------
> >
> > [...]
> >
> >>> * @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
> >>
> >> This line looks incomplete.
> >
> > Yes, fixed
> >
> >>
> >>> * 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);
> >>>
> >>> /**
> >
> > [...]
> >
> >>> return EFI_UNSUPPORTED;
> >>> @@ -557,11 +593,11 @@ void efi_variables_boot_exit_notify(void)
> >>> const efi_guid_t efi_guid_efi_rt_var_file = U_BOOT_EFI_RT_VAR_FILE_GUID;
> >>> const efi_guid_t rt_prop_guid = EFI_RT_PROPERTIES_TABLE_GUID;
> >>> efi_status_t ret;
> >>> + struct efi_var_file *buf;
> >>> + loff_t len;
> >>> + bool fail = false;
> >>>
> >>> if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
> >>> - struct efi_rt_properties_table *rt_prop =
> >>> - efi_get_configuration_table(&rt_prop_guid);
> >>> -
> >>> ret = efi_set_variable_int(u"RTStorageVolatile",
> >>> &efi_guid_efi_rt_var_file,
> >>> EFI_VARIABLE_BOOTSERVICE_ACCESS |
> >>> @@ -569,11 +605,47 @@ void efi_variables_boot_exit_notify(void)
> >>> EFI_VARIABLE_READ_ONLY,
> >>> sizeof(EFI_VAR_FILE_NAME),
> >>> EFI_VAR_FILE_NAME, false);
> >>> + if (ret != EFI_SUCCESS) {
> >>> + fail = true;
> >>> + goto out;
> >>> + }
> >>> +
> >>> + ret = efi_var_collect(&buf, &len, EFI_VARIABLE_NON_VOLATILE);
> >>> + if (ret != EFI_SUCCESS) {
> >>> + fail = true;
> >>> + goto out;
> >>> + }
> >>> +
> >>> + ret = efi_set_variable_int(u"VarToFile",
> >>> + &efi_guid_efi_rt_var_file,
> >>> + EFI_VARIABLE_BOOTSERVICE_ACCESS |
> >>> + EFI_VARIABLE_RUNTIME_ACCESS,
> >>> + len,
> >>> + buf, false);
> >>> if (ret != EFI_SUCCESS)
> >>> - rt_prop->runtime_services_supported |= ~EFI_RT_SUPPORTED_SET_VARIABLE;
> >>> - else
> >>> - log_err("Can't RTStorage. SetVariableRT won't be available\n");
> >>> + fail = true;
> >>> +out:
> >>> + if (fail) {
> >>> + 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, 0,
> >>> + false);
> >>
> >> Not providing VarToFile because the memory buffer is more than half
> >> filled before ExitBootServices() is unexpected behavior. This needs rework.
> >
> > Why? We should add the SetVariable at runtime to the documentation.
>
> Depending on the number of variables existing at boot time support you
> will be creating VarToFile or not. I can't see that users will fancy this.
>
> Best regards
>
> Heinrich
>
> >
> >>
> >> It is not necessary to create VarToFile in the internal memory buffer.
> >> You could generate it when the user calls GetVariable() in the user
> >> provided buffer.
> >
> > Yes, but that would make some functions look a bit messier, since we
> > have to inject code specifically looking for VarToFile.
> > OTOH it would make SetVariable at runtime easier to read since all the
> > size calculations and variable creation would go away.
> > But in any case, we have to add the variable at runtime (perhaps with
> > a value of 0?) -- users need to know it's there to be able to read it.
> > But if you are fine with the special conditions in GetVariable at
> > runtime, I can easily move the logic to GetVariable.
> >
> > Thanks
> > /Ilias
> >
> >>
> >> Best regards
> >>
> >> Heinrich
> >>
> >>> + efi_set_variable_int(u"VarToFile",
> >>> + &efi_guid_efi_rt_var_file,
> >>> + EFI_VARIABLE_BOOTSERVICE_ACCESS |
> >>> + EFI_VARIABLE_RUNTIME_ACCESS, 0, 0,
> >>> + false);
> >>> + } else {
> >>> + struct efi_rt_properties_table *rt_prop =
> >>> + efi_get_configuration_table(&rt_prop_guid);
> >>> +
> >>> + rt_prop->runtime_services_supported |=
> >>> + EFI_RT_SUPPORTED_SET_VARIABLE;
> >>> + }
> >>> }
> >>> +
> >>> /* Switch variable services functions to runtime version */
> >>> efi_runtime_services.get_variable = efi_get_variable_runtime;
> >>> efi_runtime_services.get_next_variable_name =
> >>> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> >>> index dde135fd9f81..9d0e270591ea 100644
> >>> --- a/lib/efi_loader/efi_variable_tee.c
> >>> +++ b/lib/efi_loader/efi_variable_tee.c
> >>> @@ -969,7 +969,6 @@ void efi_variables_boot_exit_notify(void)
> >>> log_err("Can't populate EFI variables. No runtime variables will be available\n");
> >>> else
> >>> efi_var_buf_update(var_buf);
> >>> - free(var_buf);
> >>>
> >>> /* Update runtime service table */
> >>> efi_runtime_services.query_variable_info =
> >>> --
> >>> 2.37.2
> >>>
> >>
>
More information about the U-Boot
mailing list