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

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