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