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

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