dcavalca / rpms / grub2

Forked from rpms/grub2 3 years ago
Clone

Blame SOURCES/0225-Rework-even-more-of-efi-chainload-so-non-sb-cases-wo.patch

4fe85b
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
4fe85b
From: Peter Jones <pjones@redhat.com>
4fe85b
Date: Fri, 10 Jun 2016 14:06:15 -0400
4fe85b
Subject: [PATCH] Rework even more of efi chainload so non-sb cases work right.
4fe85b
4fe85b
This ensures that if shim protocol is not loaded, or is loaded but shim
4fe85b
is disabled, we will fall back to a correct load method for the efi
4fe85b
chain loader.
4fe85b
4fe85b
Here's what I tested with this version:
4fe85b
4fe85b
results                             expected    actual
4fe85b
------------------------------------------------------------
4fe85b
sb + enabled + shim + fedora        success     success
4fe85b
sb + enabled + shim + win           success     success
4fe85b
sb + enabled + grub + fedora        fail        fail
4fe85b
sb + enabled + grub + win           fail        fail
4fe85b
4fe85b
sb + mokdisabled + shim + fedora    success     success
4fe85b
sb + mokdisabled + shim + win       success     success
4fe85b
sb + mokdisabled + grub + fedora    fail        fail
4fe85b
sb + mokdisabled + grub + win       fail        fail
4fe85b
4fe85b
sb disabled + shim + fedora         success     success*
4fe85b
sb disabled + shim + win            success     success*
4fe85b
sb disabled + grub + fedora         success     success
4fe85b
sb disabled + grub + win            success     success
4fe85b
4fe85b
nosb + shim + fedora                success     success*
4fe85b
nosb + shim + win                   success     success*
4fe85b
nosb + grub + fedora                success     success
4fe85b
nosb + grub + win                   success     success
4fe85b
4fe85b
* for some reason shim protocol is being installed in these cases, and I
4fe85b
  can't see why, but I think it may be this firmware build returning an
4fe85b
  erroneous value.  But this effectively falls back to the mokdisabled
4fe85b
  behavior, which works correctly, and the presence of the "grub" (i.e.
4fe85b
  no shim) tests effectively tests the desired behavior here.
4fe85b
4fe85b
Resolves: rhbz#1344512
4fe85b
4fe85b
Signed-off-by: Peter Jones <pjones@redhat.com>
4fe85b
---
4fe85b
 grub-core/kern/efi/sb.c            |  14 +++--
4fe85b
 grub-core/loader/arm64/linux.c     |   4 +-
4fe85b
 grub-core/loader/efi/chainloader.c | 117 ++++++++++++++++++++++---------------
4fe85b
 grub-core/loader/efi/linux.c       |  13 +++--
4fe85b
 grub-core/loader/i386/efi/linux.c  |  10 +++-
4fe85b
 include/grub/efi/linux.h           |   2 +-
4fe85b
 6 files changed, 100 insertions(+), 60 deletions(-)
4fe85b
4fe85b
diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
4fe85b
index a41b6c5b851..d74778b0cac 100644
4fe85b
--- a/grub-core/kern/efi/sb.c
4fe85b
+++ b/grub-core/kern/efi/sb.c
4fe85b
@@ -36,14 +36,20 @@ grub_efi_secure_boot (void)
4fe85b
   grub_efi_boolean_t ret = 0;
4fe85b
 
4fe85b
   secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
4fe85b
-
4fe85b
   if (datasize != 1 || !secure_boot)
4fe85b
-    goto out;
4fe85b
+    {
4fe85b
+      grub_dprintf ("secureboot", "No SecureBoot variable\n");
4fe85b
+      goto out;
4fe85b
+    }
4fe85b
+  grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot);
4fe85b
 
4fe85b
   setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
4fe85b
-
4fe85b
   if (datasize != 1 || !setup_mode)
4fe85b
-    goto out;
4fe85b
+    {
4fe85b
+      grub_dprintf ("secureboot", "No SetupMode variable\n");
4fe85b
+      goto out;
4fe85b
+    }
4fe85b
+  grub_dprintf ("secureboot", "SetupMode: %d\n", *setup_mode);
4fe85b
 
4fe85b
   if (*secure_boot && !*setup_mode)
4fe85b
     ret = 1;
4fe85b
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
4fe85b
index bdd9c9b4968..0452a20e98b 100644
4fe85b
--- a/grub-core/loader/arm64/linux.c
4fe85b
+++ b/grub-core/loader/arm64/linux.c
4fe85b
@@ -380,6 +380,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
4fe85b
   grub_file_t file = 0;
4fe85b
   struct grub_arm64_linux_kernel_header lh;
4fe85b
   struct grub_arm64_linux_pe_header *pe;
4fe85b
+  int rc;
4fe85b
 
4fe85b
   grub_dl_ref (my_mod);
4fe85b
 
4fe85b
@@ -424,7 +425,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
4fe85b
 
4fe85b
   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
4fe85b
 
4fe85b
-  if (!grub_linuxefi_secure_validate (kernel_addr, kernel_size))
4fe85b
+  rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
4fe85b
+  if (rc < 0)
4fe85b
     {
4fe85b
       grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
4fe85b
       goto fail;
4fe85b
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
4fe85b
index 4b77a7d5adb..3e89de9006c 100644
4fe85b
--- a/grub-core/loader/efi/chainloader.c
4fe85b
+++ b/grub-core/loader/efi/chainloader.c
4fe85b
@@ -182,7 +182,6 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
4fe85b
   /* Fill the file path for the directory.  */
4fe85b
   d = (grub_efi_device_path_t *) ((char *) file_path
4fe85b
 				  + ((char *) d - (char *) dp));
4fe85b
-  grub_efi_print_device_path (d);
4fe85b
   copy_file_path ((grub_efi_file_path_device_path_t *) d,
4fe85b
 		  dir_start, dir_end - dir_start);
4fe85b
 
4fe85b
@@ -252,10 +251,9 @@ read_header (void *data, grub_efi_uint32_t size,
4fe85b
   grub_efi_status_t status;
4fe85b
 
4fe85b
   shim_lock = grub_efi_locate_protocol (&guid, NULL);
4fe85b
-
4fe85b
   if (!shim_lock)
4fe85b
     {
4fe85b
-      grub_error (GRUB_ERR_BAD_ARGUMENT, "no shim lock protocol");
4fe85b
+      grub_dprintf ("chain", "no shim lock protocol");
4fe85b
       return 0;
4fe85b
     }
4fe85b
 
4fe85b
@@ -280,7 +278,7 @@ read_header (void *data, grub_efi_uint32_t size,
4fe85b
       break;
4fe85b
     }
4fe85b
 
4fe85b
-  return 0;
4fe85b
+  return -1;
4fe85b
 }
4fe85b
 
4fe85b
 static void*
4fe85b
@@ -514,18 +512,25 @@ handle_image (void *data, grub_efi_uint32_t datasize)
4fe85b
   grub_uint32_t section_alignment;
4fe85b
   grub_uint32_t buffer_size;
4fe85b
   int found_entry_point = 0;
4fe85b
+  int rc;
4fe85b
 
4fe85b
   b = grub_efi_system_table->boot_services;
4fe85b
 
4fe85b
-  if (read_header (data, datasize, &context))
4fe85b
-    {
4fe85b
-      grub_dprintf ("chain", "Succeed to read header\n");
4fe85b
-    }
4fe85b
-  else
4fe85b
+  rc = read_header (data, datasize, &context);
4fe85b
+  if (rc < 0)
4fe85b
     {
4fe85b
       grub_dprintf ("chain", "Failed to read header\n");
4fe85b
       goto error_exit;
4fe85b
     }
4fe85b
+  else if (rc == 0)
4fe85b
+    {
4fe85b
+      grub_dprintf ("chain", "Secure Boot is not enabled\n");
4fe85b
+      return 0;
4fe85b
+    }
4fe85b
+  else
4fe85b
+    {
4fe85b
+      grub_dprintf ("chain", "Header read without error\n");
4fe85b
+    }
4fe85b
 
4fe85b
   /*
4fe85b
    * The spec says, uselessly, of SectionAlignment:
4fe85b
@@ -796,10 +801,56 @@ grub_secureboot_chainloader_unload (void)
4fe85b
   return GRUB_ERR_NONE;
4fe85b
 }
4fe85b
 
4fe85b
+static grub_err_t
4fe85b
+grub_load_and_start_image(void *boot_image)
4fe85b
+{
4fe85b
+  grub_efi_boot_services_t *b;
4fe85b
+  grub_efi_status_t status;
4fe85b
+  grub_efi_loaded_image_t *loaded_image;
4fe85b
+
4fe85b
+  b = grub_efi_system_table->boot_services;
4fe85b
+
4fe85b
+  status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
4fe85b
+		       boot_image, fsize, &image_handle);
4fe85b
+  if (status != GRUB_EFI_SUCCESS)
4fe85b
+    {
4fe85b
+      if (status == GRUB_EFI_OUT_OF_RESOURCES)
4fe85b
+	grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
4fe85b
+      else
4fe85b
+	grub_error (GRUB_ERR_BAD_OS, "cannot load image");
4fe85b
+      return -1;
4fe85b
+    }
4fe85b
+
4fe85b
+  /* LoadImage does not set a device handler when the image is
4fe85b
+     loaded from memory, so it is necessary to set it explicitly here.
4fe85b
+     This is a mess.  */
4fe85b
+  loaded_image = grub_efi_get_loaded_image (image_handle);
4fe85b
+  if (! loaded_image)
4fe85b
+    {
4fe85b
+      grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
4fe85b
+      return -1;
4fe85b
+    }
4fe85b
+  loaded_image->device_handle = dev_handle;
4fe85b
+
4fe85b
+  if (cmdline)
4fe85b
+    {
4fe85b
+      loaded_image->load_options = cmdline;
4fe85b
+      loaded_image->load_options_size = cmdline_len;
4fe85b
+    }
4fe85b
+
4fe85b
+  return 0;
4fe85b
+}
4fe85b
+
4fe85b
 static grub_err_t
4fe85b
 grub_secureboot_chainloader_boot (void)
4fe85b
 {
4fe85b
-  handle_image ((void *)address, fsize);
4fe85b
+  int rc;
4fe85b
+  rc = handle_image ((void *)address, fsize);
4fe85b
+  if (rc == 0)
4fe85b
+    {
4fe85b
+      grub_load_and_start_image((void *)address);
4fe85b
+    }
4fe85b
+
4fe85b
   grub_loader_unset ();
4fe85b
   return grub_errno;
4fe85b
 }
4fe85b
@@ -813,9 +864,9 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
4fe85b
   grub_efi_boot_services_t *b;
4fe85b
   grub_device_t dev = 0;
4fe85b
   grub_efi_device_path_t *dp = 0;
4fe85b
-  grub_efi_loaded_image_t *loaded_image;
4fe85b
   char *filename;
4fe85b
   void *boot_image = 0;
4fe85b
+  int rc;
4fe85b
 
4fe85b
   if (argc == 0)
4fe85b
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
4fe85b
@@ -902,9 +953,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
4fe85b
   if (! file_path)
4fe85b
     goto fail;
4fe85b
 
4fe85b
-  grub_printf ("file path: ");
4fe85b
-  grub_efi_print_device_path (file_path);
4fe85b
-
4fe85b
   fsize = grub_file_size (file);
4fe85b
   if (!fsize)
4fe85b
     {
4fe85b
@@ -979,51 +1027,28 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
4fe85b
     }
4fe85b
 #endif
4fe85b
 
4fe85b
-  if (grub_linuxefi_secure_validate((void *)address, fsize))
4fe85b
+  rc = grub_linuxefi_secure_validate((void *)address, fsize);
4fe85b
+  grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc);
4fe85b
+  if (rc > 0)
4fe85b
     {
4fe85b
       grub_file_close (file);
4fe85b
       grub_loader_set (grub_secureboot_chainloader_boot,
4fe85b
 		       grub_secureboot_chainloader_unload, 0);
4fe85b
       return 0;
4fe85b
     }
4fe85b
-
4fe85b
-  status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
4fe85b
-		       boot_image, fsize, &image_handle);
4fe85b
-  if (status != GRUB_EFI_SUCCESS)
4fe85b
+  else if (rc == 0)
4fe85b
     {
4fe85b
-      if (status == GRUB_EFI_OUT_OF_RESOURCES)
4fe85b
-	grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
4fe85b
-      else
4fe85b
-	grub_error (GRUB_ERR_BAD_OS, "cannot load image");
4fe85b
-
4fe85b
-      goto fail;
4fe85b
-    }
4fe85b
+      grub_load_and_start_image(boot_image);
4fe85b
+      grub_file_close (file);
4fe85b
+      grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
4fe85b
 
4fe85b
-  /* LoadImage does not set a device handler when the image is
4fe85b
-     loaded from memory, so it is necessary to set it explicitly here.
4fe85b
-     This is a mess.  */
4fe85b
-  loaded_image = grub_efi_get_loaded_image (image_handle);
4fe85b
-  if (! loaded_image)
4fe85b
-    {
4fe85b
-      grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
4fe85b
-      goto fail;
4fe85b
-    }
4fe85b
-  loaded_image->device_handle = dev_handle;
4fe85b
-
4fe85b
-  if (cmdline)
4fe85b
-    {
4fe85b
-      loaded_image->load_options = cmdline;
4fe85b
-      loaded_image->load_options_size = cmdline_len;
4fe85b
+      return 0;
4fe85b
     }
4fe85b
 
4fe85b
   grub_file_close (file);
4fe85b
   grub_device_close (dev);
4fe85b
 
4fe85b
-  grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
4fe85b
-  return 0;
4fe85b
-
4fe85b
- fail:
4fe85b
-
4fe85b
+fail:
4fe85b
   if (dev)
4fe85b
     grub_device_close (dev);
4fe85b
 
4fe85b
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
4fe85b
index aea378adf5c..8890bdf059a 100644
4fe85b
--- a/grub-core/loader/efi/linux.c
4fe85b
+++ b/grub-core/loader/efi/linux.c
4fe85b
@@ -33,21 +33,24 @@ struct grub_efi_shim_lock
4fe85b
 };
4fe85b
 typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
4fe85b
 
4fe85b
-grub_efi_boolean_t
4fe85b
+int
4fe85b
 grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
4fe85b
 {
4fe85b
   grub_efi_guid_t guid = SHIM_LOCK_GUID;
4fe85b
   grub_efi_shim_lock_t *shim_lock;
4fe85b
+  grub_efi_status_t status;
4fe85b
 
4fe85b
   shim_lock = grub_efi_locate_protocol(&guid, NULL);
4fe85b
-
4fe85b
+  grub_dprintf ("secureboot", "shim_lock: %p\n", shim_lock);
4fe85b
   if (!shim_lock)
4fe85b
-    return 1;
4fe85b
+    return 0;
4fe85b
 
4fe85b
-  if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
4fe85b
+  status = shim_lock->verify(data, size);
4fe85b
+  grub_dprintf ("secureboot", "shim_lock->verify(): %ld\n", status);
4fe85b
+  if (status == GRUB_EFI_SUCCESS)
4fe85b
     return 1;
4fe85b
 
4fe85b
-  return 0;
4fe85b
+  return -1;
4fe85b
 }
4fe85b
 
4fe85b
 typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
4fe85b
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
4fe85b
index 7ccf32d9d45..82f75b7f3ab 100644
4fe85b
--- a/grub-core/loader/i386/efi/linux.c
4fe85b
+++ b/grub-core/loader/i386/efi/linux.c
4fe85b
@@ -155,6 +155,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
4fe85b
   struct linux_kernel_header lh;
4fe85b
   grub_ssize_t len, start, filelen;
4fe85b
   void *kernel = NULL;
4fe85b
+  int rc;
4fe85b
 
4fe85b
   grub_dl_ref (my_mod);
4fe85b
 
4fe85b
@@ -180,13 +181,16 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
4fe85b
 
4fe85b
   if (grub_file_read (file, kernel, filelen) != filelen)
4fe85b
     {
4fe85b
-      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]);
4fe85b
+      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"),
4fe85b
+		  argv[0]);
4fe85b
       goto fail;
4fe85b
     }
4fe85b
 
4fe85b
-  if (! grub_linuxefi_secure_validate (kernel, filelen))
4fe85b
+  rc = grub_linuxefi_secure_validate (kernel, filelen);
4fe85b
+  if (rc < 0)
4fe85b
     {
4fe85b
-      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
4fe85b
+      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"),
4fe85b
+		  argv[0]);
4fe85b
       grub_free (kernel);
4fe85b
       goto fail;
4fe85b
     }
4fe85b
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
4fe85b
index d9ede36773b..0033d9305a9 100644
4fe85b
--- a/include/grub/efi/linux.h
4fe85b
+++ b/include/grub/efi/linux.h
4fe85b
@@ -22,7 +22,7 @@
4fe85b
 #include <grub/err.h>
4fe85b
 #include <grub/symbol.h>
4fe85b
 
4fe85b
-grub_efi_boolean_t
4fe85b
+int
4fe85b
 EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
4fe85b
 grub_err_t
4fe85b
 EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,