[PATCH] efi_loader: Avoid emitting efi_var_buf to .GOT
Heinrich Schuchardt
xypron.glpk at gmx.de
Fri Jan 15 19:53:11 CET 2021
On 15.01.21 17:00, Ilias Apalodimas wrote:
> Atish reports than on RISC-V, accessing the EFI variables causes
> a kernel panic. An objdump of the file verifies that, since the
> global pointer for efi_var_buf ends up in .GOT section which is
> not mapped in virtual address space for Linux.
>
> <snip of efi_var_mem_find>
>
> 0000000000000084 <efi_var_mem_find>:
> 84: 715d addi sp,sp,-80
>
> * objdump -dr
> 0000000000000086 <.LCFI2>:
> 86: e0a2 sd s0,64(sp)
> 88: fc26 sd s1,56(sp)
> 8a: e486 sd ra,72(sp)
> 8c: f84a sd s2,48(sp)
> 8e: f44e sd s3,40(sp)
> 90: f052 sd s4,32(sp)
> 92: ec56 sd s5,24(sp)
> 94: 00000497 auipc s1,0x0
> 94: R_RISCV_GOT_HI20 efi_var_buf
> 98: 0004b483 ld s1,0(s1) # 94 <.LCFI2+0xe>
> 98: R_RISCV_PCREL_LO12_I .L0
> 98: R_RISCV_RELAX *ABS*
>
> * objdump -t
> 0000000000000084 g F .text.efi_runtime 00000000000000b8 efi_var_mem_find
>
> With the patch applied:
>
> * objdump -dr
> 0000000000000086 <.LCFI2>:
> 86: e0a2 sd s0,64(sp)
> 88: fc26 sd s1,56(sp)
> 8a: e486 sd ra,72(sp)
> 8c: f84a sd s2,48(sp)
> 8e: f44e sd s3,40(sp)
> 90: f052 sd s4,32(sp)
> 92: ec56 sd s5,24(sp)
> 94: 00000497 auipc s1,0x0
> 94: R_RISCV_PCREL_HI20 .LANCHOR0
> 94: R_RISCV_RELAX *ABS*
> 98: 00048493 mv s1,s1
> 98: R_RISCV_PCREL_LO12_I .L0
> 98: R_RISCV_RELAX *ABS*
>
> * objdump -t
> 0000000000000008 l O .data.efi_runtime 0000000000000008 efi_var_buf
>
> On arm64 this works, because there's no .GOT entries for this
> and everything is converted to relative references.
>
> * objdump -dr (identical pre-post patch, only the new function shows up)
> 00000000000000b4 <efi_var_mem_find>:
> b4: aa0003ee mov x14, x0
> b8: 9000000a adrp x10, 0 <efi_var_mem_compare>
> b8: R_AARCH64_ADR_PREL_PG_HI21 .data.efi_runtime
> bc: 91000140 add x0, x10, #0x0
> bc: R_AARCH64_ADD_ABS_LO12_NC .data.efi_runtime
> c0: aa0103ed mov x13, x1
> c4: 79400021 ldrh w1, [x1]
> c8: aa0203eb mov x11, x2
> cc: f9400400 ldr x0, [x0, #8]
> d0: b940100c ldr w12, [x0, #16]
> d4: 8b0c000c add x12, x0, x12
>
> So let's switch efi_var_buf to static and create a helper function for
> anyone that needs to update it.
>
> Fixes: e01aed47d6a0 ("efi_loader: Enable run-time variable support for tee based variables")
> Reported-by: Atish Patra <atishp at atishpatra.org>
> Signed-off-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>
> ---
> Atish can you give it a spin and let me know if this fixes the issue for you?
> The objdump seems to be correct now, but I am not familiar with RISC-V.
> No regressions on Arm with TEE or memory backed variables.
> include/efi_variable.h | 12 ++++++++++++
> lib/efi_loader/efi_var_mem.c | 12 +++++++++++-
> lib/efi_loader/efi_variable_tee.c | 2 +-
> 3 files changed, 24 insertions(+), 2 deletions(-)
>
> diff --git a/include/efi_variable.h b/include/efi_variable.h
> index 4704a3c16e65..b2317eb7bf1c 100644
> --- a/include/efi_variable.h
> +++ b/include/efi_variable.h
> @@ -306,4 +306,16 @@ efi_status_t __efi_runtime EFIAPI
> efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
> u16 *variable_name, efi_guid_t *guid);
>
> +/**
> + * efi_var_buf_update() - Update the value of efi_var_buf in efi_var_mem.c
Dear Ilias,
thank you for addressing this problem. The code looks fine to me. Just
some ideas concerning comment lines:
The value of efi_var_buf is the address it is pointing to. So i would
prefer:
efi_var_buf_update() - udpate memory buffer for variables
> + *
> + * @var_buf: Source buffer
%s/Source/source/
> + *
> + * efi_var_buf is special since we use it on Runtime Services. We need
> + * to keep it static in efi_var_mem.c and avoid having it pulled into
> + * .GOT. Since it has to be static this function must be used to update
You already place a comment about .GOT where the declaration is. Here
describing how the function is used would be of interest. E.g.
"This function copies to the memory buffer for UEFI variables. Call this
function in ExitBootServices() if memory backed variables are only used
at runtime to fill the buffer."
> + * it
> + */
> +void efi_var_buf_update(struct efi_var_file *var_buf);
> +
> #endif
> diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c
> index d155f25f60e6..fcf0043b5d3b 100644
> --- a/lib/efi_loader/efi_var_mem.c
> +++ b/lib/efi_loader/efi_var_mem.c
> @@ -10,7 +10,12 @@
> #include <efi_variable.h>
> #include <u-boot/crc.h>
>
> -struct efi_var_file __efi_runtime_data *efi_var_buf;
> +/*
> + * keep efi_var_buf as static , moving it out might move it to .got
> + * which is not mapped in virtual address for Linux. Whenever
> + * we try to invoke get_variable service, it will panic.
Not everybody will know the abbreviation .got. How about:
"The variables efi_var_file and efi_var_entry must be static to avoid
that they are referenced via the global offset table (section .got). The
GOT is neither mapped as EfiRuntimeServicesData nor do we support its
relocation during SetVirtualAddressMap()."
Otherwise
Reviewed-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> + */
> +static struct efi_var_file __efi_runtime_data *efi_var_buf;
> static struct efi_var_entry __efi_runtime_data *efi_current_var;
>
> /**
> @@ -339,3 +344,8 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size,
>
> return EFI_SUCCESS;
> }
> +
> +void efi_var_buf_update(struct efi_var_file *var_buf)
> +{
> + memcpy(efi_var_buf, var_buf, EFI_VAR_BUF_SIZE);
> +}
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> index be6f3dfad469..c69330443801 100644
> --- a/lib/efi_loader/efi_variable_tee.c
> +++ b/lib/efi_loader/efi_variable_tee.c
> @@ -692,7 +692,7 @@ void efi_variables_boot_exit_notify(void)
> if (ret != EFI_SUCCESS)
> log_err("Can't populate EFI variables. No runtime variables will be available\n");
> else
> - memcpy(efi_var_buf, var_buf, len);
> + efi_var_buf_update(var_buf);
> free(var_buf);
>
> /* Update runtime service table */
>
More information about the U-Boot
mailing list