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

d41074
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
a85e8e
From: Peter Jones <pjones@redhat.com>
a85e8e
Date: Fri, 10 Jun 2016 14:06:15 -0400
d41074
Subject: [PATCH] Rework even more of efi chainload so non-sb cases 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 +-
d41074
 grub-core/loader/efi/chainloader.c | 117 ++++++++++++++++++++++---------------
a85e8e
 grub-core/loader/efi/linux.c       |  13 +++--
a85e8e
 grub-core/loader/i386/efi/linux.c  |  10 +++-
a85e8e
 include/grub/efi/linux.h           |   2 +-
d41074
 6 files changed, 100 insertions(+), 60 deletions(-)
a85e8e
a85e8e
diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
d41074
index a41b6c5b851..d74778b0cac 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
d41074
index bdd9c9b4968..0452a20e98b 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
d41074
index 4b77a7d5adb..3e89de9006c 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*
d41074
@@ -514,18 +512,25 @@ 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))
d41074
-    {
d41074
-      grub_dprintf ("chain", "Succeed to read header\n");
d41074
-    }
d41074
-  else
a85e8e
+  rc = read_header (data, datasize, &context);
a85e8e
+  if (rc < 0)
a85e8e
     {
d41074
       grub_dprintf ("chain", "Failed to read header\n");
d41074
       goto error_exit;
d41074
     }
a85e8e
+  else if (rc == 0)
a85e8e
+    {
a85e8e
+      grub_dprintf ("chain", "Secure Boot is not enabled\n");
a85e8e
+      return 0;
d41074
+    }
d41074
+  else
d41074
+    {
a85e8e
+      grub_dprintf ("chain", "Header read without error\n");
d41074
+    }
a85e8e
 
a85e8e
   /*
d41074
    * The spec says, uselessly, of SectionAlignment:
d41074
@@ -796,10 +801,56 @@ grub_secureboot_chainloader_unload (void)
d41074
   return GRUB_ERR_NONE;
a85e8e
 }
a85e8e
 
d41074
+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
+
d41074
 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
-    }
d41074
+      grub_load_and_start_image(boot_image);
d41074
+      grub_file_close (file);
d41074
+      grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
d41074
 
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;
d41074
-
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
d41074
index aea378adf5c..8890bdf059a 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
d41074
index 7ccf32d9d45..82f75b7f3ab 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
d41074
index d9ede36773b..0033d9305a9 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,