Re: [PATCH v2] efi_loader: fix use of uninitialized guid in variable enumeration loops

Heinrich Schuchardt <[email protected]> Fri, 31 Jul 2026 11:24:49 +0200
Newsgroups gmane.comp.boot-loaders.u-boot
Message-ID <[email protected]>
On 7/28/26 21:33, Scott Moser wrote:
> efi_bootmgr_delete_invalid_boot_option(), eficonfig_show_boot_selection(),
> and eficonfig_create_change_boot_order_entry() each enumerate all EFI
> variables by repeatedly calling efi_next_variable_name() in a loop,
> passing the same efi_guid_t as both input and output. GetNextVariableName()
> needs the vendor GUID returned by the previous call, together with the
> variable name it returned, to know where to resume.
> 
> In each of these loops the efi_guid_t was declared inside the loop body,
> so a new instance comes into scope on every iteration. Relying on it to
> still hold the previous iteration's value depends on the compiler reusing
> the same stack slot across iterations, which is undefined behavior. With
> a compiler that zero-initializes locals by default (e.g. clang, or gcc
> configured with -ftrivial-auto-var-init=zero), the GUID is cleared on
> every iteration, so the lookup of the variable name returned by the
> previous call fails and efi_init_obj_list() aborts:
> 
>    Cannot initialize UEFI sub-system
>    ** Booting bootflow ... with efi
>    Boot failed (err=-22)
> 
> Move the efi_guid_t declarations out of the loops so the value written
> by the previous efi_next_variable_name() call is preserved across
> iterations.
> 
> Fixes: 140a8959d48f ("eficonfig: use efi_get_next_variable_name_int()")
> Signed-off-by: Scott Moser <[email protected]>

Reviewed-by: Heinrich Schuchardt <[email protected]>

None of the loops handles EFI_BUFFER_TOO_SMALL. Just create a variable 
called fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 
to break the code.

We should move all calls of GetNextVariable() to a new function in 
lib/efi_loader/efi_var_common.c with proper handling of the variable 
name buffer.

But let's merge the current patch first.

Best regards

Heinrich

> ---
> Changes for v2:
> - Drop the "= {}" initializer on the hoisted guid: per the UEFI spec,
>    VendorGuid is ignored when VariableName is an empty string, which is
>    the state var_name16 is in on the first call, so the initial value is
>    never read and zero-initializing it only costs code size.
> 
>   cmd/eficonfig.c              | 4 ++--
>   lib/efi_loader/efi_bootmgr.c | 2 +-
>   2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c
> index 4d060e3007c..d8e7ed6666a 100644
> --- a/cmd/eficonfig.c
> +++ b/cmd/eficonfig.c
> @@ -1844,6 +1844,7 @@ static efi_status_t eficonfig_show_boot_selection(unsigned int *selected)
>   	struct efimenu *efi_menu;
>   	struct list_head *pos, *n;
>   	struct eficonfig_entry *entry;
> +	efi_guid_t guid;
>   
>   	efi_menu = calloc(1, sizeof(struct efimenu));
>   	if (!efi_menu)
> @@ -1872,7 +1873,6 @@ static efi_status_t eficonfig_show_boot_selection(unsigned int *selected)
>   	var_name16[0] = 0;
>   	for (;;) {
>   		int index;
> -		efi_guid_t guid;
>   
>   		ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
>   		if (ret == EFI_NOT_FOUND)
> @@ -2245,6 +2245,7 @@ static efi_status_t eficonfig_create_change_boot_order_entry(struct efimenu *efi
>   	u16 *var_name16 = NULL;
>   	efi_uintn_t size, buf_size;
>   	struct eficonfig_save_boot_order_data *save_data;
> +	efi_guid_t guid;
>   
>   	/* list the load option in the order of BootOrder variable */
>   	for (i = 0; i < num; i++) {
> @@ -2265,7 +2266,6 @@ static efi_status_t eficonfig_create_change_boot_order_entry(struct efimenu *efi
>   	var_name16[0] = 0;
>   	for (;;) {
>   		int index;
> -		efi_guid_t guid;
>   
>   		if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 2)
>   			break;
> diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
> index 8c9a9b5eb56..8938b214ceb 100644
> --- a/lib/efi_loader/efi_bootmgr.c
> +++ b/lib/efi_loader/efi_bootmgr.c
> @@ -934,6 +934,7 @@ static efi_status_t efi_bootmgr_delete_invalid_boot_option(struct eficonfig_medi
>   	efi_status_t ret = EFI_SUCCESS;
>   	u16 *delete_index_list = NULL, *p;
>   	efi_uintn_t buf_size;
> +	efi_guid_t guid;
>   
>   	buf_size = 128;
>   	var_name16 = malloc(buf_size);
> @@ -943,7 +944,6 @@ static efi_status_t efi_bootmgr_delete_invalid_boot_option(struct eficonfig_medi
>   	var_name16[0] = 0;
>   	for (;;) {
>   		int index;
> -		efi_guid_t guid;
>   		efi_uintn_t tmp;
>   
>   		ret = efi_next_variable_name(&buf_size, &var_name16, &guid);