[PATCH v2] efi_loader: fix append write behavior to non-existent variable

Ilias Apalodimas ilias.apalodimas at linaro.org
Thu Apr 4 09:35:51 CEST 2024


On Tue, 2 Apr 2024 at 12:09, Masahisa Kojima
<kojima.masahisa at socionext.com> wrote:
>
> Current "variables" efi_selftest result is inconsistent
> between the U-Boot file storage and the tee-based StandaloneMM
> RPMB secure storage.
>
> U-Boot file storage implementation does not accept SetVariale
> call to non-existent variable with EFI_VARIABLE_APPEND_WRITE,
> it return EFI_NOT_FOUND.
> However it is accepted and new variable is created in EDK II
> StandaloneMM implementation if valid data and size are specified.
> If data size is 0, EFI_SUCCESS is returned.
>
> Since UEFI specification does not clearly describe the behavior
> of the append write to non-existent variable, let's update
> the U-Boot file storage implementation to get aligned with
> the EDK II reference implementation.
>
> Signed-off-by: Masahisa Kojima <kojima.masahisa at socionext.com>
> ---
> v1 -> v2
> - return EFI_SUCCESS for append write with data size 0
> - add comment that we follow the EDK II implementation
>
>  lib/efi_loader/efi_variable.c             | 26 +++++++++---
>  lib/efi_selftest/efi_selftest_variables.c | 48 ++++++++++++++++++++++-
>  2 files changed, 66 insertions(+), 8 deletions(-)
>
> diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
> index 40f7a0fb10..d1db7ade0a 100644
> --- a/lib/efi_loader/efi_variable.c
> +++ b/lib/efi_loader/efi_variable.c
> @@ -282,11 +282,21 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
>                 }
>                 time = var->time;
>         } else {
> -               if (delete || append)
> -                       /*
> -                        * Trying to delete or to update a non-existent
> -                        * variable.
> -                        */
> +               /*
> +                * UEFI specification does not clearly describe the expected
> +                * behavior of append write with data size 0, we follow
> +                * the EDK II reference implementation.
> +                */
> +               if (append && !data_size)
> +                       return EFI_SUCCESS;
> +
> +               /*
> +                * EFI_VARIABLE_APPEND_WRITE to non-existent variable is accepted
> +                * and new variable is created in EDK II reference implementation.
> +                * We follow it and only check the deletion here.
> +                */
> +               if (delete)
> +                       /* Trying to delete a non-existent variable. */
>                         return EFI_NOT_FOUND;
>         }
>
> @@ -329,7 +339,11 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
>                 /* EFI_NOT_FOUND has been handled before */
>                 attributes = var->attr;
>                 ret = EFI_SUCCESS;
> -       } else if (append) {
> +       } else if (append && var) {
> +               /*
> +                * data is appended if EFI_VARIABLE_APPEND_WRITE is set and
> +                * variable exists.
> +                */
>                 u16 *old_data = var->name;
>
>                 for (; *old_data; ++old_data)
> diff --git a/lib/efi_selftest/efi_selftest_variables.c b/lib/efi_selftest/efi_selftest_variables.c
> index c7a3fdbaa6..39ad03a090 100644
> --- a/lib/efi_selftest/efi_selftest_variables.c
> +++ b/lib/efi_selftest/efi_selftest_variables.c
> @@ -131,13 +131,57 @@ static int execute(void)
>                             (unsigned int)len);
>         if (memcmp(data, v, len))
>                 efi_st_todo("GetVariable returned wrong value\n");
> -       /* Append variable 2 */
> +
> +       /* Append variable 2, write to non-existent variable with datasize=0 */
> +       ret = runtime->set_variable(u"efi_none", &guid_vendor1,
> +                                   EFI_VARIABLE_BOOTSERVICE_ACCESS |
> +                                   EFI_VARIABLE_APPEND_WRITE,
> +                                   0, v);
> +       if (ret != EFI_SUCCESS) {
> +               efi_st_error(
> +                       "SetVariable(APPEND_WRITE) with size 0 to non-existent variable returns wrong code\n");
> +               return EFI_ST_FAILURE;
> +       }
> +       len = EFI_ST_MAX_DATA_SIZE;
> +       ret = runtime->get_variable(u"efi_none", &guid_vendor1,
> +                                   &attr, &len, data);
> +       if (ret != EFI_NOT_FOUND) {
> +               efi_st_error("Variable must not be created\n");
> +               return EFI_ST_FAILURE;
> +       }
> +       /* Append variable 2, write to non-existent variable with valid data size*/
>         ret = runtime->set_variable(u"efi_none", &guid_vendor1,
>                                     EFI_VARIABLE_BOOTSERVICE_ACCESS |
>                                     EFI_VARIABLE_APPEND_WRITE,
>                                     15, v);
> +       if (ret != EFI_SUCCESS) {
> +               efi_st_error("SetVariable(APPEND_WRITE) with valid size and data to non-existent variable must be succcessful\n");
> +               return EFI_ST_FAILURE;
> +       }
> +       len = EFI_ST_MAX_DATA_SIZE;
> +       ret = runtime->get_variable(u"efi_none", &guid_vendor1,
> +                                   &attr, &len, data);
> +       if (ret != EFI_SUCCESS) {
> +               efi_st_error("GetVariable failed\n");
> +               return EFI_ST_FAILURE;
> +       }
> +       if (len != 15)
> +               efi_st_todo("GetVariable returned wrong length %u\n",
> +                           (unsigned int)len);
> +       if (memcmp(data, v, len))
> +               efi_st_todo("GetVariable returned wrong value\n");
> +       /* Delete variable efi_none */
> +       ret = runtime->set_variable(u"efi_none", &guid_vendor1,
> +                                   0, 0, NULL);
> +       if (ret != EFI_SUCCESS) {
> +               efi_st_error("SetVariable failed\n");
> +               return EFI_ST_FAILURE;
> +       }
> +       len = EFI_ST_MAX_DATA_SIZE;
> +       ret = runtime->get_variable(u"efi_none", &guid_vendor1,
> +                                   &attr, &len, data);
>         if (ret != EFI_NOT_FOUND) {
> -               efi_st_error("SetVariable(APPEND_WRITE) with size 0 to non-existent variable returns wrong code\n");
> +               efi_st_error("Variable was not deleted\n");
>                 return EFI_ST_FAILURE;
>         }
>         /* Enumerate variables */
> --
> 2.34.1
>

Reviewed-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>
Tested-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>


More information about the U-Boot mailing list