[U-Boot] [PATCH 1/1] efi_selftest: do not write to linker generated array

Simon Glass sjg at chromium.org
Mon Oct 22 17:49:58 UTC 2018


Hi Heinrich,

On 18 October 2018 at 23:51, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
> Linker generated arrays may be stored in code sections of memory that are
> not writable. So let's allocate setup_ok as an array at runtime.
>
> This avoids an illegal memory access observed in the sandbox.
>
> Reported-by: Simon Glass <sjg at chromium.org>
> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> ---
>  include/efi_selftest.h          |  2 --
>  lib/efi_selftest/efi_selftest.c | 31 ++++++++++++++++++++++---------
>  2 files changed, 22 insertions(+), 11 deletions(-)

Reviewed-by: Simon Glass <sjg at chromium.org>

Thanks for doing this!

>
> diff --git a/include/efi_selftest.h b/include/efi_selftest.h
> index 56beac305e..49d3d6d0b4 100644
> --- a/include/efi_selftest.h
> +++ b/include/efi_selftest.h
> @@ -129,7 +129,6 @@ u16 efi_st_get_key(void);
>   * @setup:     set up the unit test
>   * @teardown:  tear down the unit test
>   * @execute:   execute the unit test
> - * @setup_ok:  setup was successful (set at runtime)

I'm not keen on the name setup_ok, which suggests a bool which would
be true if it is OK.

How about setup_err or setup_ret?

>   * @on_request:        test is only executed on request
>   */
>  struct efi_unit_test {
> @@ -139,7 +138,6 @@ struct efi_unit_test {
>                      const struct efi_system_table *systable);
>         int (*execute)(void);
>         int (*teardown)(void);
> -       int setup_ok;
>         bool on_request;
>  };
>
> diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c
> index dd338db687..fc7866365d 100644
> --- a/lib/efi_selftest/efi_selftest.c
> +++ b/lib/efi_selftest/efi_selftest.c
> @@ -18,6 +18,7 @@ static const struct efi_boot_services *boottime;
>  static const struct efi_runtime_services *runtime;
>  static efi_handle_t handle;
>  static u16 reset_message[] = L"Selftest completed";
> +static int *setup_ok;
>
>  /*
>   * Exit the boot services.
> @@ -74,20 +75,20 @@ void efi_st_exit_boot_services(void)
>   */
>  static int setup(struct efi_unit_test *test, unsigned int *failures)
>  {
> -       if (!test->setup) {
> -               test->setup_ok = EFI_ST_SUCCESS;
> +       int ret;
> +
> +       if (!test->setup)
>                 return EFI_ST_SUCCESS;
> -       }
>         efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name);
> -       test->setup_ok = test->setup(handle, systable);
> -       if (test->setup_ok != EFI_ST_SUCCESS) {
> +       ret = test->setup(handle, systable);
> +       if (ret != EFI_ST_SUCCESS) {
>                 efi_st_error("Setting up '%s' failed\n", test->name);
>                 ++*failures;
>         } else {
>                 efi_st_printc(EFI_LIGHTGREEN,
>                               "Setting up '%s' succeeded\n", test->name);
>         }
> -       return test->setup_ok;
> +       return ret;
>  }
>
>  /*
> @@ -186,18 +187,20 @@ static void list_all_tests(void)
>  void efi_st_do_tests(const u16 *testname, unsigned int phase,
>                      unsigned int steps, unsigned int *failures)
>  {
> +       int i = 0;
>         struct efi_unit_test *test;
>
>         for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
> -            test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
> +            test < ll_entry_end(struct efi_unit_test, efi_unit_test);
> +            ++test, ++i) {
>                 if (testname ?
>                     efi_st_strcmp_16_8(testname, test->name) : test->on_request)
>                         continue;
>                 if (test->phase != phase)
>                         continue;
>                 if (steps & EFI_ST_SETUP)
> -                       setup(test, failures);
> -               if (steps & EFI_ST_EXECUTE && test->setup_ok == EFI_ST_SUCCESS)
> +                       setup_ok[i] = setup(test, failures);
> +               if (steps & EFI_ST_EXECUTE && setup_ok[i] == EFI_ST_SUCCESS)
>                         execute(test, failures);
>                 if (steps & EFI_ST_TEARDOWN)
>                         teardown(test, failures);
> @@ -271,6 +274,16 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
>                               ll_entry_count(struct efi_unit_test,
>                                              efi_unit_test));
>
> +       /* Allocate buffer for setup results */
> +       ret = boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) *
> +                                     ll_entry_count(struct efi_unit_test,
> +                                                    efi_unit_test),
> +                                     (void **)&setup_ok);

Isn't this calling the code you are trying to test and messing with
the memory allocation tables? I wonder if you should allocate this in
the caller or as part of the setup.

Hmmm but I suppose you don't want to, since this is sort-of an EFI app?

> +       if (ret != EFI_SUCCESS) {
> +               efi_st_error("Allocate pool failed\n");
> +               return ret;
> +       }
> +
>         /* Execute boottime tests */
>         efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
>                         EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
> --
> 2.19.1
>

Regards,
Simon


More information about the U-Boot mailing list