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

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