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