Blame SOURCES/0152-Load-arm-with-SB-enabled.patch

a85e8e
From 0c0ca3a51e6edda6900a3f812c3a442a57b9c8d1 Mon Sep 17 00:00:00 2001
a85e8e
From: Peter Jones <pjones@redhat.com>
a85e8e
Date: Thu, 18 Sep 2014 11:26:14 -0400
a85e8e
Subject: [PATCH 152/260] Load arm with SB enabled.
a85e8e
a85e8e
Make sure we actually try to validate secure boot on this platform (even
a85e8e
though we're not shipping it enabled by default.)
a85e8e
a85e8e
This means giving the kernel grub's loaded image as the vehicle for the
a85e8e
kernel command line, because we can't call systab->bs->LoadImage() if SB
a85e8e
is enabled.
a85e8e
---
a85e8e
 grub-core/Makefile.core.def       |   2 +
a85e8e
 grub-core/loader/arm64/linux.c    | 108 ++++++++++++++++++++------------------
a85e8e
 grub-core/loader/efi/linux.c      |  65 +++++++++++++++++++++++
a85e8e
 grub-core/loader/i386/efi/linux.c |  39 ++------------
a85e8e
 include/grub/arm64/linux.h        |   8 +++
a85e8e
 include/grub/efi/linux.h          |  31 +++++++++++
a85e8e
 6 files changed, 166 insertions(+), 87 deletions(-)
a85e8e
 create mode 100644 grub-core/loader/efi/linux.c
a85e8e
 create mode 100644 include/grub/efi/linux.h
a85e8e
a85e8e
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
a85e8e
index 9ff9ae5a3..9378c7329 100644
a85e8e
--- a/grub-core/Makefile.core.def
a85e8e
+++ b/grub-core/Makefile.core.def
a85e8e
@@ -1682,6 +1682,7 @@ module = {
a85e8e
   ia64_efi = loader/ia64/efi/linux.c;
a85e8e
   arm = loader/arm/linux.c;
a85e8e
   arm64 = loader/arm64/linux.c;
a85e8e
+  arm64 = loader/efi/linux.c;
a85e8e
   fdt = lib/fdt.c;
a85e8e
   common = loader/linux.c;
a85e8e
   common = lib/cmdline.c;
a85e8e
@@ -1718,6 +1719,7 @@ module = {
a85e8e
   name = linuxefi;
a85e8e
   efi = loader/i386/efi/linux.c;
a85e8e
   efi = lib/cmdline.c;
a85e8e
+  efi = loader/efi/linux.c;
a85e8e
   enable = i386_efi;
a85e8e
   enable = x86_64_efi;
a85e8e
 };
a85e8e
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
a85e8e
index 0dc144e5d..bdd9c9b49 100644
a85e8e
--- a/grub-core/loader/arm64/linux.c
a85e8e
+++ b/grub-core/loader/arm64/linux.c
a85e8e
@@ -27,6 +27,7 @@
a85e8e
 #include <grub/types.h>
a85e8e
 #include <grub/cpu/linux.h>
a85e8e
 #include <grub/efi/efi.h>
a85e8e
+#include <grub/efi/linux.h>
a85e8e
 #include <grub/efi/pe32.h>
a85e8e
 #include <grub/i18n.h>
a85e8e
 #include <grub/lib/cmdline.h>
a85e8e
@@ -44,6 +45,7 @@ static int loaded;
a85e8e
 
a85e8e
 static void *kernel_addr;
a85e8e
 static grub_uint64_t kernel_size;
a85e8e
+static grub_uint32_t handover_offset;
a85e8e
 
a85e8e
 static char *linux_args;
a85e8e
 static grub_uint32_t cmdline_size;
a85e8e
@@ -135,7 +137,9 @@ finalize_params (void)
a85e8e
 {
a85e8e
   grub_efi_boot_services_t *b;
a85e8e
   grub_efi_status_t status;
a85e8e
+  grub_efi_loaded_image_t *loaded_image = NULL;
a85e8e
   int node, retval;
a85e8e
+  int len;
a85e8e
 
a85e8e
   get_fdt ();
a85e8e
   if (!fdt)
a85e8e
@@ -172,6 +176,23 @@ finalize_params (void)
a85e8e
   grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
a85e8e
 		fdt);
a85e8e
 
a85e8e
+  /* Convert command line to UCS-2 */
a85e8e
+  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
a85e8e
+  if (!loaded_image)
a85e8e
+    goto failure;
a85e8e
+
a85e8e
+  loaded_image->load_options_size = len =
a85e8e
+    (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
a85e8e
+  loaded_image->load_options =
a85e8e
+    grub_efi_allocate_pages (0,
a85e8e
+			     BYTES_TO_PAGES (loaded_image->load_options_size));
a85e8e
+  if (!loaded_image->load_options)
a85e8e
+    return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
a85e8e
+
a85e8e
+  loaded_image->load_options_size =
a85e8e
+    2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
a85e8e
+			    (grub_uint8_t *) linux_args, len, NULL);
a85e8e
+
a85e8e
   return GRUB_ERR_NONE;
a85e8e
 
a85e8e
 failure:
a85e8e
@@ -181,6 +202,23 @@ failure:
a85e8e
   return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
a85e8e
 }
a85e8e
 
a85e8e
+static void
a85e8e
+free_params (void)
a85e8e
+{
a85e8e
+  grub_efi_loaded_image_t *loaded_image = NULL;
a85e8e
+
a85e8e
+  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
a85e8e
+  if (loaded_image)
a85e8e
+    {
a85e8e
+      if (loaded_image->load_options)
a85e8e
+	grub_efi_free_pages ((grub_efi_physical_address_t)
a85e8e
+			      loaded_image->load_options,
a85e8e
+			     BYTES_TO_PAGES (loaded_image->load_options_size));
a85e8e
+      loaded_image->load_options = NULL;
a85e8e
+      loaded_image->load_options_size = 0;
a85e8e
+    }
a85e8e
+}
a85e8e
+
a85e8e
 static grub_err_t
a85e8e
 grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
a85e8e
 		     int argc, char *argv[])
a85e8e
@@ -199,6 +237,10 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
a85e8e
   if (argc != 1)
a85e8e
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
a85e8e
 
a85e8e
+  if (grub_efi_secure_boot ())
a85e8e
+    return grub_error (GRUB_ERR_INVALID_COMMAND,
a85e8e
+		       N_("Not loading devicetree - Secure Boot is enabled"));
a85e8e
+
a85e8e
   if (loaded_fdt)
a85e8e
     grub_free (loaded_fdt);
a85e8e
   loaded_fdt = NULL;
a85e8e
@@ -243,65 +285,20 @@ out:
a85e8e
 static grub_err_t
a85e8e
 grub_linux_boot (void)
a85e8e
 {
a85e8e
-  grub_efi_memory_mapped_device_path_t *mempath;
a85e8e
-  grub_efi_handle_t image_handle;
a85e8e
-  grub_efi_boot_services_t *b;
a85e8e
-  grub_efi_status_t status;
a85e8e
   grub_err_t retval;
a85e8e
-  grub_efi_loaded_image_t *loaded_image;
a85e8e
-  int len;
a85e8e
 
a85e8e
   retval = finalize_params();
a85e8e
   if (retval != GRUB_ERR_NONE)
a85e8e
     return retval;
a85e8e
 
a85e8e
-  mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t));
a85e8e
-  if (!mempath)
a85e8e
-    return grub_errno;
a85e8e
-
a85e8e
-  mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE;
a85e8e
-  mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE;
a85e8e
-  mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath));
a85e8e
-  mempath[0].memory_type = GRUB_EFI_LOADER_DATA;
a85e8e
-  mempath[0].start_address = (grub_addr_t) kernel_addr;
a85e8e
-  mempath[0].end_address = (grub_addr_t) kernel_addr + kernel_size;
a85e8e
-
a85e8e
-  mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE;
a85e8e
-  mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
a85e8e
-  mempath[1].header.length = sizeof (grub_efi_device_path_t);
a85e8e
-
a85e8e
-  b = grub_efi_system_table->boot_services;
a85e8e
-  status = b->load_image (0, grub_efi_image_handle,
a85e8e
-			  (grub_efi_device_path_t *) mempath,
a85e8e
-                          kernel_addr, kernel_size, &image_handle);
a85e8e
-  if (status != GRUB_EFI_SUCCESS)
a85e8e
-    return grub_error (GRUB_ERR_BAD_OS, "cannot load image");
a85e8e
-
a85e8e
   grub_dprintf ("linux", "linux command line: '%s'\n", linux_args);
a85e8e
 
a85e8e
-  /* Convert command line to UCS-2 */
a85e8e
-  loaded_image = grub_efi_get_loaded_image (image_handle);
a85e8e
-  loaded_image->load_options_size = len =
a85e8e
-    (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
a85e8e
-  loaded_image->load_options =
a85e8e
-    grub_efi_allocate_pages (0,
a85e8e
-			     BYTES_TO_PAGES (loaded_image->load_options_size));
a85e8e
-  if (!loaded_image->load_options)
a85e8e
-    return grub_errno;
a85e8e
+  retval = grub_efi_linux_boot ((char *)kernel_addr, handover_offset,
a85e8e
+				kernel_addr);
a85e8e
 
a85e8e
-  loaded_image->load_options_size =
a85e8e
-    2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
a85e8e
-			    (grub_uint8_t *) linux_args, len, NULL);
a85e8e
-
a85e8e
-  grub_dprintf("linux", "starting image %p\n", image_handle);
a85e8e
-  status = b->start_image (image_handle, 0, NULL);
a85e8e
-
a85e8e
-  /* When successful, not reached */
a85e8e
-  b->unload_image (image_handle);
a85e8e
-  grub_efi_free_pages ((grub_efi_physical_address_t) loaded_image->load_options,
a85e8e
-		       BYTES_TO_PAGES (loaded_image->load_options_size));
a85e8e
-
a85e8e
-  return grub_errno;
a85e8e
+  /* Never reached... */
a85e8e
+  free_params();
a85e8e
+  return retval;
a85e8e
 }
a85e8e
 
a85e8e
 static grub_err_t
a85e8e
@@ -382,6 +379,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
a85e8e
 {
a85e8e
   grub_file_t file = 0;
a85e8e
   struct grub_arm64_linux_kernel_header lh;
a85e8e
+  struct grub_arm64_linux_pe_header *pe;
a85e8e
 
a85e8e
   grub_dl_ref (my_mod);
a85e8e
 
a85e8e
@@ -426,6 +424,15 @@ 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
+    {
a85e8e
+      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
a85e8e
+      goto fail;
a85e8e
+    }
a85e8e
+
a85e8e
+  pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
a85e8e
+  handover_offset = pe->opt.entry_addr;
a85e8e
+
a85e8e
   cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
a85e8e
   linux_args = grub_malloc (cmdline_size);
a85e8e
   if (!linux_args)
a85e8e
@@ -464,7 +471,6 @@ fail:
a85e8e
   return grub_errno;
a85e8e
 }
a85e8e
 
a85e8e
-
a85e8e
 static grub_command_t cmd_linux, cmd_initrd, cmd_devicetree;
a85e8e
 
a85e8e
 GRUB_MOD_INIT (linux)
a85e8e
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
a85e8e
new file mode 100644
a85e8e
index 000000000..aea378adf
a85e8e
--- /dev/null
a85e8e
+++ b/grub-core/loader/efi/linux.c
a85e8e
@@ -0,0 +1,65 @@
a85e8e
+/*
a85e8e
+ *  GRUB  --  GRand Unified Bootloader
a85e8e
+ *  Copyright (C) 2014 Free Software Foundation, Inc.
a85e8e
+ *
a85e8e
+ *  GRUB is free software: you can redistribute it and/or modify
a85e8e
+ *  it under the terms of the GNU General Public License as published by
a85e8e
+ *  the Free Software Foundation, either version 3 of the License, or
a85e8e
+ *  (at your option) any later version.
a85e8e
+ *
a85e8e
+ *  GRUB is distributed in the hope that it will be useful,
a85e8e
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
a85e8e
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
a85e8e
+ *  GNU General Public License for more details.
a85e8e
+ *
a85e8e
+ *  You should have received a copy of the GNU General Public License
a85e8e
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
a85e8e
+ */
a85e8e
+
a85e8e
+#include <grub/err.h>
a85e8e
+#include <grub/mm.h>
a85e8e
+#include <grub/types.h>
a85e8e
+#include <grub/cpu/linux.h>
a85e8e
+#include <grub/efi/efi.h>
a85e8e
+#include <grub/efi/pe32.h>
a85e8e
+#include <grub/efi/linux.h>
a85e8e
+
a85e8e
+#define SHIM_LOCK_GUID \
a85e8e
+ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
a85e8e
+
a85e8e
+struct grub_efi_shim_lock
a85e8e
+{
a85e8e
+  grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
a85e8e
+};
a85e8e
+typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
a85e8e
+
a85e8e
+grub_efi_boolean_t
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
+
a85e8e
+  shim_lock = grub_efi_locate_protocol(&guid, NULL);
a85e8e
+
a85e8e
+  if (!shim_lock)
a85e8e
+    return 1;
a85e8e
+
a85e8e
+  if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
a85e8e
+    return 1;
a85e8e
+
a85e8e
+  return 0;
a85e8e
+}
a85e8e
+
a85e8e
+typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
a85e8e
+
a85e8e
+grub_err_t
a85e8e
+grub_efi_linux_boot (void *kernel_addr, grub_off_t offset,
a85e8e
+		     void *kernel_params)
a85e8e
+{
a85e8e
+  handover_func hf;
a85e8e
+
a85e8e
+  hf = (handover_func)((char *)kernel_addr + offset);
a85e8e
+  hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
a85e8e
+
a85e8e
+  return GRUB_ERR_BUG;
a85e8e
+}
a85e8e
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
a85e8e
index b79e6320b..e5b778577 100644
a85e8e
--- a/grub-core/loader/i386/efi/linux.c
a85e8e
+++ b/grub-core/loader/i386/efi/linux.c
a85e8e
@@ -26,6 +26,7 @@
a85e8e
 #include <grub/i18n.h>
a85e8e
 #include <grub/lib/cmdline.h>
a85e8e
 #include <grub/efi/efi.h>
a85e8e
+#include <grub/efi/linux.h>
a85e8e
 
a85e8e
 GRUB_MOD_LICENSE ("GPLv3+");
a85e8e
 
a85e8e
@@ -40,52 +41,18 @@ static char *linux_cmdline;
a85e8e
 
a85e8e
 #define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
a85e8e
 
a85e8e
-#define SHIM_LOCK_GUID \
a85e8e
-  { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
a85e8e
-
a85e8e
-struct grub_efi_shim_lock
a85e8e
-{
a85e8e
-  grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
a85e8e
-};
a85e8e
-typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
a85e8e
-
a85e8e
-static grub_efi_boolean_t
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
-
a85e8e
-  shim_lock = grub_efi_locate_protocol(&guid, NULL);
a85e8e
-
a85e8e
-  if (!shim_lock)
a85e8e
-    return 1;
a85e8e
-
a85e8e
-  if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
a85e8e
-    return 1;
a85e8e
-
a85e8e
-  return 0;
a85e8e
-}
a85e8e
-
a85e8e
-typedef void(*handover_func)(void *, grub_efi_system_table_t *, struct linux_kernel_params *);
a85e8e
-
a85e8e
 static grub_err_t
a85e8e
 grub_linuxefi_boot (void)
a85e8e
 {
a85e8e
-  handover_func hf;
a85e8e
   int offset = 0;
a85e8e
 
a85e8e
 #ifdef __x86_64__
a85e8e
   offset = 512;
a85e8e
 #endif
a85e8e
-
a85e8e
-  hf = (handover_func)((char *)kernel_mem + handover_offset + offset);
a85e8e
-
a85e8e
   asm volatile ("cli");
a85e8e
 
a85e8e
-  hf (grub_efi_image_handle, grub_efi_system_table, params);
a85e8e
-
a85e8e
-  /* Not reached */
a85e8e
-  return GRUB_ERR_NONE;
a85e8e
+  return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset,
a85e8e
+			      params);
a85e8e
 }
a85e8e
 
a85e8e
 static grub_err_t
a85e8e
diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h
a85e8e
index 864e5dc36..2cbd64f8c 100644
a85e8e
--- a/include/grub/arm64/linux.h
a85e8e
+++ b/include/grub/arm64/linux.h
a85e8e
@@ -20,6 +20,7 @@
a85e8e
 #define GRUB_LINUX_CPU_HEADER 1
a85e8e
 
a85e8e
 #include <grub/efi/efi.h>
a85e8e
+#include <grub/efi/pe32.h>
a85e8e
 
a85e8e
 #define GRUB_ARM64_LINUX_MAGIC 0x644d5241 /* 'ARM\x64' */
a85e8e
 
a85e8e
@@ -38,4 +39,11 @@ struct grub_arm64_linux_kernel_header
a85e8e
   grub_uint32_t hdr_offset;	/* Offset of PE/COFF header */
a85e8e
 };
a85e8e
 
a85e8e
+struct grub_arm64_linux_pe_header
a85e8e
+{
a85e8e
+  grub_uint32_t magic;
a85e8e
+  struct grub_pe32_coff_header coff;
a85e8e
+  struct grub_pe64_optional_header opt;
a85e8e
+};
a85e8e
+
a85e8e
 #endif /* ! GRUB_LINUX_CPU_HEADER */
a85e8e
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
a85e8e
new file mode 100644
a85e8e
index 000000000..d9ede3677
a85e8e
--- /dev/null
a85e8e
+++ b/include/grub/efi/linux.h
a85e8e
@@ -0,0 +1,31 @@
a85e8e
+/*
a85e8e
+ *  GRUB  --  GRand Unified Bootloader
a85e8e
+ *  Copyright (C) 2014  Free Software Foundation, Inc.
a85e8e
+ *
a85e8e
+ *  GRUB is free software: you can redistribute it and/or modify
a85e8e
+ *  it under the terms of the GNU General Public License as published by
a85e8e
+ *  the Free Software Foundation, either version 3 of the License, or
a85e8e
+ *  (at your option) any later version.
a85e8e
+ *
a85e8e
+ *  GRUB is distributed in the hope that it will be useful,
a85e8e
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
a85e8e
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
a85e8e
+ *  GNU General Public License for more details.
a85e8e
+ *
a85e8e
+ *  You should have received a copy of the GNU General Public License
a85e8e
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
a85e8e
+ */
a85e8e
+#ifndef GRUB_EFI_LINUX_HEADER
a85e8e
+#define GRUB_EFI_LINUX_HEADER	1
a85e8e
+
a85e8e
+#include <grub/efi/api.h>
a85e8e
+#include <grub/err.h>
a85e8e
+#include <grub/symbol.h>
a85e8e
+
a85e8e
+grub_efi_boolean_t
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
+				  void *kernel_param);
a85e8e
+
a85e8e
+#endif /* ! GRUB_EFI_LINUX_HEADER */
a85e8e
-- 
a85e8e
2.13.0
a85e8e