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.
433 lines
13 KiB
433 lines
13 KiB
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
|
From: Peter Jones <pjones@redhat.com> |
|
Date: Thu, 18 Sep 2014 11:26:14 -0400 |
|
Subject: [PATCH] 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 9ff9ae5a311..9378c732981 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 0dc144e5da0..bdd9c9b4968 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 00000000000..aea378adf5c |
|
--- /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 b79e6320ba9..e5b778577f9 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 864e5dc363a..2cbd64f8c55 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 00000000000..d9ede36773b |
|
--- /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 */
|
|
|