78e1a10
From c03bf04fd9e3192bec942a7adee23b5377ea81dc Mon Sep 17 00:00:00 2001
58fe9aa
From: Peter Jones <pjones@redhat.com>
58fe9aa
Date: Thu, 18 Sep 2014 11:26:14 -0400
78e1a10
Subject: [PATCH 123/216] 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 +
ec4acbb
 grub-core/loader/arm64/linux.c    | 121 ++++++++++++++++++++------------------
ec4acbb
 grub-core/loader/efi/linux.c      |  65 ++++++++++++++++++++
ec4acbb
 grub-core/loader/i386/efi/linux.c |  39 +-----------
b9efc54
 include/grub/arm64/linux.h        |   7 +++
9074bf3
 include/grub/efi/linux.h          |  31 ++++++++++
ec4acbb
 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
ec4acbb
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
ec4acbb
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
 
ec4acbb
@@ -100,79 +103,73 @@ finalize_params_linux (void)
b9efc54
   if (grub_fdt_install() != GRUB_ERR_NONE)
8c6b1ac
     goto failure;
58fe9aa
 
ec4acbb
-  return GRUB_ERR_NONE;
ec4acbb
-
ec4acbb
-failure:
ec4acbb
-  grub_fdt_unload();
ec4acbb
-  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
ec4acbb
-}
ec4acbb
-
9074bf3
-grub_err_t
9074bf3
-grub_arm64_uefi_boot_image (grub_addr_t addr, grub_size_t size, char *args)
ec4acbb
-{
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;
ec4acbb
-
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");
ec4acbb
-
ec4acbb
-  grub_dprintf ("linux", "linux command line: '%s'\n", args);
ec4acbb
+  grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
ec4acbb
+		fdt);
ec4acbb
 
ec4acbb
   /* Convert command line to UCS-2 */
ec4acbb
-  loaded_image = grub_efi_get_loaded_image (image_handle);
ec4acbb
+  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
ec4acbb
+  if (!loaded_image)
ec4acbb
+    goto failure;
ec4acbb
+
ec4acbb
   loaded_image->load_options_size = len =
ec4acbb
-    (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t);
ec4acbb
+    (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
ec4acbb
   loaded_image->load_options =
ec4acbb
     grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
ec4acbb
   if (!loaded_image->load_options)
ec4acbb
-    return grub_errno;
ec4acbb
+    return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
ec4acbb
 
ec4acbb
   loaded_image->load_options_size =
ec4acbb
     2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
ec4acbb
-			    (grub_uint8_t *) args, len, NULL);
ec4acbb
+			    (grub_uint8_t *) linux_args, len, NULL);
ec4acbb
 
ec4acbb
-  grub_dprintf ("linux", "starting image %p\n", image_handle);
ec4acbb
-  status = b->start_image (image_handle, 0, NULL);
ec4acbb
+  return GRUB_ERR_NONE;
ec4acbb
 
ec4acbb
-  /* When successful, not reached */
ec4acbb
-  b->unload_image (image_handle);
ec4acbb
-  grub_efi_free_pages ((grub_addr_t) loaded_image->load_options,
ec4acbb
-		       GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
ec4acbb
+failure:
ec4acbb
+  grub_fdt_unload();
ec4acbb
+  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
ec4acbb
+}
ec4acbb
 
ec4acbb
-  return grub_errno;
ec4acbb
+static void
ec4acbb
+free_params (void)
ec4acbb
+{
ec4acbb
+  grub_efi_loaded_image_t *loaded_image = NULL;
ec4acbb
+
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
+}
ec4acbb
+
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;
ec4acbb
+
b9efc54
+  retval = finalize_params_linux ();
b9efc54
+  if (retval != GRUB_ERR_NONE)
ec4acbb
+    return grub_errno;
ec4acbb
+
b9efc54
+  grub_dprintf ("linux", "linux command line: '%s'\n", args);
ec4acbb
+
b9efc54
+  retval = grub_efi_linux_boot ((char *)kernel_addr, handover_offset,
b9efc54
+				kernel_addr);
ec4acbb
+
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
ec4acbb
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
ec4acbb
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
ec4acbb
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
ec4acbb
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
-- 
ec4acbb
2.15.0
58fe9aa