dcavalca / rpms / grub2

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