konradr / rpms / grub2

Forked from rpms/grub2 6 years ago
Clone
1d9771a
From 8b4deb97529ba7ff689a11639f2a5bfdb29ad2ea Mon Sep 17 00:00:00 2001
1d9771a
From: Peter Jones <pjones@redhat.com>
1d9771a
Date: Fri, 10 Jun 2016 14:06:15 -0400
1d9771a
Subject: [PATCH 83/87] Rework even more of efi chainload so non-sb cases work
1d9771a
 right.
1d9771a
1d9771a
This ensures that if shim protocol is not loaded, or is loaded but shim
1d9771a
is disabled, we will fall back to a correct load method for the efi
1d9771a
chain loader.
1d9771a
1d9771a
Here's what I tested with this version:
1d9771a
1d9771a
results                             expected    actual
1d9771a
------------------------------------------------------------
1d9771a
sb + enabled + shim + fedora        success     success
1d9771a
sb + enabled + shim + win           success     success
1d9771a
sb + enabled + grub + fedora        fail        fail
1d9771a
sb + enabled + grub + win           fail        fail
1d9771a
1d9771a
sb + mokdisabled + shim + fedora    success     success
1d9771a
sb + mokdisabled + shim + win       success     success
1d9771a
sb + mokdisabled + grub + fedora    fail        fail
1d9771a
sb + mokdisabled + grub + win       fail        fail
1d9771a
1d9771a
sb disabled + shim + fedora         success     success*
1d9771a
sb disabled + shim + win            success     success*
1d9771a
sb disabled + grub + fedora         success     success
1d9771a
sb disabled + grub + win            success     success
1d9771a
1d9771a
nosb + shim + fedora                success     success*
1d9771a
nosb + shim + win                   success     success*
1d9771a
nosb + grub + fedora                success     success
1d9771a
nosb + grub + win                   success     success
1d9771a
1d9771a
* for some reason shim protocol is being installed in these cases, and I
1d9771a
  can't see why, but I think it may be this firmware build returning an
1d9771a
  erroneous value.  But this effectively falls back to the mokdisabled
1d9771a
  behavior, which works correctly, and the presence of the "grub" (i.e.
1d9771a
  no shim) tests effectively tests the desired behavior here.
1d9771a
1d9771a
Resolves: rhbz#1344512
1d9771a
1d9771a
Signed-off-by: Peter Jones <pjones@redhat.com>
1d9771a
---
1d9771a
 grub-core/kern/efi/sb.c            |  14 +++--
1d9771a
 grub-core/loader/arm64/linux.c     |   4 +-
1d9771a
 grub-core/loader/efi/chainloader.c | 115 ++++++++++++++++++++++---------------
1d9771a
 grub-core/loader/efi/linux.c       |  13 +++--
1d9771a
 grub-core/loader/i386/efi/linux.c  |  10 +++-
1d9771a
 include/grub/efi/linux.h           |   2 +-
1d9771a
 6 files changed, 99 insertions(+), 59 deletions(-)
1d9771a
1d9771a
diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
1d9771a
index a41b6c5..d74778b 100644
1d9771a
--- a/grub-core/kern/efi/sb.c
1d9771a
+++ b/grub-core/kern/efi/sb.c
1d9771a
@@ -36,14 +36,20 @@ grub_efi_secure_boot (void)
1d9771a
   grub_efi_boolean_t ret = 0;
1d9771a
 
1d9771a
   secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
1d9771a
-
1d9771a
   if (datasize != 1 || !secure_boot)
1d9771a
-    goto out;
1d9771a
+    {
1d9771a
+      grub_dprintf ("secureboot", "No SecureBoot variable\n");
1d9771a
+      goto out;
1d9771a
+    }
1d9771a
+  grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot);
1d9771a
 
1d9771a
   setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
1d9771a
-
1d9771a
   if (datasize != 1 || !setup_mode)
1d9771a
-    goto out;
1d9771a
+    {
1d9771a
+      grub_dprintf ("secureboot", "No SetupMode variable\n");
1d9771a
+      goto out;
1d9771a
+    }
1d9771a
+  grub_dprintf ("secureboot", "SetupMode: %d\n", *setup_mode);
1d9771a
 
1d9771a
   if (*secure_boot && !*setup_mode)
1d9771a
     ret = 1;
1d9771a
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
1d9771a
index 4756ef7..f83820e 100644
1d9771a
--- a/grub-core/loader/arm64/linux.c
1d9771a
+++ b/grub-core/loader/arm64/linux.c
1d9771a
@@ -251,6 +251,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
1d9771a
   grub_file_t file = 0;
1d9771a
   struct grub_arm64_linux_kernel_header lh;
1d9771a
   struct grub_arm64_linux_pe_header *pe;
1d9771a
+  int rc;
1d9771a
 
1d9771a
   grub_dl_ref (my_mod);
1d9771a
 
1d9771a
@@ -295,7 +296,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
1d9771a
 
1d9771a
   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
1d9771a
 
1d9771a
-  if (!grub_linuxefi_secure_validate (kernel_addr, kernel_size))
1d9771a
+  rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
1d9771a
+  if (rc < 0)
1d9771a
     {
1d9771a
       grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
1d9771a
       goto fail;
1d9771a
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
1d9771a
index 323f873..49a7662 100644
1d9771a
--- a/grub-core/loader/efi/chainloader.c
1d9771a
+++ b/grub-core/loader/efi/chainloader.c
1d9771a
@@ -178,7 +178,6 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
1d9771a
   /* Fill the file path for the directory.  */
1d9771a
   d = (grub_efi_device_path_t *) ((char *) file_path
1d9771a
 				  + ((char *) d - (char *) dp));
1d9771a
-  grub_efi_print_device_path (d);
1d9771a
   copy_file_path ((grub_efi_file_path_device_path_t *) d,
1d9771a
 		  dir_start, dir_end - dir_start);
1d9771a
 
1d9771a
@@ -248,10 +247,9 @@ read_header (void *data, grub_efi_uint32_t size,
1d9771a
   grub_efi_status_t status;
1d9771a
 
1d9771a
   shim_lock = grub_efi_locate_protocol (&guid, NULL);
1d9771a
-
1d9771a
   if (!shim_lock)
1d9771a
     {
1d9771a
-      grub_error (GRUB_ERR_BAD_ARGUMENT, "no shim lock protocol");
1d9771a
+      grub_dprintf ("chain", "no shim lock protocol");
1d9771a
       return 0;
1d9771a
     }
1d9771a
 
1d9771a
@@ -276,7 +274,7 @@ read_header (void *data, grub_efi_uint32_t size,
1d9771a
       break;
1d9771a
     }
1d9771a
 
1d9771a
-  return 0;
1d9771a
+  return -1;
1d9771a
 }
1d9771a
 
1d9771a
 static void*
1d9771a
@@ -510,17 +508,24 @@ handle_image (void *data, grub_efi_uint32_t datasize)
1d9771a
   grub_uint32_t section_alignment;
1d9771a
   grub_uint32_t buffer_size;
1d9771a
   int found_entry_point = 0;
1d9771a
+  int rc;
1d9771a
 
1d9771a
   b = grub_efi_system_table->boot_services;
1d9771a
 
1d9771a
-  if (read_header (data, datasize, &context))
1d9771a
+  rc = read_header (data, datasize, &context);
1d9771a
+  if (rc < 0)
1d9771a
     {
1d9771a
-      grub_dprintf ("chain", "Succeed to read header\n");
1d9771a
+      grub_dprintf ("chain", "Failed to read header\n");
1d9771a
+      goto error_exit;
1d9771a
+    }
1d9771a
+  else if (rc == 0)
1d9771a
+    {
1d9771a
+      grub_dprintf ("chain", "Secure Boot is not enabled\n");
1d9771a
+      return 0;
1d9771a
     }
1d9771a
   else
1d9771a
     {
1d9771a
-      grub_dprintf ("chain", "Failed to read header\n");
1d9771a
-      goto error_exit;
1d9771a
+      grub_dprintf ("chain", "Header read without error\n");
1d9771a
     }
1d9771a
 
1d9771a
   /*
1d9771a
@@ -793,9 +798,55 @@ grub_secureboot_chainloader_unload (void)
1d9771a
 }
1d9771a
 
1d9771a
 static grub_err_t
1d9771a
+grub_load_and_start_image(void *boot_image)
1d9771a
+{
1d9771a
+  grub_efi_boot_services_t *b;
1d9771a
+  grub_efi_status_t status;
1d9771a
+  grub_efi_loaded_image_t *loaded_image;
1d9771a
+
1d9771a
+  b = grub_efi_system_table->boot_services;
1d9771a
+
1d9771a
+  status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
1d9771a
+		       boot_image, fsize, &image_handle);
1d9771a
+  if (status != GRUB_EFI_SUCCESS)
1d9771a
+    {
1d9771a
+      if (status == GRUB_EFI_OUT_OF_RESOURCES)
1d9771a
+	grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
1d9771a
+      else
1d9771a
+	grub_error (GRUB_ERR_BAD_OS, "cannot load image");
1d9771a
+      return -1;
1d9771a
+    }
1d9771a
+
1d9771a
+  /* LoadImage does not set a device handler when the image is
1d9771a
+     loaded from memory, so it is necessary to set it explicitly here.
1d9771a
+     This is a mess.  */
1d9771a
+  loaded_image = grub_efi_get_loaded_image (image_handle);
1d9771a
+  if (! loaded_image)
1d9771a
+    {
1d9771a
+      grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
1d9771a
+      return -1;
1d9771a
+    }
1d9771a
+  loaded_image->device_handle = dev_handle;
1d9771a
+
1d9771a
+  if (cmdline)
1d9771a
+    {
1d9771a
+      loaded_image->load_options = cmdline;
1d9771a
+      loaded_image->load_options_size = cmdline_len;
1d9771a
+    }
1d9771a
+
1d9771a
+  return 0;
1d9771a
+}
1d9771a
+
1d9771a
+static grub_err_t
1d9771a
 grub_secureboot_chainloader_boot (void)
1d9771a
 {
1d9771a
-  handle_image ((void *)address, fsize);
1d9771a
+  int rc;
1d9771a
+  rc = handle_image ((void *)address, fsize);
1d9771a
+  if (rc == 0)
1d9771a
+    {
1d9771a
+      grub_load_and_start_image((void *)address);
1d9771a
+    }
1d9771a
+
1d9771a
   grub_loader_unset ();
1d9771a
   return grub_errno;
1d9771a
 }
1d9771a
@@ -809,9 +860,9 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
1d9771a
   grub_efi_boot_services_t *b;
1d9771a
   grub_device_t dev = 0;
1d9771a
   grub_efi_device_path_t *dp = 0;
1d9771a
-  grub_efi_loaded_image_t *loaded_image;
1d9771a
   char *filename;
1d9771a
   void *boot_image = 0;
1d9771a
+  int rc;
1d9771a
 
1d9771a
   if (argc == 0)
1d9771a
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
1d9771a
@@ -898,9 +949,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
1d9771a
   if (! file_path)
1d9771a
     goto fail;
1d9771a
 
1d9771a
-  grub_printf ("file path: ");
1d9771a
-  grub_efi_print_device_path (file_path);
1d9771a
-
1d9771a
   fsize = grub_file_size (file);
1d9771a
   if (!fsize)
1d9771a
     {
1d9771a
@@ -975,51 +1023,28 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
1d9771a
     }
1d9771a
 #endif
1d9771a
 
1d9771a
-  if (grub_linuxefi_secure_validate((void *)address, fsize))
1d9771a
+  rc = grub_linuxefi_secure_validate((void *)address, fsize);
1d9771a
+  grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc);
1d9771a
+  if (rc > 0)
1d9771a
     {
1d9771a
       grub_file_close (file);
1d9771a
       grub_loader_set (grub_secureboot_chainloader_boot,
1d9771a
 		       grub_secureboot_chainloader_unload, 0);
1d9771a
       return 0;
1d9771a
     }
1d9771a
-
1d9771a
-  status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
1d9771a
-		       boot_image, fsize, &image_handle);
1d9771a
-  if (status != GRUB_EFI_SUCCESS)
1d9771a
+  else if (rc == 0)
1d9771a
     {
1d9771a
-      if (status == GRUB_EFI_OUT_OF_RESOURCES)
1d9771a
-	grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
1d9771a
-      else
1d9771a
-	grub_error (GRUB_ERR_BAD_OS, "cannot load image");
1d9771a
-
1d9771a
-      goto fail;
1d9771a
-    }
1d9771a
-
1d9771a
-  /* LoadImage does not set a device handler when the image is
1d9771a
-     loaded from memory, so it is necessary to set it explicitly here.
1d9771a
-     This is a mess.  */
1d9771a
-  loaded_image = grub_efi_get_loaded_image (image_handle);
1d9771a
-  if (! loaded_image)
1d9771a
-    {
1d9771a
-      grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
1d9771a
-      goto fail;
1d9771a
-    }
1d9771a
-  loaded_image->device_handle = dev_handle;
1d9771a
+      grub_load_and_start_image(boot_image);
1d9771a
+      grub_file_close (file);
1d9771a
+      grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
1d9771a
 
1d9771a
-  if (cmdline)
1d9771a
-    {
1d9771a
-      loaded_image->load_options = cmdline;
1d9771a
-      loaded_image->load_options_size = cmdline_len;
1d9771a
+      return 0;
1d9771a
     }
1d9771a
 
1d9771a
   grub_file_close (file);
1d9771a
   grub_device_close (dev);
1d9771a
 
1d9771a
-  grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
1d9771a
-  return 0;
1d9771a
-
1d9771a
- fail:
1d9771a
-
1d9771a
+fail:
1d9771a
   if (dev)
1d9771a
     grub_device_close (dev);
1d9771a
 
1d9771a
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
1d9771a
index aea378a..8890bdf 100644
1d9771a
--- a/grub-core/loader/efi/linux.c
1d9771a
+++ b/grub-core/loader/efi/linux.c
1d9771a
@@ -33,21 +33,24 @@ struct grub_efi_shim_lock
1d9771a
 };
1d9771a
 typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
1d9771a
 
1d9771a
-grub_efi_boolean_t
1d9771a
+int
1d9771a
 grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
1d9771a
 {
1d9771a
   grub_efi_guid_t guid = SHIM_LOCK_GUID;
1d9771a
   grub_efi_shim_lock_t *shim_lock;
1d9771a
+  grub_efi_status_t status;
1d9771a
 
1d9771a
   shim_lock = grub_efi_locate_protocol(&guid, NULL);
1d9771a
-
1d9771a
+  grub_dprintf ("secureboot", "shim_lock: %p\n", shim_lock);
1d9771a
   if (!shim_lock)
1d9771a
-    return 1;
1d9771a
+    return 0;
1d9771a
 
1d9771a
-  if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
1d9771a
+  status = shim_lock->verify(data, size);
1d9771a
+  grub_dprintf ("secureboot", "shim_lock->verify(): %ld\n", status);
1d9771a
+  if (status == GRUB_EFI_SUCCESS)
1d9771a
     return 1;
1d9771a
 
1d9771a
-  return 0;
1d9771a
+  return -1;
1d9771a
 }
1d9771a
 
1d9771a
 typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
1d9771a
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
1d9771a
index 7ccf32d..82f75b7 100644
1d9771a
--- a/grub-core/loader/i386/efi/linux.c
1d9771a
+++ b/grub-core/loader/i386/efi/linux.c
1d9771a
@@ -155,6 +155,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
1d9771a
   struct linux_kernel_header lh;
1d9771a
   grub_ssize_t len, start, filelen;
1d9771a
   void *kernel = NULL;
1d9771a
+  int rc;
1d9771a
 
1d9771a
   grub_dl_ref (my_mod);
1d9771a
 
1d9771a
@@ -180,13 +181,16 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
1d9771a
 
1d9771a
   if (grub_file_read (file, kernel, filelen) != filelen)
1d9771a
     {
1d9771a
-      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]);
1d9771a
+      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"),
1d9771a
+		  argv[0]);
1d9771a
       goto fail;
1d9771a
     }
1d9771a
 
1d9771a
-  if (! grub_linuxefi_secure_validate (kernel, filelen))
1d9771a
+  rc = grub_linuxefi_secure_validate (kernel, filelen);
1d9771a
+  if (rc < 0)
1d9771a
     {
1d9771a
-      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
1d9771a
+      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"),
1d9771a
+		  argv[0]);
1d9771a
       grub_free (kernel);
1d9771a
       goto fail;
1d9771a
     }
1d9771a
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
1d9771a
index d9ede36..0033d93 100644
1d9771a
--- a/include/grub/efi/linux.h
1d9771a
+++ b/include/grub/efi/linux.h
1d9771a
@@ -22,7 +22,7 @@
1d9771a
 #include <grub/err.h>
1d9771a
 #include <grub/symbol.h>
1d9771a
 
1d9771a
-grub_efi_boolean_t
1d9771a
+int
1d9771a
 EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
1d9771a
 grub_err_t
1d9771a
 EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
1d9771a
-- 
1d9771a
2.7.4
1d9771a