3c4dd19
From edfc2b0952b1eacf95188e53167cc038e5ea0129 Mon Sep 17 00:00:00 2001
58fe9aa
From: Peter Jones <pjones@redhat.com>
58fe9aa
Date: Thu, 18 Sep 2014 11:26:14 -0400
3c4dd19
Subject: [PATCH 122/229] Load arm with SB enabled.
58fe9aa
58fe9aa
Make sure we actually try to validate secure boot on this platform (even
58fe9aa
though we're not shipping it enabled by default.)
58fe9aa
58fe9aa
This means giving the kernel grub's loaded image as the vehicle for the
58fe9aa
kernel command line, because we can't call systab->bs->LoadImage() if SB
58fe9aa
is enabled.
58fe9aa
---
b9efc54
 grub-core/Makefile.core.def       |   3 +
81987f4
 grub-core/loader/arm64/linux.c    | 121 ++++++++++++++++++++------------------
81987f4
 grub-core/loader/efi/linux.c      |  65 ++++++++++++++++++++
81987f4
 grub-core/loader/i386/efi/linux.c |  39 +-----------
b9efc54
 include/grub/arm64/linux.h        |   7 +++
9074bf3
 include/grub/efi/linux.h          |  31 ++++++++++
81987f4
 6 files changed, 173 insertions(+), 93 deletions(-)
58fe9aa
 create mode 100644 grub-core/loader/efi/linux.c
58fe9aa
 create mode 100644 include/grub/efi/linux.h
58fe9aa
58fe9aa
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
81987f4
index 7f3d5a2bfe6..5ae70204cd2 100644
58fe9aa
--- a/grub-core/Makefile.core.def
58fe9aa
+++ b/grub-core/Makefile.core.def
6f1e3d5
@@ -1709,6 +1709,8 @@ module = {
58fe9aa
   ia64_efi = loader/ia64/efi/linux.c;
58fe9aa
   arm = loader/arm/linux.c;
58fe9aa
   arm64 = loader/arm64/linux.c;
58fe9aa
+  arm64 = loader/efi/linux.c;
b9efc54
+  fdt = lib/fdt.c;
58fe9aa
   common = loader/linux.c;
58fe9aa
   common = lib/cmdline.c;
b9efc54
   enable = noemu;
6f1e3d5
@@ -1776,6 +1778,7 @@ module = {
58fe9aa
   name = linuxefi;
58fe9aa
   efi = loader/i386/efi/linux.c;
58fe9aa
   efi = lib/cmdline.c;
58fe9aa
+  efi = loader/efi/linux.c;
58fe9aa
   enable = i386_efi;
58fe9aa
   enable = x86_64_efi;
58fe9aa
 };
58fe9aa
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
81987f4
index 746edd10415..33345d37534 100644
58fe9aa
--- a/grub-core/loader/arm64/linux.c
58fe9aa
+++ b/grub-core/loader/arm64/linux.c
b9efc54
@@ -28,6 +28,7 @@
58fe9aa
 #include <grub/cpu/linux.h>
58fe9aa
 #include <grub/efi/efi.h>
bbc6a89
 #include <grub/efi/fdtload.h>
58fe9aa
+#include <grub/efi/linux.h>
58fe9aa
 #include <grub/efi/pe32.h>
58fe9aa
 #include <grub/i18n.h>
58fe9aa
 #include <grub/lib/cmdline.h>
b9efc54
@@ -39,6 +40,7 @@ static int loaded;
58fe9aa
 
58fe9aa
 static void *kernel_addr;
58fe9aa
 static grub_uint64_t kernel_size;
58fe9aa
+static grub_uint32_t handover_offset;
58fe9aa
 
58fe9aa
 static char *linux_args;
58fe9aa
 static grub_uint32_t cmdline_size;
bbc6a89
@@ -65,7 +67,8 @@ grub_arm64_uefi_check_image (struct grub_arm64_linux_kernel_header * lh)
b9efc54
 static grub_err_t
b9efc54
 finalize_params_linux (void)
b9efc54
 {
b9efc54
-  int node, retval;
58fe9aa
+  grub_efi_loaded_image_t *loaded_image = NULL;
b9efc54
+  int node, retval, len;
b9efc54
 
b9efc54
   void *fdt;
58fe9aa
 
81987f4
@@ -100,79 +103,73 @@ finalize_params_linux (void)
b9efc54
   if (grub_fdt_install() != GRUB_ERR_NONE)
8c6b1ac
     goto failure;
58fe9aa
 
81987f4
-  return GRUB_ERR_NONE;
81987f4
-
81987f4
-failure:
81987f4
-  grub_fdt_unload();
81987f4
-  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
81987f4
-}
81987f4
-
9074bf3
-grub_err_t
9074bf3
-grub_arm64_uefi_boot_image (grub_addr_t addr, grub_size_t size, char *args)
81987f4
-{
58fe9aa
-  grub_efi_memory_mapped_device_path_t *mempath;
58fe9aa
-  grub_efi_handle_t image_handle;
58fe9aa
-  grub_efi_boot_services_t *b;
58fe9aa
-  grub_efi_status_t status;
58fe9aa
-  grub_efi_loaded_image_t *loaded_image;
58fe9aa
-  int len;
9074bf3
-
58fe9aa
-  mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t));
58fe9aa
-  if (!mempath)
58fe9aa
-    return grub_errno;
9074bf3
-
58fe9aa
-  mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE;
58fe9aa
-  mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE;
58fe9aa
-  mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath));
58fe9aa
-  mempath[0].memory_type = GRUB_EFI_LOADER_DATA;
8c6b1ac
-  mempath[0].start_address = addr;
8c6b1ac
-  mempath[0].end_address = addr + size;
81987f4
-
58fe9aa
-  mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE;
58fe9aa
-  mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
58fe9aa
-  mempath[1].header.length = sizeof (grub_efi_device_path_t);
9074bf3
-
58fe9aa
-  b = grub_efi_system_table->boot_services;
58fe9aa
-  status = b->load_image (0, grub_efi_image_handle,
58fe9aa
-			  (grub_efi_device_path_t *) mempath,
8c6b1ac
-			  (void *) addr, size, &image_handle);
58fe9aa
-  if (status != GRUB_EFI_SUCCESS)
58fe9aa
-    return grub_error (GRUB_ERR_BAD_OS, "cannot load image");
81987f4
-
81987f4
-  grub_dprintf ("linux", "linux command line: '%s'\n", args);
81987f4
+  grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
81987f4
+		fdt);
81987f4
 
81987f4
   /* Convert command line to UCS-2 */
81987f4
-  loaded_image = grub_efi_get_loaded_image (image_handle);
81987f4
+  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
81987f4
+  if (!loaded_image)
81987f4
+    goto failure;
81987f4
+
81987f4
   loaded_image->load_options_size = len =
81987f4
-    (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t);
81987f4
+    (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
81987f4
   loaded_image->load_options =
81987f4
     grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
81987f4
   if (!loaded_image->load_options)
81987f4
-    return grub_errno;
81987f4
+    return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
81987f4
 
81987f4
   loaded_image->load_options_size =
81987f4
     2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
81987f4
-			    (grub_uint8_t *) args, len, NULL);
81987f4
+			    (grub_uint8_t *) linux_args, len, NULL);
81987f4
 
81987f4
-  grub_dprintf ("linux", "starting image %p\n", image_handle);
81987f4
-  status = b->start_image (image_handle, 0, NULL);
81987f4
+  return GRUB_ERR_NONE;
81987f4
 
81987f4
-  /* When successful, not reached */
81987f4
-  b->unload_image (image_handle);
81987f4
-  grub_efi_free_pages ((grub_addr_t) loaded_image->load_options,
81987f4
-		       GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
81987f4
+failure:
81987f4
+  grub_fdt_unload();
81987f4
+  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
81987f4
+}
81987f4
 
81987f4
-  return grub_errno;
81987f4
+static void
81987f4
+free_params (void)
81987f4
+{
81987f4
+  grub_efi_loaded_image_t *loaded_image = NULL;
81987f4
+
b9efc54
+  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
b9efc54
+  if (loaded_image)
b9efc54
+    {
b9efc54
+      if (loaded_image->load_options)
b9efc54
+	grub_efi_free_pages ((grub_efi_physical_address_t)
b9efc54
+			      loaded_image->load_options,
0ac23e2
+			     GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
b9efc54
+      loaded_image->load_options = NULL;
b9efc54
+      loaded_image->load_options_size = 0;
b9efc54
+    }
b9efc54
+}
81987f4
+
b9efc54
+grub_err_t
b9efc54
+grub_arm64_uefi_boot_image (grub_addr_t addr, grub_size_t size, char *args)
b9efc54
+{
b9efc54
+  grub_err_t retval;
81987f4
+
b9efc54
+  retval = finalize_params_linux ();
b9efc54
+  if (retval != GRUB_ERR_NONE)
81987f4
+    return grub_errno;
81987f4
+
b9efc54
+  grub_dprintf ("linux", "linux command line: '%s'\n", args);
81987f4
+
b9efc54
+  retval = grub_efi_linux_boot ((char *)kernel_addr, handover_offset,
b9efc54
+				kernel_addr);
81987f4
+
b9efc54
+  /* Never reached... */
b9efc54
+  free_params();
b9efc54
+  return retval;
b9efc54
 }
b9efc54
 
9074bf3
 static grub_err_t
9074bf3
 grub_linux_boot (void)
9074bf3
 {
b9efc54
-  if (finalize_params_linux () != GRUB_ERR_NONE)
b9efc54
-    return grub_errno;
b9efc54
-
9074bf3
-  return (grub_arm64_uefi_boot_image((grub_addr_t)kernel_addr,
9074bf3
-                                     kernel_size, linux_args));
b9efc54
+  return grub_arm64_uefi_boot_image ((grub_addr_t)kernel_addr,
b9efc54
+				     kernel_size, linux_args);
58fe9aa
 }
58fe9aa
 
58fe9aa
 static grub_err_t
8b3d200
@@ -249,6 +246,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
58fe9aa
 {
58fe9aa
   grub_file_t file = 0;
58fe9aa
   struct grub_arm64_linux_kernel_header lh;
58fe9aa
+  struct grub_arm64_linux_pe_header *pe;
58fe9aa
 
58fe9aa
   grub_dl_ref (my_mod);
58fe9aa
 
8b3d200
@@ -293,6 +291,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
58fe9aa
 
58fe9aa
   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
58fe9aa
 
58fe9aa
+  if (!grub_linuxefi_secure_validate (kernel_addr, kernel_size))
58fe9aa
+    {
58fe9aa
+      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
58fe9aa
+      goto fail;
58fe9aa
+    }
58fe9aa
+
58fe9aa
+  pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
58fe9aa
+  handover_offset = pe->opt.entry_addr;
58fe9aa
+
58fe9aa
   cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
58fe9aa
   linux_args = grub_malloc (cmdline_size);
58fe9aa
   if (!linux_args)
58fe9aa
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
58fe9aa
new file mode 100644
81987f4
index 00000000000..aea378adf5c
58fe9aa
--- /dev/null
58fe9aa
+++ b/grub-core/loader/efi/linux.c
9d15b4d
@@ -0,0 +1,65 @@
58fe9aa
+/*
58fe9aa
+ *  GRUB  --  GRand Unified Bootloader
58fe9aa
+ *  Copyright (C) 2014 Free Software Foundation, Inc.
58fe9aa
+ *
58fe9aa
+ *  GRUB is free software: you can redistribute it and/or modify
58fe9aa
+ *  it under the terms of the GNU General Public License as published by
58fe9aa
+ *  the Free Software Foundation, either version 3 of the License, or
58fe9aa
+ *  (at your option) any later version.
58fe9aa
+ *
58fe9aa
+ *  GRUB is distributed in the hope that it will be useful,
58fe9aa
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
58fe9aa
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
58fe9aa
+ *  GNU General Public License for more details.
58fe9aa
+ *
58fe9aa
+ *  You should have received a copy of the GNU General Public License
58fe9aa
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
58fe9aa
+ */
58fe9aa
+
58fe9aa
+#include <grub/err.h>
58fe9aa
+#include <grub/mm.h>
58fe9aa
+#include <grub/types.h>
58fe9aa
+#include <grub/cpu/linux.h>
58fe9aa
+#include <grub/efi/efi.h>
58fe9aa
+#include <grub/efi/pe32.h>
58fe9aa
+#include <grub/efi/linux.h>
58fe9aa
+
58fe9aa
+#define SHIM_LOCK_GUID \
58fe9aa
+ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
58fe9aa
+
58fe9aa
+struct grub_efi_shim_lock
58fe9aa
+{
58fe9aa
+  grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
58fe9aa
+};
58fe9aa
+typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
58fe9aa
+
58fe9aa
+grub_efi_boolean_t
58fe9aa
+grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
58fe9aa
+{
58fe9aa
+  grub_efi_guid_t guid = SHIM_LOCK_GUID;
58fe9aa
+  grub_efi_shim_lock_t *shim_lock;
58fe9aa
+
58fe9aa
+  shim_lock = grub_efi_locate_protocol(&guid, NULL);
58fe9aa
+
58fe9aa
+  if (!shim_lock)
58fe9aa
+    return 1;
58fe9aa
+
58fe9aa
+  if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
58fe9aa
+    return 1;
58fe9aa
+
58fe9aa
+  return 0;
58fe9aa
+}
58fe9aa
+
58fe9aa
+typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
58fe9aa
+
58fe9aa
+grub_err_t
58fe9aa
+grub_efi_linux_boot (void *kernel_addr, grub_off_t offset,
58fe9aa
+		     void *kernel_params)
58fe9aa
+{
58fe9aa
+  handover_func hf;
58fe9aa
+
58fe9aa
+  hf = (handover_func)((char *)kernel_addr + offset);
58fe9aa
+  hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
58fe9aa
+
58fe9aa
+  return GRUB_ERR_BUG;
58fe9aa
+}
58fe9aa
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
81987f4
index b79e6320ba9..e5b778577f9 100644
58fe9aa
--- a/grub-core/loader/i386/efi/linux.c
58fe9aa
+++ b/grub-core/loader/i386/efi/linux.c
58fe9aa
@@ -26,6 +26,7 @@
58fe9aa
 #include <grub/i18n.h>
58fe9aa
 #include <grub/lib/cmdline.h>
58fe9aa
 #include <grub/efi/efi.h>
58fe9aa
+#include <grub/efi/linux.h>
58fe9aa
 
58fe9aa
 GRUB_MOD_LICENSE ("GPLv3+");
58fe9aa
 
58fe9aa
@@ -40,52 +41,18 @@ static char *linux_cmdline;
58fe9aa
 
58fe9aa
 #define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
58fe9aa
 
58fe9aa
-#define SHIM_LOCK_GUID \
58fe9aa
-  { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
58fe9aa
-
58fe9aa
-struct grub_efi_shim_lock
58fe9aa
-{
58fe9aa
-  grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
58fe9aa
-};
58fe9aa
-typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
58fe9aa
-
58fe9aa
-static grub_efi_boolean_t
58fe9aa
-grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
58fe9aa
-{
58fe9aa
-  grub_efi_guid_t guid = SHIM_LOCK_GUID;
58fe9aa
-  grub_efi_shim_lock_t *shim_lock;
58fe9aa
-
58fe9aa
-  shim_lock = grub_efi_locate_protocol(&guid, NULL);
58fe9aa
-
58fe9aa
-  if (!shim_lock)
58fe9aa
-    return 1;
58fe9aa
-
58fe9aa
-  if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
58fe9aa
-    return 1;
58fe9aa
-
58fe9aa
-  return 0;
58fe9aa
-}
58fe9aa
-
58fe9aa
-typedef void(*handover_func)(void *, grub_efi_system_table_t *, struct linux_kernel_params *);
58fe9aa
-
58fe9aa
 static grub_err_t
58fe9aa
 grub_linuxefi_boot (void)
58fe9aa
 {
58fe9aa
-  handover_func hf;
58fe9aa
   int offset = 0;
58fe9aa
 
58fe9aa
 #ifdef __x86_64__
58fe9aa
   offset = 512;
58fe9aa
 #endif
58fe9aa
-
58fe9aa
-  hf = (handover_func)((char *)kernel_mem + handover_offset + offset);
58fe9aa
-
58fe9aa
   asm volatile ("cli");
58fe9aa
 
58fe9aa
-  hf (grub_efi_image_handle, grub_efi_system_table, params);
58fe9aa
-
58fe9aa
-  /* Not reached */
58fe9aa
-  return GRUB_ERR_NONE;
58fe9aa
+  return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset,
58fe9aa
+			      params);
58fe9aa
 }
58fe9aa
 
58fe9aa
 static grub_err_t
58fe9aa
diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h
81987f4
index a981df5d15f..0df38413338 100644
58fe9aa
--- a/include/grub/arm64/linux.h
58fe9aa
+++ b/include/grub/arm64/linux.h
58fe9aa
@@ -20,6 +20,7 @@
58fe9aa
 #define GRUB_LINUX_CPU_HEADER 1
58fe9aa
 
58fe9aa
 #include <grub/efi/efi.h>
58fe9aa
+#include <grub/efi/pe32.h>
58fe9aa
 
58fe9aa
 #define GRUB_ARM64_LINUX_MAGIC 0x644d5241 /* 'ARM\x64' */
58fe9aa
 
bbc6a89
@@ -42,5 +43,11 @@ grub_err_t grub_arm64_uefi_check_image (struct grub_arm64_linux_kernel_header
b9efc54
                                         *lh);
b9efc54
 grub_err_t grub_arm64_uefi_boot_image (grub_addr_t addr, grub_size_t size,
b9efc54
                                        char *args);
58fe9aa
+struct grub_arm64_linux_pe_header
58fe9aa
+{
58fe9aa
+  grub_uint32_t magic;
58fe9aa
+  struct grub_pe32_coff_header coff;
58fe9aa
+  struct grub_pe64_optional_header opt;
58fe9aa
+};
8c6b1ac
 
58fe9aa
 #endif /* ! GRUB_LINUX_CPU_HEADER */
58fe9aa
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
58fe9aa
new file mode 100644
81987f4
index 00000000000..d9ede36773b
58fe9aa
--- /dev/null
58fe9aa
+++ b/include/grub/efi/linux.h
58fe9aa
@@ -0,0 +1,31 @@
58fe9aa
+/*
58fe9aa
+ *  GRUB  --  GRand Unified Bootloader
58fe9aa
+ *  Copyright (C) 2014  Free Software Foundation, Inc.
58fe9aa
+ *
58fe9aa
+ *  GRUB is free software: you can redistribute it and/or modify
58fe9aa
+ *  it under the terms of the GNU General Public License as published by
58fe9aa
+ *  the Free Software Foundation, either version 3 of the License, or
58fe9aa
+ *  (at your option) any later version.
58fe9aa
+ *
58fe9aa
+ *  GRUB is distributed in the hope that it will be useful,
58fe9aa
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
58fe9aa
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
58fe9aa
+ *  GNU General Public License for more details.
58fe9aa
+ *
58fe9aa
+ *  You should have received a copy of the GNU General Public License
58fe9aa
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
58fe9aa
+ */
58fe9aa
+#ifndef GRUB_EFI_LINUX_HEADER
58fe9aa
+#define GRUB_EFI_LINUX_HEADER	1
58fe9aa
+
58fe9aa
+#include <grub/efi/api.h>
58fe9aa
+#include <grub/err.h>
58fe9aa
+#include <grub/symbol.h>
58fe9aa
+
58fe9aa
+grub_efi_boolean_t
58fe9aa
+EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
58fe9aa
+grub_err_t
58fe9aa
+EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
58fe9aa
+				  void *kernel_param);
58fe9aa
+
58fe9aa
+#endif /* ! GRUB_EFI_LINUX_HEADER */
58fe9aa
-- 
81987f4
2.15.0
58fe9aa