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