|
|
4fe85b |
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
4fe85b |
From: Peter Jones <pjones@redhat.com>
|
|
|
4fe85b |
Date: Tue, 6 Oct 2015 13:04:37 -0400
|
|
|
4fe85b |
Subject: [PATCH] Add secureboot support on efi chainloader
|
|
|
4fe85b |
|
|
|
4fe85b |
Expand the chainloader to be able to verify the image by means of shim
|
|
|
4fe85b |
lock protocol. The PE/COFF image is loaded and relocated by the
|
|
|
4fe85b |
chainloader instead of calling LoadImage and StartImage UEFI boot
|
|
|
4fe85b |
Service as they require positive verification result from keys enrolled
|
|
|
4fe85b |
in KEK or DB. The shim will use MOK in addition to firmware enrolled
|
|
|
4fe85b |
keys to verify the image.
|
|
|
4fe85b |
|
|
|
4fe85b |
The chainloader module could be used to load other UEFI bootloaders,
|
|
|
4fe85b |
such as xen.efi, and could be signed by any of MOK, KEK or DB.
|
|
|
4fe85b |
|
|
|
4fe85b |
Based on https://build.opensuse.org/package/view_file/openSUSE:Factory/grub2/grub2-secureboot-chainloader.patch
|
|
|
4fe85b |
|
|
|
4fe85b |
Signed-off-by: Peter Jones <pjones@redhat.com>
|
|
|
4fe85b |
---
|
|
|
4fe85b |
grub-core/loader/efi/chainloader.c | 612 ++++++++++++++++++++++++++++++++++---
|
|
|
4fe85b |
include/grub/efi/pe32.h | 20 +-
|
|
|
4fe85b |
2 files changed, 595 insertions(+), 37 deletions(-)
|
|
|
4fe85b |
|
|
|
4fe85b |
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
|
|
|
4fe85b |
index 14ce6ddd7ad..87a91e16f17 100644
|
|
|
4fe85b |
--- a/grub-core/loader/efi/chainloader.c
|
|
|
4fe85b |
+++ b/grub-core/loader/efi/chainloader.c
|
|
|
4fe85b |
@@ -32,6 +32,8 @@
|
|
|
4fe85b |
#include <grub/efi/api.h>
|
|
|
4fe85b |
#include <grub/efi/efi.h>
|
|
|
4fe85b |
#include <grub/efi/disk.h>
|
|
|
4fe85b |
+#include <grub/efi/pe32.h>
|
|
|
4fe85b |
+#include <grub/efi/linux.h>
|
|
|
4fe85b |
#include <grub/command.h>
|
|
|
4fe85b |
#include <grub/i18n.h>
|
|
|
4fe85b |
#include <grub/net.h>
|
|
|
4fe85b |
@@ -46,9 +48,14 @@ static grub_dl_t my_mod;
|
|
|
4fe85b |
|
|
|
4fe85b |
static grub_efi_physical_address_t address;
|
|
|
4fe85b |
static grub_efi_uintn_t pages;
|
|
|
4fe85b |
+static grub_ssize_t fsize;
|
|
|
4fe85b |
static grub_efi_device_path_t *file_path;
|
|
|
4fe85b |
static grub_efi_handle_t image_handle;
|
|
|
4fe85b |
static grub_efi_char16_t *cmdline;
|
|
|
4fe85b |
+static grub_ssize_t cmdline_len;
|
|
|
4fe85b |
+static grub_efi_handle_t dev_handle;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
|
|
|
4fe85b |
|
|
|
4fe85b |
static grub_err_t
|
|
|
4fe85b |
grub_chainloader_unload (void)
|
|
|
4fe85b |
@@ -63,6 +70,7 @@ grub_chainloader_unload (void)
|
|
|
4fe85b |
grub_free (cmdline);
|
|
|
4fe85b |
cmdline = 0;
|
|
|
4fe85b |
file_path = 0;
|
|
|
4fe85b |
+ dev_handle = 0;
|
|
|
4fe85b |
|
|
|
4fe85b |
grub_dl_unref (my_mod);
|
|
|
4fe85b |
return GRUB_ERR_NONE;
|
|
|
4fe85b |
@@ -191,12 +199,523 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
|
|
|
4fe85b |
return file_path;
|
|
|
4fe85b |
}
|
|
|
4fe85b |
|
|
|
4fe85b |
+#define SHIM_LOCK_GUID \
|
|
|
4fe85b |
+ { 0x605dab50, 0xe046, 0x4300, { 0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23 } }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+typedef union
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ struct grub_pe32_header_32 pe32;
|
|
|
4fe85b |
+ struct grub_pe32_header_64 pe32plus;
|
|
|
4fe85b |
+} grub_pe_header_t;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+struct pe_coff_loader_image_context
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ grub_efi_uint64_t image_address;
|
|
|
4fe85b |
+ grub_efi_uint64_t image_size;
|
|
|
4fe85b |
+ grub_efi_uint64_t entry_point;
|
|
|
4fe85b |
+ grub_efi_uintn_t size_of_headers;
|
|
|
4fe85b |
+ grub_efi_uint16_t image_type;
|
|
|
4fe85b |
+ grub_efi_uint16_t number_of_sections;
|
|
|
4fe85b |
+ grub_efi_uint32_t section_alignment;
|
|
|
4fe85b |
+ struct grub_pe32_section_table *first_section;
|
|
|
4fe85b |
+ struct grub_pe32_data_directory *reloc_dir;
|
|
|
4fe85b |
+ struct grub_pe32_data_directory *sec_dir;
|
|
|
4fe85b |
+ grub_efi_uint64_t number_of_rva_and_sizes;
|
|
|
4fe85b |
+ grub_pe_header_t *pe_hdr;
|
|
|
4fe85b |
+};
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+typedef struct pe_coff_loader_image_context pe_coff_loader_image_context_t;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+struct grub_efi_shim_lock
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ grub_efi_status_t (*verify)(void *buffer,
|
|
|
4fe85b |
+ grub_efi_uint32_t size);
|
|
|
4fe85b |
+ grub_efi_status_t (*hash)(void *data,
|
|
|
4fe85b |
+ grub_efi_int32_t datasize,
|
|
|
4fe85b |
+ pe_coff_loader_image_context_t *context,
|
|
|
4fe85b |
+ grub_efi_uint8_t *sha256hash,
|
|
|
4fe85b |
+ grub_efi_uint8_t *sha1hash);
|
|
|
4fe85b |
+ grub_efi_status_t (*context)(void *data,
|
|
|
4fe85b |
+ grub_efi_uint32_t size,
|
|
|
4fe85b |
+ pe_coff_loader_image_context_t *context);
|
|
|
4fe85b |
+};
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+static grub_efi_boolean_t
|
|
|
4fe85b |
+read_header (void *data, grub_efi_uint32_t size,
|
|
|
4fe85b |
+ pe_coff_loader_image_context_t *context)
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ grub_efi_guid_t guid = SHIM_LOCK_GUID;
|
|
|
4fe85b |
+ grub_efi_shim_lock_t *shim_lock;
|
|
|
4fe85b |
+ grub_efi_status_t status;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ shim_lock = grub_efi_locate_protocol (&guid, NULL);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (!shim_lock)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "no shim lock protocol");
|
|
|
4fe85b |
+ return 0;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ status = shim_lock->context (data, size, context);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (status == GRUB_EFI_SUCCESS)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_dprintf ("chain", "context success\n");
|
|
|
4fe85b |
+ return 1;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ switch (status)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ case GRUB_EFI_UNSUPPORTED:
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error unsupported");
|
|
|
4fe85b |
+ break;
|
|
|
4fe85b |
+ case GRUB_EFI_INVALID_PARAMETER:
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error invalid parameter");
|
|
|
4fe85b |
+ break;
|
|
|
4fe85b |
+ default:
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error code");
|
|
|
4fe85b |
+ break;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ return 0;
|
|
|
4fe85b |
+}
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+static void*
|
|
|
4fe85b |
+image_address (void *image, grub_efi_uint64_t sz, grub_efi_uint64_t adr)
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ if (adr > sz)
|
|
|
4fe85b |
+ return NULL;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ return ((grub_uint8_t*)image + adr);
|
|
|
4fe85b |
+}
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+static int
|
|
|
4fe85b |
+image_is_64_bit (grub_pe_header_t *pe_hdr)
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ /* .Magic is the same offset in all cases */
|
|
|
4fe85b |
+ if (pe_hdr->pe32plus.optional_header.magic == GRUB_PE32_PE64_MAGIC)
|
|
|
4fe85b |
+ return 1;
|
|
|
4fe85b |
+ return 0;
|
|
|
4fe85b |
+}
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+static const grub_uint16_t machine_type =
|
|
|
4fe85b |
+#if defined(__x86_64__)
|
|
|
4fe85b |
+ GRUB_PE32_MACHINE_X86_64;
|
|
|
4fe85b |
+#elif defined(__aarch64__)
|
|
|
4fe85b |
+ GRUB_PE32_MACHINE_ARM64;
|
|
|
4fe85b |
+#elif defined(__arm__)
|
|
|
4fe85b |
+ GRUB_PE32_MACHINE_ARMTHUMB_MIXED;
|
|
|
4fe85b |
+#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
|
|
|
4fe85b |
+ GRUB_PE32_MACHINE_I386;
|
|
|
4fe85b |
+#elif defined(__ia64__)
|
|
|
4fe85b |
+ GRUB_PE32_MACHINE_IA64;
|
|
|
4fe85b |
+#else
|
|
|
4fe85b |
+#error this architecture is not supported by grub2
|
|
|
4fe85b |
+#endif
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+static grub_efi_status_t
|
|
|
4fe85b |
+relocate_coff (pe_coff_loader_image_context_t *context,
|
|
|
4fe85b |
+ struct grub_pe32_section_table *section,
|
|
|
4fe85b |
+ void *orig, void *data)
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ struct grub_pe32_data_directory *reloc_base, *reloc_base_end;
|
|
|
4fe85b |
+ grub_efi_uint64_t adjust;
|
|
|
4fe85b |
+ struct grub_pe32_fixup_block *reloc, *reloc_end;
|
|
|
4fe85b |
+ char *fixup, *fixup_base, *fixup_data = NULL;
|
|
|
4fe85b |
+ grub_efi_uint16_t *fixup_16;
|
|
|
4fe85b |
+ grub_efi_uint32_t *fixup_32;
|
|
|
4fe85b |
+ grub_efi_uint64_t *fixup_64;
|
|
|
4fe85b |
+ grub_efi_uint64_t size = context->image_size;
|
|
|
4fe85b |
+ void *image_end = (char *)orig + size;
|
|
|
4fe85b |
+ int n = 0;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (image_is_64_bit (context->pe_hdr))
|
|
|
4fe85b |
+ context->pe_hdr->pe32plus.optional_header.image_base =
|
|
|
4fe85b |
+ (grub_uint64_t)(unsigned long)data;
|
|
|
4fe85b |
+ else
|
|
|
4fe85b |
+ context->pe_hdr->pe32.optional_header.image_base =
|
|
|
4fe85b |
+ (grub_uint32_t)(unsigned long)data;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ /* Alright, so here's how this works:
|
|
|
4fe85b |
+ *
|
|
|
4fe85b |
+ * context->reloc_dir gives us two things:
|
|
|
4fe85b |
+ * - the VA the table of base relocation blocks are (maybe) to be
|
|
|
4fe85b |
+ * mapped at (reloc_dir->rva)
|
|
|
4fe85b |
+ * - the virtual size (reloc_dir->size)
|
|
|
4fe85b |
+ *
|
|
|
4fe85b |
+ * The .reloc section (section here) gives us some other things:
|
|
|
4fe85b |
+ * - the name! kind of. (section->name)
|
|
|
4fe85b |
+ * - the virtual size (section->virtual_size), which should be the same
|
|
|
4fe85b |
+ * as RelocDir->Size
|
|
|
4fe85b |
+ * - the virtual address (section->virtual_address)
|
|
|
4fe85b |
+ * - the file section size (section->raw_data_size), which is
|
|
|
4fe85b |
+ * a multiple of optional_header->file_alignment. Only useful for image
|
|
|
4fe85b |
+ * validation, not really useful for iteration bounds.
|
|
|
4fe85b |
+ * - the file address (section->raw_data_offset)
|
|
|
4fe85b |
+ * - a bunch of stuff we don't use that's 0 in our binaries usually
|
|
|
4fe85b |
+ * - Flags (section->characteristics)
|
|
|
4fe85b |
+ *
|
|
|
4fe85b |
+ * and then the thing that's actually at the file address is an array
|
|
|
4fe85b |
+ * of struct grub_pe32_fixup_block structs with some values packed behind
|
|
|
4fe85b |
+ * them. The block_size field of this structure includes the
|
|
|
4fe85b |
+ * structure itself, and adding it to that structure's address will
|
|
|
4fe85b |
+ * yield the next entry in the array.
|
|
|
4fe85b |
+ */
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ reloc_base = image_address (orig, size, section->raw_data_offset);
|
|
|
4fe85b |
+ reloc_base_end = image_address (orig, size, section->raw_data_offset
|
|
|
4fe85b |
+ + section->virtual_size - 1);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ grub_dprintf ("chain", "reloc_base %p reloc_base_end %p\n", reloc_base,
|
|
|
4fe85b |
+ reloc_base_end);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (!reloc_base && !reloc_base_end)
|
|
|
4fe85b |
+ return GRUB_EFI_SUCCESS;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (!reloc_base || !reloc_base_end)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc table overflows binary");
|
|
|
4fe85b |
+ return GRUB_EFI_UNSUPPORTED;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ adjust = (grub_uint64_t)data - context->image_address;
|
|
|
4fe85b |
+ if (adjust == 0)
|
|
|
4fe85b |
+ return GRUB_EFI_SUCCESS;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ while (reloc_base < reloc_base_end)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_uint16_t *entry;
|
|
|
4fe85b |
+ reloc = (struct grub_pe32_fixup_block *)((char*)reloc_base);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if ((reloc_base->size == 0) ||
|
|
|
4fe85b |
+ (reloc_base->size > context->reloc_dir->size))
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT,
|
|
|
4fe85b |
+ "Reloc %d block size %d is invalid\n", n,
|
|
|
4fe85b |
+ reloc_base->size);
|
|
|
4fe85b |
+ return GRUB_EFI_UNSUPPORTED;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ entry = &reloc->entries[0];
|
|
|
4fe85b |
+ reloc_end = (struct grub_pe32_fixup_block *)
|
|
|
4fe85b |
+ ((char *)reloc_base + reloc_base->size);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if ((void *)reloc_end < data || (void *)reloc_end > image_end)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc entry %d overflows binary",
|
|
|
4fe85b |
+ n);
|
|
|
4fe85b |
+ return GRUB_EFI_UNSUPPORTED;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ fixup_base = image_address(data, size, reloc_base->rva);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (!fixup_base)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc %d Invalid fixupbase", n);
|
|
|
4fe85b |
+ return GRUB_EFI_UNSUPPORTED;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ while ((void *)entry < (void *)reloc_end)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ fixup = fixup_base + (*entry & 0xFFF);
|
|
|
4fe85b |
+ switch ((*entry) >> 12)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ case GRUB_PE32_REL_BASED_ABSOLUTE:
|
|
|
4fe85b |
+ break;
|
|
|
4fe85b |
+ case GRUB_PE32_REL_BASED_HIGH:
|
|
|
4fe85b |
+ fixup_16 = (grub_uint16_t *)fixup;
|
|
|
4fe85b |
+ *fixup_16 = (grub_uint16_t)
|
|
|
4fe85b |
+ (*fixup_16 + ((grub_uint16_t)((grub_uint32_t)adjust >> 16)));
|
|
|
4fe85b |
+ if (fixup_data != NULL)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ *(grub_uint16_t *) fixup_data = *fixup_16;
|
|
|
4fe85b |
+ fixup_data = fixup_data + sizeof (grub_uint16_t);
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ break;
|
|
|
4fe85b |
+ case GRUB_PE32_REL_BASED_LOW:
|
|
|
4fe85b |
+ fixup_16 = (grub_uint16_t *)fixup;
|
|
|
4fe85b |
+ *fixup_16 = (grub_uint16_t) (*fixup_16 + (grub_uint16_t)adjust);
|
|
|
4fe85b |
+ if (fixup_data != NULL)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ *(grub_uint16_t *) fixup_data = *fixup_16;
|
|
|
4fe85b |
+ fixup_data = fixup_data + sizeof (grub_uint16_t);
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ break;
|
|
|
4fe85b |
+ case GRUB_PE32_REL_BASED_HIGHLOW:
|
|
|
4fe85b |
+ fixup_32 = (grub_uint32_t *)fixup;
|
|
|
4fe85b |
+ *fixup_32 = *fixup_32 + (grub_uint32_t)adjust;
|
|
|
4fe85b |
+ if (fixup_data != NULL)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint32_t));
|
|
|
4fe85b |
+ *(grub_uint32_t *) fixup_data = *fixup_32;
|
|
|
4fe85b |
+ fixup_data += sizeof (grub_uint32_t);
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ break;
|
|
|
4fe85b |
+ case GRUB_PE32_REL_BASED_DIR64:
|
|
|
4fe85b |
+ fixup_64 = (grub_uint64_t *)fixup;
|
|
|
4fe85b |
+ *fixup_64 = *fixup_64 + (grub_uint64_t)adjust;
|
|
|
4fe85b |
+ if (fixup_data != NULL)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint64_t));
|
|
|
4fe85b |
+ *(grub_uint64_t *) fixup_data = *fixup_64;
|
|
|
4fe85b |
+ fixup_data += sizeof (grub_uint64_t);
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ break;
|
|
|
4fe85b |
+ default:
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT,
|
|
|
4fe85b |
+ "Reloc %d unknown relocation type %d",
|
|
|
4fe85b |
+ n, (*entry) >> 12);
|
|
|
4fe85b |
+ return GRUB_EFI_UNSUPPORTED;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ entry += 1;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ reloc_base = (struct grub_pe32_data_directory *)reloc_end;
|
|
|
4fe85b |
+ n++;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ return GRUB_EFI_SUCCESS;
|
|
|
4fe85b |
+}
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+static grub_efi_device_path_t *
|
|
|
4fe85b |
+grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ while (1)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
|
|
|
4fe85b |
+ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (type == GRUB_EFI_END_DEVICE_PATH_TYPE)
|
|
|
4fe85b |
+ break;
|
|
|
4fe85b |
+ else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
|
|
|
4fe85b |
+ && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE)
|
|
|
4fe85b |
+ return dp;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ dp = GRUB_EFI_NEXT_DEVICE_PATH (dp);
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ return NULL;
|
|
|
4fe85b |
+}
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+static grub_efi_boolean_t
|
|
|
4fe85b |
+handle_image (void *data, grub_efi_uint32_t datasize)
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ grub_efi_boot_services_t *b;
|
|
|
4fe85b |
+ grub_efi_loaded_image_t *li, li_bak;
|
|
|
4fe85b |
+ grub_efi_status_t efi_status;
|
|
|
4fe85b |
+ char *buffer = NULL;
|
|
|
4fe85b |
+ char *buffer_aligned = NULL;
|
|
|
4fe85b |
+ grub_efi_uint32_t i, size;
|
|
|
4fe85b |
+ struct grub_pe32_section_table *section;
|
|
|
4fe85b |
+ char *base, *end;
|
|
|
4fe85b |
+ pe_coff_loader_image_context_t context;
|
|
|
4fe85b |
+ grub_uint32_t section_alignment;
|
|
|
4fe85b |
+ grub_uint32_t buffer_size;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ b = grub_efi_system_table->boot_services;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (read_header (data, datasize, &context))
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_dprintf ("chain", "Succeed to read header\n");
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ else
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_dprintf ("chain", "Failed to read header\n");
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ section_alignment = context.section_alignment;
|
|
|
4fe85b |
+ buffer_size = context.image_size + section_alignment;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA,
|
|
|
4fe85b |
+ buffer_size, &buffer);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (efi_status != GRUB_EFI_SUCCESS)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ buffer_aligned = (char *)ALIGN_UP ((grub_addr_t)buffer, section_alignment);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (!buffer_aligned)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ grub_memcpy (buffer_aligned, data, context.size_of_headers);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ char *reloc_base, *reloc_base_end;
|
|
|
4fe85b |
+ reloc_base = image_address (buffer_aligned, datasize,
|
|
|
4fe85b |
+ context.reloc_dir->rva);
|
|
|
4fe85b |
+ /* RelocBaseEnd here is the address of the last byte of the table */
|
|
|
4fe85b |
+ reloc_base_end = image_address (buffer_aligned, datasize,
|
|
|
4fe85b |
+ context.reloc_dir->rva
|
|
|
4fe85b |
+ + context.reloc_dir->size - 1);
|
|
|
4fe85b |
+ struct grub_pe32_section_table *reloc_section = NULL;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ section = context.first_section;
|
|
|
4fe85b |
+ for (i = 0; i < context.number_of_sections; i++, section++)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ size = section->virtual_size;
|
|
|
4fe85b |
+ if (size > section->raw_data_size)
|
|
|
4fe85b |
+ size = section->raw_data_size;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ base = image_address (buffer_aligned, context.image_size,
|
|
|
4fe85b |
+ section->virtual_address);
|
|
|
4fe85b |
+ end = image_address (buffer_aligned, context.image_size,
|
|
|
4fe85b |
+ section->virtual_address + size - 1);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ /* We do want to process .reloc, but it's often marked
|
|
|
4fe85b |
+ * discardable, so we don't want to memcpy it. */
|
|
|
4fe85b |
+ if (grub_memcmp (section->name, ".reloc\0\0", 8) == 0)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ if (reloc_section)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT,
|
|
|
4fe85b |
+ "Image has multiple relocation sections");
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ /* If it has nonzero sizes, and our bounds check
|
|
|
4fe85b |
+ * made sense, and the VA and size match RelocDir's
|
|
|
4fe85b |
+ * versions, then we believe in this section table. */
|
|
|
4fe85b |
+ if (section->raw_data_size && section->virtual_size &&
|
|
|
4fe85b |
+ base && end && reloc_base == base && reloc_base_end == end)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ reloc_section = section;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (section->characteristics && GRUB_PE32_SCN_MEM_DISCARDABLE)
|
|
|
4fe85b |
+ continue;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (!base || !end)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid section size");
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (section->virtual_address < context.size_of_headers ||
|
|
|
4fe85b |
+ section->raw_data_offset < context.size_of_headers)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT,
|
|
|
4fe85b |
+ "Section %d is inside image headers", i);
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (section->raw_data_size > 0)
|
|
|
4fe85b |
+ grub_memcpy (base, (grub_efi_uint8_t*)data + section->raw_data_offset,
|
|
|
4fe85b |
+ size);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (size < section->virtual_size)
|
|
|
4fe85b |
+ grub_memset (base + size, 0, section->virtual_size - size);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ grub_dprintf ("chain", "copied section %s\n", section->name);
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ /* 5 == EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC */
|
|
|
4fe85b |
+ if (context.number_of_rva_and_sizes <= 5)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_dprintf ("chain", "image has no relocation entry\n");
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (context.reloc_dir->size && reloc_section)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ /* run the relocation fixups */
|
|
|
4fe85b |
+ efi_status = relocate_coff (&context, reloc_section, data,
|
|
|
4fe85b |
+ buffer_aligned);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (efi_status != GRUB_EFI_SUCCESS)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "relocation failed");
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ entry_point = image_address (buffer_aligned, context.image_size,
|
|
|
4fe85b |
+ context.entry_point);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (!entry_point)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid entry point");
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ li = grub_efi_get_loaded_image (grub_efi_image_handle);
|
|
|
4fe85b |
+ if (!li)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "no loaded image available");
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t));
|
|
|
4fe85b |
+ li->image_base = buffer_aligned;
|
|
|
4fe85b |
+ li->image_size = context.image_size;
|
|
|
4fe85b |
+ li->load_options = cmdline;
|
|
|
4fe85b |
+ li->load_options_size = cmdline_len;
|
|
|
4fe85b |
+ li->file_path = grub_efi_get_media_file_path (file_path);
|
|
|
4fe85b |
+ li->device_handle = dev_handle;
|
|
|
4fe85b |
+ if (li->file_path)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_printf ("file path: ");
|
|
|
4fe85b |
+ grub_efi_print_device_path (li->file_path);
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ else
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found");
|
|
|
4fe85b |
+ goto error_exit;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ efi_status = efi_call_2 (entry_point, grub_efi_image_handle,
|
|
|
4fe85b |
+ grub_efi_system_table);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t));
|
|
|
4fe85b |
+ efi_status = efi_call_1 (b->free_pool, buffer);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ return 1;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+error_exit:
|
|
|
4fe85b |
+ if (buffer)
|
|
|
4fe85b |
+ efi_call_1 (b->free_pool, buffer);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ return 0;
|
|
|
4fe85b |
+}
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+static grub_err_t
|
|
|
4fe85b |
+grub_secureboot_chainloader_unload (void)
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ grub_efi_boot_services_t *b;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ b = grub_efi_system_table->boot_services;
|
|
|
4fe85b |
+ efi_call_2 (b->free_pages, address, pages);
|
|
|
4fe85b |
+ grub_free (file_path);
|
|
|
4fe85b |
+ grub_free (cmdline);
|
|
|
4fe85b |
+ cmdline = 0;
|
|
|
4fe85b |
+ file_path = 0;
|
|
|
4fe85b |
+ dev_handle = 0;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ grub_dl_unref (my_mod);
|
|
|
4fe85b |
+ return GRUB_ERR_NONE;
|
|
|
4fe85b |
+}
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+static grub_err_t
|
|
|
4fe85b |
+grub_secureboot_chainloader_boot (void)
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ handle_image ((void *)address, fsize);
|
|
|
4fe85b |
+ grub_loader_unset ();
|
|
|
4fe85b |
+ return grub_errno;
|
|
|
4fe85b |
+}
|
|
|
4fe85b |
+
|
|
|
4fe85b |
static grub_err_t
|
|
|
4fe85b |
grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
4fe85b |
int argc, char *argv[])
|
|
|
4fe85b |
{
|
|
|
4fe85b |
grub_file_t file = 0;
|
|
|
4fe85b |
- grub_ssize_t size;
|
|
|
4fe85b |
grub_efi_status_t status;
|
|
|
4fe85b |
grub_efi_boot_services_t *b;
|
|
|
4fe85b |
grub_device_t dev = 0;
|
|
|
4fe85b |
@@ -204,7 +723,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
4fe85b |
grub_efi_loaded_image_t *loaded_image;
|
|
|
4fe85b |
char *filename;
|
|
|
4fe85b |
void *boot_image = 0;
|
|
|
4fe85b |
- grub_efi_handle_t dev_handle = 0;
|
|
|
4fe85b |
|
|
|
4fe85b |
if (argc == 0)
|
|
|
4fe85b |
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
|
|
|
4fe85b |
@@ -216,9 +734,36 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
4fe85b |
address = 0;
|
|
|
4fe85b |
image_handle = 0;
|
|
|
4fe85b |
file_path = 0;
|
|
|
4fe85b |
+ dev_handle = 0;
|
|
|
4fe85b |
|
|
|
4fe85b |
b = grub_efi_system_table->boot_services;
|
|
|
4fe85b |
|
|
|
4fe85b |
+ if (argc > 1)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ int i;
|
|
|
4fe85b |
+ grub_efi_char16_t *p16;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ for (i = 1, cmdline_len = 0; i < argc; i++)
|
|
|
4fe85b |
+ cmdline_len += grub_strlen (argv[i]) + 1;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ cmdline_len *= sizeof (grub_efi_char16_t);
|
|
|
4fe85b |
+ cmdline = p16 = grub_malloc (cmdline_len);
|
|
|
4fe85b |
+ if (! cmdline)
|
|
|
4fe85b |
+ goto fail;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ for (i = 1; i < argc; i++)
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ char *p8;
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ p8 = argv[i];
|
|
|
4fe85b |
+ while (*p8)
|
|
|
4fe85b |
+ *(p16++) = *(p8++);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ *(p16++) = ' ';
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+ *(--p16) = 0;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
file = grub_file_open (filename);
|
|
|
4fe85b |
if (! file)
|
|
|
4fe85b |
goto fail;
|
|
|
4fe85b |
@@ -267,14 +812,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
4fe85b |
grub_printf ("file path: ");
|
|
|
4fe85b |
grub_efi_print_device_path (file_path);
|
|
|
4fe85b |
|
|
|
4fe85b |
- size = grub_file_size (file);
|
|
|
4fe85b |
- if (!size)
|
|
|
4fe85b |
+ fsize = grub_file_size (file);
|
|
|
4fe85b |
+ if (!fsize)
|
|
|
4fe85b |
{
|
|
|
4fe85b |
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
|
|
4fe85b |
filename);
|
|
|
4fe85b |
goto fail;
|
|
|
4fe85b |
}
|
|
|
4fe85b |
- pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12);
|
|
|
4fe85b |
+ pages = (((grub_efi_uintn_t) fsize + ((1 << 12) - 1)) >> 12);
|
|
|
4fe85b |
|
|
|
4fe85b |
status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
|
|
|
4fe85b |
GRUB_EFI_LOADER_CODE,
|
|
|
4fe85b |
@@ -288,7 +833,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
4fe85b |
}
|
|
|
4fe85b |
|
|
|
4fe85b |
boot_image = (void *) ((grub_addr_t) address);
|
|
|
4fe85b |
- if (grub_file_read (file, boot_image, size) != size)
|
|
|
4fe85b |
+ if (grub_file_read (file, boot_image, fsize) != fsize)
|
|
|
4fe85b |
{
|
|
|
4fe85b |
if (grub_errno == GRUB_ERR_NONE)
|
|
|
4fe85b |
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
|
|
4fe85b |
@@ -298,7 +843,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
4fe85b |
}
|
|
|
4fe85b |
|
|
|
4fe85b |
#if defined (__i386__) || defined (__x86_64__)
|
|
|
4fe85b |
- if (size >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
|
|
|
4fe85b |
+ if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
|
|
|
4fe85b |
{
|
|
|
4fe85b |
struct grub_macho_fat_header *head = boot_image;
|
|
|
4fe85b |
if (head->magic
|
|
|
4fe85b |
@@ -307,6 +852,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
4fe85b |
grub_uint32_t i;
|
|
|
4fe85b |
struct grub_macho_fat_arch *archs
|
|
|
4fe85b |
= (struct grub_macho_fat_arch *) (head + 1);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+ if (grub_efi_secure_boot())
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_error (GRUB_ERR_BAD_OS,
|
|
|
4fe85b |
+ "MACHO binaries are forbidden with Secure Boot");
|
|
|
4fe85b |
+ goto fail;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
for (i = 0; i < grub_cpu_to_le32 (head->nfat_arch); i++)
|
|
|
4fe85b |
{
|
|
|
4fe85b |
if (GRUB_MACHO_CPUTYPE_IS_HOST_CURRENT (archs[i].cputype))
|
|
|
4fe85b |
@@ -321,21 +874,28 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
4fe85b |
> ~grub_cpu_to_le32 (archs[i].size)
|
|
|
4fe85b |
|| grub_cpu_to_le32 (archs[i].offset)
|
|
|
4fe85b |
+ grub_cpu_to_le32 (archs[i].size)
|
|
|
4fe85b |
- > (grub_size_t) size)
|
|
|
4fe85b |
+ > (grub_size_t) fsize)
|
|
|
4fe85b |
{
|
|
|
4fe85b |
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
|
|
4fe85b |
filename);
|
|
|
4fe85b |
goto fail;
|
|
|
4fe85b |
}
|
|
|
4fe85b |
boot_image = (char *) boot_image + grub_cpu_to_le32 (archs[i].offset);
|
|
|
4fe85b |
- size = grub_cpu_to_le32 (archs[i].size);
|
|
|
4fe85b |
+ fsize = grub_cpu_to_le32 (archs[i].size);
|
|
|
4fe85b |
}
|
|
|
4fe85b |
}
|
|
|
4fe85b |
#endif
|
|
|
4fe85b |
|
|
|
4fe85b |
+ if (grub_linuxefi_secure_validate((void *)address, fsize))
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_file_close (file);
|
|
|
4fe85b |
+ grub_loader_set (grub_secureboot_chainloader_boot,
|
|
|
4fe85b |
+ grub_secureboot_chainloader_unload, 0);
|
|
|
4fe85b |
+ return 0;
|
|
|
4fe85b |
+ }
|
|
|
4fe85b |
+
|
|
|
4fe85b |
status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
|
|
|
4fe85b |
- boot_image, size,
|
|
|
4fe85b |
- &image_handle);
|
|
|
4fe85b |
+ boot_image, fsize, &image_handle);
|
|
|
4fe85b |
if (status != GRUB_EFI_SUCCESS)
|
|
|
4fe85b |
{
|
|
|
4fe85b |
if (status == GRUB_EFI_OUT_OF_RESOURCES)
|
|
|
4fe85b |
@@ -357,33 +917,10 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
4fe85b |
}
|
|
|
4fe85b |
loaded_image->device_handle = dev_handle;
|
|
|
4fe85b |
|
|
|
4fe85b |
- if (argc > 1)
|
|
|
4fe85b |
+ if (cmdline)
|
|
|
4fe85b |
{
|
|
|
4fe85b |
- int i, len;
|
|
|
4fe85b |
- grub_efi_char16_t *p16;
|
|
|
4fe85b |
-
|
|
|
4fe85b |
- for (i = 1, len = 0; i < argc; i++)
|
|
|
4fe85b |
- len += grub_strlen (argv[i]) + 1;
|
|
|
4fe85b |
-
|
|
|
4fe85b |
- len *= sizeof (grub_efi_char16_t);
|
|
|
4fe85b |
- cmdline = p16 = grub_malloc (len);
|
|
|
4fe85b |
- if (! cmdline)
|
|
|
4fe85b |
- goto fail;
|
|
|
4fe85b |
-
|
|
|
4fe85b |
- for (i = 1; i < argc; i++)
|
|
|
4fe85b |
- {
|
|
|
4fe85b |
- char *p8;
|
|
|
4fe85b |
-
|
|
|
4fe85b |
- p8 = argv[i];
|
|
|
4fe85b |
- while (*p8)
|
|
|
4fe85b |
- *(p16++) = *(p8++);
|
|
|
4fe85b |
-
|
|
|
4fe85b |
- *(p16++) = ' ';
|
|
|
4fe85b |
- }
|
|
|
4fe85b |
- *(--p16) = 0;
|
|
|
4fe85b |
-
|
|
|
4fe85b |
loaded_image->load_options = cmdline;
|
|
|
4fe85b |
- loaded_image->load_options_size = len;
|
|
|
4fe85b |
+ loaded_image->load_options_size = cmdline_len;
|
|
|
4fe85b |
}
|
|
|
4fe85b |
|
|
|
4fe85b |
grub_file_close (file);
|
|
|
4fe85b |
@@ -405,6 +942,9 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
4fe85b |
if (address)
|
|
|
4fe85b |
efi_call_2 (b->free_pages, address, pages);
|
|
|
4fe85b |
|
|
|
4fe85b |
+ if (cmdline)
|
|
|
4fe85b |
+ grub_free (cmdline);
|
|
|
4fe85b |
+
|
|
|
4fe85b |
grub_dl_unref (my_mod);
|
|
|
4fe85b |
|
|
|
4fe85b |
return grub_errno;
|
|
|
4fe85b |
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
|
|
|
4fe85b |
index f79c36c026e..f79782e1bde 100644
|
|
|
4fe85b |
--- a/include/grub/efi/pe32.h
|
|
|
4fe85b |
+++ b/include/grub/efi/pe32.h
|
|
|
4fe85b |
@@ -212,7 +212,11 @@ struct grub_pe64_optional_header
|
|
|
4fe85b |
struct grub_pe32_section_table
|
|
|
4fe85b |
{
|
|
|
4fe85b |
char name[8];
|
|
|
4fe85b |
- grub_uint32_t virtual_size;
|
|
|
4fe85b |
+ union
|
|
|
4fe85b |
+ {
|
|
|
4fe85b |
+ grub_uint32_t physical_address;
|
|
|
4fe85b |
+ grub_uint32_t virtual_size;
|
|
|
4fe85b |
+ };
|
|
|
4fe85b |
grub_uint32_t virtual_address;
|
|
|
4fe85b |
grub_uint32_t raw_data_size;
|
|
|
4fe85b |
grub_uint32_t raw_data_offset;
|
|
|
4fe85b |
@@ -263,6 +267,20 @@ struct grub_pe32_header
|
|
|
4fe85b |
#endif
|
|
|
4fe85b |
};
|
|
|
4fe85b |
|
|
|
4fe85b |
+struct grub_pe32_header_32
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ char signature[GRUB_PE32_SIGNATURE_SIZE];
|
|
|
4fe85b |
+ struct grub_pe32_coff_header coff_header;
|
|
|
4fe85b |
+ struct grub_pe32_optional_header optional_header;
|
|
|
4fe85b |
+};
|
|
|
4fe85b |
+
|
|
|
4fe85b |
+struct grub_pe32_header_64
|
|
|
4fe85b |
+{
|
|
|
4fe85b |
+ char signature[GRUB_PE32_SIGNATURE_SIZE];
|
|
|
4fe85b |
+ struct grub_pe32_coff_header coff_header;
|
|
|
4fe85b |
+ struct grub_pe64_optional_header optional_header;
|
|
|
4fe85b |
+};
|
|
|
4fe85b |
+
|
|
|
4fe85b |
struct grub_pe32_fixup_block
|
|
|
4fe85b |
{
|
|
|
4fe85b |
grub_uint32_t page_rva;
|