On Mon, Mar 10, 2025 at 09:12:22AM +0000, Mate Kukri wrote:
> - Use shim loader protocol to verify images in the shim_lock verifier.

This change makes the shim loader protocol mandatory for GRUB under UEFI
Secure Boot. However, I don't think this is a good idea, since the new
protocol is only available starting from shim 16.0. GRUB should remain
compatible with older shim versions, otherwise this could introduce a
disruptive change.

Why not implement a fallback mechanism to use the shim lock protocol
when the loader protocol is unavailable ?

Also see below for an issue:

> - Add API to allow downstream consumers to re-use image handles produced
>   by the verifier. This is necessary to avoid having images measured
>   twice to the TPM.
> - Register shim loader protocol as an image loader.
> 
> Signed-off-by: Mate Kukri <mate.ku...@canonical.com>
> ---
>  grub-core/kern/efi/sb.c            | 45 ++++++++++++++++--------------
>  grub-core/loader/efi/chainloader.c | 21 ++++++++------
>  grub-core/loader/efi/linux.c       | 30 ++++++--------------
>  include/grub/efi/api.h             |  5 ++++
>  include/grub/efi/efi.h             | 19 ++++++++-----
>  include/grub/efi/sb.h              |  5 ++--
>  6 files changed, 66 insertions(+), 59 deletions(-)
> 
> diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
> index 8d3e41360..fcc71e4e8 100644
> --- a/grub-core/kern/efi/sb.c
> +++ b/grub-core/kern/efi/sb.c
> @@ -31,8 +31,11 @@
>  #include <grub/verify.h>
>  
>  static grub_guid_t shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID;
> +static grub_guid_t shim_loader_guid = GRUB_EFI_SHIM_IMAGE_LOADER_GUID;
>  
> -static bool shim_lock_enabled = false;
> +static grub_efi_loader_t *shim_loader = NULL;
> +
> +static grub_efi_handle_t last_verified_image_handle;
>  
>  /*
>   * Determine whether we're in secure boot mode.
> @@ -95,14 +98,6 @@ grub_efi_get_secureboot (void)
>    if (!(attr & GRUB_EFI_VARIABLE_RUNTIME_ACCESS) && *moksbstate == 1)
>      {
>        secureboot = GRUB_EFI_SECUREBOOT_MODE_DISABLED;
> -      /*
> -       * TODO: Replace this all with shim's LoadImage protocol, delegating 
> policy to it.
> -       *
> -       * We need to set shim_lock_enabled here because we disabled secure 
> boot
> -       * validation *inside* shim but not in the firmware, so we set this 
> variable
> -       * here to trigger that code path, whereas the actual verifier is not 
> enabled.
> -       */
> -      shim_lock_enabled = true;
>        goto out;
>      }
>  
> @@ -183,14 +178,18 @@ shim_lock_verifier_init (grub_file_t io __attribute__ 
> ((unused)),
>  static grub_err_t
>  shim_lock_verifier_write (void *context __attribute__ ((unused)), void *buf, 
> grub_size_t size)
>  {
> -  grub_efi_shim_lock_protocol_t *sl = grub_efi_locate_protocol 
> (&shim_lock_guid, 0);
> +  grub_efi_handle_t image_handle;
>  
> -  if (!sl)
> -    return grub_error (GRUB_ERR_ACCESS_DENIED, N_("shim_lock protocol not 
> found"));
> +  if (last_verified_image_handle)
> +    {
> +      shim_loader->unload_image (last_verified_image_handle);
> +      last_verified_image_handle = NULL;
> +    }
>  
> -  if (sl->verify (buf, size) != GRUB_EFI_SUCCESS)
> +  if (shim_loader->load_image (false, grub_efi_image_handle, NULL, buf, 
> size, &image_handle) != GRUB_EFI_SUCCESS)
>      return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad shim signature"));

.. and here may cause a NULL pointer dereference if shim_loader is not
provided by the shim.

Thanks,
Michael

>  
> +  last_verified_image_handle = image_handle;
>    return GRUB_ERR_NONE;
>  }
>  
> @@ -205,11 +204,11 @@ void
>  grub_shim_lock_verifier_setup (void)
>  {
>    struct grub_module_header *header;
> -  grub_efi_shim_lock_protocol_t *sl =
> -    grub_efi_locate_protocol (&shim_lock_guid, 0);
>  
> -  /* shim_lock is missing, check if GRUB image is built with 
> --disable-shim-lock. */
> -  if (!sl)
> +  shim_loader = grub_efi_locate_protocol (&shim_loader_guid, 0);
> +
> +  /* shim is missing, check if GRUB image is built with --disable-shim-lock. 
> */
> +  if (!shim_loader)
>      {
>        FOR_MODULES (header)
>       {
> @@ -225,14 +224,18 @@ grub_shim_lock_verifier_setup (void)
>    /* Enforce shim_lock_verifier. */
>    grub_verifier_register (&shim_lock_verifier);
>  
> -  shim_lock_enabled = true;
> +  /* Register shim loader if supported. */
> +  grub_efi_register_loader (shim_loader);
>  
>    grub_env_set ("shim_lock", "y");
>    grub_env_export ("shim_lock");
>  }
>  
> -bool
> -grub_is_shim_lock_enabled (void)
> +
> +grub_efi_handle_t
> +grub_efi_get_last_verified_image_handle (void)
>  {
> -  return shim_lock_enabled;
> +  grub_efi_handle_t tmp = last_verified_image_handle;
> +  last_verified_image_handle = NULL;
> +  return tmp;
>  }
> diff --git a/grub-core/loader/efi/chainloader.c 
> b/grub-core/loader/efi/chainloader.c
> index 11b64ac1b..e77bd863c 100644
> --- a/grub-core/loader/efi/chainloader.c
> +++ b/grub-core/loader/efi/chainloader.c
> @@ -33,6 +33,7 @@
>  #include <grub/efi/efi.h>
>  #include <grub/efi/disk.h>
>  #include <grub/efi/memory.h>
> +#include <grub/efi/sb.h>
>  #include <grub/command.h>
>  #include <grub/i18n.h>
>  #include <grub/net.h>
> @@ -337,16 +338,20 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ 
> ((unused)),
>      }
>  #endif
>  
> -  status = grub_efi_load_image (0, grub_efi_image_handle, file_path,
> -                             boot_image, size, &image_handle);
> -  if (status != GRUB_EFI_SUCCESS)
> +  image_handle = grub_efi_get_last_verified_image_handle ();
> +  if (image_handle == NULL)
>      {
> -      if (status == GRUB_EFI_OUT_OF_RESOURCES)
> -     grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
> -      else
> -     grub_error (GRUB_ERR_BAD_OS, "cannot load image");
> +      status = grub_efi_load_image (0, grub_efi_image_handle, file_path,
> +                             boot_image, size, &image_handle);
> +      if (status != GRUB_EFI_SUCCESS)
> +     {
> +       if (status == GRUB_EFI_OUT_OF_RESOURCES)
> +         grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
> +       else
> +         grub_error (GRUB_ERR_BAD_OS, "cannot load image");
>  
> -      goto fail;
> +       goto fail;
> +     }
>      }
>  
>    /* LoadImage does not set a device handler when the image is
> diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
> index 7342f3ee7..b97b3e27b 100644
> --- a/grub-core/loader/efi/linux.c
> +++ b/grub-core/loader/efi/linux.c
> @@ -206,11 +206,15 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, 
> grub_size_t size, char *args)
>    mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
>    mempath[1].header.length = sizeof (grub_efi_device_path_t);
>  
> -  status = grub_efi_load_image (0, grub_efi_image_handle,
> -                             (grub_efi_device_path_t *)mempath,
> -                             (void *)addr, size, &image_handle);
> -  if (status != GRUB_EFI_SUCCESS)
> -    return grub_error (GRUB_ERR_BAD_OS, "cannot load image");
> +  image_handle = grub_efi_get_last_verified_image_handle ();
> +  if (image_handle == NULL)
> +    {
> +      status = grub_efi_load_image (0, grub_efi_image_handle,
> +                                 (grub_efi_device_path_t *)mempath,
> +                                 (void *)addr, size, &image_handle);
> +      if (status != GRUB_EFI_SUCCESS)
> +     return grub_error (GRUB_ERR_BAD_OS, "cannot load image");
> +    }
>  
>    grub_dprintf ("linux", "linux command line: '%s'\n", args);
>  
> @@ -461,22 +465,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ 
> ((unused)),
>  
>    grub_dl_ref (my_mod);
>  
> -  if (grub_is_shim_lock_enabled () == true)
> -    {
> -#if defined(__i386__) || defined(__x86_64__)
> -      grub_dprintf ("linux", "shim_lock enabled, falling back to legacy 
> Linux kernel loader\n");
> -
> -      err = grub_cmd_linux_x86_legacy (cmd, argc, argv);
> -
> -      if (err == GRUB_ERR_NONE)
> -     return GRUB_ERR_NONE;
> -      else
> -     goto fail;
> -#else
> -      grub_dprintf ("linux", "shim_lock enabled, trying Linux kernel EFI 
> stub loader\n");
> -#endif
> -    }
> -
>    if (argc == 0)
>      {
>        grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
> diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
> index b686e8afe..9ae908729 100644
> --- a/include/grub/efi/api.h
> +++ b/include/grub/efi/api.h
> @@ -364,6 +364,11 @@
>      { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \
>    }
>  
> +#define GRUB_EFI_SHIM_IMAGE_LOADER_GUID \
> +  { 0x1f492041, 0xfadb, 0x4e59, \
> +    {0x9e, 0x57, 0x7c, 0xaf, 0xe7, 0x3a, 0x55, 0xab } \
> +  }
> +
>  #define GRUB_EFI_RNG_PROTOCOL_GUID \
>    { 0x3152bca5, 0xeade, 0x433d, \
>      { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \
> diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
> index 692a1b935..b4d2f2d46 100644
> --- a/include/grub/efi/efi.h
> +++ b/include/grub/efi/efi.h
> @@ -150,15 +150,20 @@ EXPORT_FUNC (grub_efi_unload_image) (grub_efi_handle_t 
> image_handle);
>  typedef struct grub_efi_loader
>  {
>    grub_efi_status_t (__grub_efi_api *load_image) (grub_efi_boolean_t 
> boot_policy,
> -                                grub_efi_handle_t parent_image_handle,
> -                                grub_efi_device_path_t *file_path,
> -                                void *source_buffer,
> -                                grub_efi_uintn_t source_size,
> -                                grub_efi_handle_t *image_handle);
> +                                               grub_efi_handle_t 
> parent_image_handle,
> +                                               grub_efi_device_path_t 
> *file_path,
> +                                               void *source_buffer,
> +                                               grub_efi_uintn_t source_size,
> +                                               grub_efi_handle_t 
> *image_handle);
>  
>    grub_efi_status_t (__grub_efi_api *start_image) (grub_efi_handle_t 
> image_handle,
> -                                 grub_efi_uintn_t *exit_data_size,
> -                                 grub_efi_char16_t **exit_data);
> +                                                grub_efi_uintn_t 
> *exit_data_size,
> +                                                grub_efi_char16_t 
> **exit_data);
> +
> +  grub_efi_status_t (__grub_efi_api *exit) (grub_efi_handle_t image_handle,
> +                                         grub_efi_status_t exit_status,
> +                                         grub_efi_uintn_t exit_data_size,
> +                                         grub_efi_char16_t *exit_data);
>  
>    grub_efi_status_t (__grub_efi_api *unload_image) (grub_efi_handle_t 
> image_handle);
>  } grub_efi_loader_t;
> diff --git a/include/grub/efi/sb.h b/include/grub/efi/sb.h
> index 49a9ad01c..284e14992 100644
> --- a/include/grub/efi/sb.h
> +++ b/include/grub/efi/sb.h
> @@ -21,6 +21,7 @@
>  
>  #include <grub/types.h>
>  #include <grub/dl.h>
> +#include <grub/efi/api.h>
>  
>  #define GRUB_EFI_SECUREBOOT_MODE_UNSET               0
>  #define GRUB_EFI_SECUREBOOT_MODE_UNKNOWN     1
> @@ -31,8 +32,8 @@
>  extern grub_uint8_t
>  EXPORT_FUNC (grub_efi_get_secureboot) (void);
>  
> -extern bool
> -EXPORT_FUNC (grub_is_shim_lock_enabled) (void);
> +extern grub_efi_handle_t
> +EXPORT_FUNC (grub_efi_get_last_verified_image_handle) (void);
>  
>  extern void
>  grub_shim_lock_verifier_setup (void);
> -- 
> 2.39.5
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to