nalika / rpms / grub2

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