48a2e836ff
This is done for moving packages that are related to secure boot out of LAT and into integ. Use grub version: 2.06-1 . Port grub-efi from LAT and make its build independent from grub2. The patches for code and changes for debian build are ported from layers ( meta-lat and meta-secure-core ) of yocto upstream. Make grub-efi independent from grub2 because some code changes for secure boot can make grub-pc's build fail. This porting of grub-efi customizes grub images and grub.cfg for efi boot. Install those files customized to grub-efi-amd64 package. Test Plan: The tests are done with all the changes for this porting, which involves efitools/shim/grub2/grub-efi/lat-sdk.sh, because they are in a chain for secure boot verification. - PASS: secure boot OK on qemu. - PASS: secure boot OK on PowerEdge R430 lab. - PASS: secure boot NG on qemu/hardware when shim/grub-efi images are without the right signatures. Story: 2009221 Task: 46402 Signed-off-by: Li Zhou <li.zhou@windriver.com> Change-Id: Ia3b482c1959b5e6462fe54f0b0e59a69db1b1ca7
583 lines
19 KiB
Diff
583 lines
19 KiB
Diff
From cb88b18b2648c89bccedb7bda25e398618110cbc Mon Sep 17 00:00:00 2001
|
|
From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
|
|
Date: Fri, 27 Mar 2015 08:19:21 -0700
|
|
Subject: [PATCH] efi: chainloader: port shim to grub
|
|
|
|
Upstream-Status: Inappropriate [embedded specific]
|
|
|
|
Shim is a thin loader to execute signed binaries under the
|
|
chain of trust of UEFI secure boot. Before executing the image,
|
|
shim verifies that such image is signed with any of the Machine
|
|
Owner Keys (MOKs). If the verification is successful, shim will
|
|
load, parse, relocate and execute the image.
|
|
|
|
Shim is useful in case the user does not want to modify the UEFI
|
|
database of valid certificates (DB).
|
|
|
|
This commit ports Matthew Garret's code from shim to grub in order
|
|
to provide to grub the capability of load and execute trusted
|
|
binaries. This is useful in case we need to chainload two bootloaders.
|
|
|
|
Shim can be found here: https://github.com/rhinstaller/shim
|
|
|
|
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
|
|
---
|
|
grub-core/loader/efi/chainloader.c | 534 +++++++++++++++++++++++++++++
|
|
1 file changed, 534 insertions(+)
|
|
|
|
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
|
|
index 2bd80f4..d192e2d 100644
|
|
--- a/grub-core/loader/efi/chainloader.c
|
|
+++ b/grub-core/loader/efi/chainloader.c
|
|
@@ -32,6 +32,7 @@
|
|
#include <grub/efi/api.h>
|
|
#include <grub/efi/efi.h>
|
|
#include <grub/efi/disk.h>
|
|
+#include <grub/efi/shim.h>
|
|
#include <grub/command.h>
|
|
#include <grub/i18n.h>
|
|
#include <grub/net.h>
|
|
@@ -49,6 +50,539 @@ static grub_efi_uintn_t pages;
|
|
static grub_efi_device_path_t *file_path;
|
|
static grub_efi_handle_t image_handle;
|
|
static grub_efi_char16_t *cmdline;
|
|
+static grub_int32_t shim_used;
|
|
+static grub_efi_physical_address_t shim_buffer;
|
|
+static grub_efi_uintn_t shim_pages;
|
|
+static grub_efi_loaded_image_t shim_li_bak;
|
|
+static grub_efi_status_t (*shim_entry_point) (grub_efi_handle_t image_handle,
|
|
+ grub_efi_system_table_t *systab);
|
|
+
|
|
+static const grub_uint16_t
|
|
+grub_shim_machine_type =
|
|
+#if defined(__x86_64__)
|
|
+ GRUB_PE32_MACHINE_X86_64;
|
|
+#elif defined(__aarch64__)
|
|
+ IMAGE_FILE_MACHINE_ARM64;
|
|
+#elif defined(__arm__)
|
|
+ IMAGE_FILE_MACHINE_ARMTHUMB_MIXED;
|
|
+#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
|
|
+ GRUB_PE32_MACHINE_I386;
|
|
+#elif defined(__ia64__)
|
|
+ GRUB_PE32_MACHINE_IA64;
|
|
+#else
|
|
+#error this architecture is not supported by shim chainloader
|
|
+#endif
|
|
+
|
|
+static grub_efi_guid_t grub_shim_protocol_guid = GRUB_EFI_SHIM_PROTOCOL_GUID;
|
|
+
|
|
+static grub_int32_t
|
|
+grub_shim_allow_64_bit (void)
|
|
+{
|
|
+/* TODO: what is the definition for aarch64? */
|
|
+#if defined(__x86_64__)
|
|
+ return 1;
|
|
+#elif defined(__i386__) || defined(__i686__)
|
|
+/* TODO: find out what to do with in_protocol */
|
|
+ return 0;
|
|
+#else /* assuming everything else is 32-bit... */
|
|
+ return 0;
|
|
+#endif
|
|
+}
|
|
+
|
|
+static grub_int32_t
|
|
+grub_shim_allow_32_bit (void)
|
|
+{
|
|
+/* TODO: what is the definition for aarch64? */
|
|
+#if defined(__x86_64__)
|
|
+/* TODO: find out what to do with in_protocol */
|
|
+ return 0;
|
|
+#elif defined(__i386__) || defined(__i686__)
|
|
+ return 1;
|
|
+#else /* assuming everything else is 32-bit... */
|
|
+ return 1;
|
|
+#endif
|
|
+}
|
|
+
|
|
+static grub_int32_t
|
|
+grub_shim_image_is_64_bit (union grub_shim_optional_header_union *pe_hdr)
|
|
+{
|
|
+ /* .Magic is the same offset in all cases */
|
|
+ if (pe_hdr->pe32plus.opt_hdr.magic == GRUB_PE32_PE64_MAGIC)
|
|
+ return 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static grub_int32_t
|
|
+grub_shim_image_is_loadable (union grub_shim_optional_header_union *pe_hdr)
|
|
+{
|
|
+ /* If the machine type doesn't match the binary, bail, unless
|
|
+ * we're in an allowed 64-on-32 scenario
|
|
+ */
|
|
+ if (pe_hdr->pe32.file_hdr.machine != grub_shim_machine_type)
|
|
+ {
|
|
+ if (!(grub_shim_machine_type == GRUB_PE32_MACHINE_I386
|
|
+ && pe_hdr->pe32.file_hdr.machine == GRUB_PE32_MACHINE_X86_64
|
|
+ && grub_shim_allow_64_bit ()))
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* If it's not a header type we recognize at all, bail */
|
|
+ switch (pe_hdr->pe32plus.opt_hdr.magic)
|
|
+ {
|
|
+ case GRUB_PE32_PE64_MAGIC:
|
|
+ case GRUB_PE32_PE32_MAGIC:
|
|
+ break;
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* and now just check for general 64-vs-32 compatibility */
|
|
+ if (grub_shim_image_is_64_bit(pe_hdr))
|
|
+ {
|
|
+ if (grub_shim_allow_64_bit ())
|
|
+ return 1;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (grub_shim_allow_32_bit ())
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Perform basic bounds checking of the intra-image pointers
|
|
+ */
|
|
+static grub_efi_uint64_t
|
|
+grub_shim_image_address (grub_addr_t image, grub_uint32_t size, grub_uint32_t addr)
|
|
+{
|
|
+ if (addr > size)
|
|
+ return 0;
|
|
+ return image + addr;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Perform the actual relocation
|
|
+ */
|
|
+static grub_err_t
|
|
+grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
|
|
+ void *orig, void *data)
|
|
+{
|
|
+ struct grub_image_base_relocation *reloc_base, *reloc_base_end;
|
|
+ grub_efi_uint64_t adjust;
|
|
+ grub_efi_uint16_t *reloc, *reloc_end;
|
|
+ grub_uint8_t *fixup, *fixup_base, *fixup_data = NULL;
|
|
+ grub_efi_uint16_t *fixup16;
|
|
+ grub_efi_uint32_t *fixup32;
|
|
+ grub_efi_uint64_t *fixup64;
|
|
+ grub_int32_t size = context->image_size;
|
|
+ void *image_end = (char *)orig + size;
|
|
+
|
|
+ if (grub_shim_image_is_64_bit(context->pe_hdr))
|
|
+ context->pe_hdr->pe32plus.opt_hdr.image_base = (grub_efi_uint64_t)(unsigned long)data;
|
|
+ else
|
|
+ context->pe_hdr->pe32.opt_hdr.image_base = (grub_efi_uint32_t)(unsigned long)data;
|
|
+
|
|
+ reloc_base = (struct grub_image_base_relocation *)
|
|
+ grub_shim_image_address ((grub_efi_uint64_t)orig, size,
|
|
+ context->reloc_dir->rva);
|
|
+ reloc_base_end = (struct grub_image_base_relocation *)
|
|
+ grub_shim_image_address ((grub_efi_uint64_t)orig, size,
|
|
+ context->reloc_dir->rva
|
|
+ + context->reloc_dir->size - 1);
|
|
+
|
|
+ if (!reloc_base || !reloc_base_end)
|
|
+ {
|
|
+ grub_printf("Reloc table overflows binary\n");
|
|
+ return GRUB_ERR_BAD_FILE_TYPE;
|
|
+ }
|
|
+
|
|
+ adjust = (grub_efi_uintn_t)data - context->image_address;
|
|
+
|
|
+ if (adjust == 0)
|
|
+ return GRUB_EFI_SUCCESS;
|
|
+
|
|
+ while (reloc_base < reloc_base_end)
|
|
+ {
|
|
+ reloc = (grub_efi_uint16_t *) ((grub_int8_t *) reloc_base
|
|
+ + sizeof (struct grub_image_base_relocation));
|
|
+
|
|
+ if ((reloc_base->block_size == 0)
|
|
+ || (reloc_base->block_size > context->reloc_dir->size))
|
|
+ {
|
|
+ grub_printf("Reloc block size %d is invalid\n", reloc_base->block_size);
|
|
+ return GRUB_ERR_FILE_READ_ERROR;
|
|
+ }
|
|
+
|
|
+ reloc_end = (grub_efi_uint16_t *)
|
|
+ ((grub_uint8_t *) reloc_base + reloc_base->block_size);
|
|
+ if ((void *)reloc_end < orig || (void *)reloc_end > image_end)
|
|
+ {
|
|
+ grub_printf("Reloc entry overflows binary\n");
|
|
+ return GRUB_ERR_FILE_READ_ERROR;
|
|
+ }
|
|
+
|
|
+ fixup_base = (grub_uint8_t *)
|
|
+ grub_shim_image_address ((grub_efi_uint64_t)data,
|
|
+ size,
|
|
+ reloc_base->virtual_address);
|
|
+ if (!fixup_base)
|
|
+ {
|
|
+ grub_printf("Invalid fixup_base\n");
|
|
+ return GRUB_ERR_FILE_READ_ERROR;
|
|
+ }
|
|
+
|
|
+ while (reloc < reloc_end)
|
|
+ {
|
|
+ fixup = fixup_base + (*reloc & 0xFFF);
|
|
+ switch ((*reloc) >> 12)
|
|
+ {
|
|
+ case EFI_IMAGE_REL_BASED_ABSOLUTE:
|
|
+ break;
|
|
+
|
|
+ case EFI_IMAGE_REL_BASED_HIGH:
|
|
+ fixup16 = (grub_efi_uint16_t *) fixup;
|
|
+ *fixup16 = (grub_efi_uint16_t)
|
|
+ (*fixup16
|
|
+ + ((grub_efi_uint16_t) ((grub_efi_uint32_t) adjust >> 16)));
|
|
+ if (fixup_data != NULL)
|
|
+ {
|
|
+ *(grub_efi_uint16_t *) fixup_data = *fixup16;
|
|
+ fixup_data = fixup_data + sizeof (grub_efi_uint16_t);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case EFI_IMAGE_REL_BASED_LOW:
|
|
+ fixup16 = (grub_efi_uint16_t *) fixup;
|
|
+ *fixup16 = (grub_efi_uint16_t)
|
|
+ (*fixup16 + (grub_efi_uint16_t) adjust);
|
|
+ if (fixup_data != NULL)
|
|
+ {
|
|
+ *(grub_efi_uint16_t *) fixup_data = *fixup16;
|
|
+ fixup_data = fixup_data + sizeof (grub_efi_uint16_t);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case EFI_IMAGE_REL_BASED_HIGHLOW:
|
|
+ fixup32 = (grub_efi_uint32_t *) fixup;
|
|
+ *fixup32 = *fixup32 + (grub_efi_uint32_t) adjust;
|
|
+ if (fixup_data != NULL)
|
|
+ {
|
|
+ fixup_data = ALIGN_POINTER (fixup_data, sizeof (grub_efi_uint32_t));
|
|
+ *(grub_efi_uint32_t *)fixup_data = *fixup32;
|
|
+ fixup_data = fixup_data + sizeof (grub_efi_uint32_t);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case EFI_IMAGE_REL_BASED_DIR64:
|
|
+ fixup64 = (grub_efi_uint64_t *) fixup;
|
|
+ *fixup64 = *fixup64 + (grub_efi_uint64_t) adjust;
|
|
+ if (fixup_data != NULL)
|
|
+ {
|
|
+ fixup_data = ALIGN_POINTER (fixup_data, sizeof(grub_efi_uint64_t));
|
|
+ *(grub_efi_uint64_t *)(fixup_data) = *fixup64;
|
|
+ fixup_data = fixup_data + sizeof(grub_efi_uint64_t);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ grub_printf("Unknown relocation\n");
|
|
+ return GRUB_ERR_FILE_READ_ERROR;
|
|
+ }
|
|
+ reloc += 1;
|
|
+ }
|
|
+ reloc_base = (struct grub_image_base_relocation *) reloc_end;
|
|
+ }
|
|
+
|
|
+ return GRUB_EFI_SUCCESS;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Read the binary header and grab appropriate information from it
|
|
+ */
|
|
+static grub_err_t
|
|
+grub_shim_read_header(grub_efi_physical_address_t data, grub_uint32_t datasize,
|
|
+ struct grub_shim_pe_coff_loader_image_context *context)
|
|
+{
|
|
+ struct grub_dos_header *dos_hdr = (struct grub_dos_header *)data;
|
|
+ union grub_shim_optional_header_union *pe_hdr = (union grub_shim_optional_header_union *)data;
|
|
+ grub_uint64_t header_without_data_dir, section_header_offset, opt_hdr_size;
|
|
+
|
|
+ if (datasize < sizeof (pe_hdr->pe32))
|
|
+ {
|
|
+ grub_printf("Invalid image\n");
|
|
+ return GRUB_ERR_BAD_FILE_TYPE;
|
|
+ }
|
|
+
|
|
+ if (dos_hdr->magic == EFI_IMAGE_DOS_SIGNATURE)
|
|
+ pe_hdr = (union grub_shim_optional_header_union *)((grub_uint8_t *)data
|
|
+ + dos_hdr->lfanew);
|
|
+
|
|
+ if (!grub_shim_image_is_loadable(pe_hdr))
|
|
+ {
|
|
+ grub_printf("Platform does not support this image\n");
|
|
+ return GRUB_ERR_BAD_FILE_TYPE;
|
|
+ }
|
|
+
|
|
+ if (grub_shim_image_is_64_bit(pe_hdr))
|
|
+ {
|
|
+ context->number_of_rva_and_sizes = pe_hdr->pe32plus.opt_hdr.num_data_directories;
|
|
+ context->header_size = pe_hdr->pe32plus.opt_hdr.header_size;
|
|
+ context->image_size = pe_hdr->pe32plus.opt_hdr.image_size;
|
|
+ opt_hdr_size = sizeof(struct grub_pe64_optional_header);
|
|
+ } else
|
|
+ {
|
|
+ context->number_of_rva_and_sizes = pe_hdr->pe32.opt_hdr.num_data_directories;
|
|
+ context->header_size = pe_hdr->pe32.opt_hdr.header_size;
|
|
+ context->image_size = (grub_efi_uint64_t)pe_hdr->pe32.opt_hdr.header_size;
|
|
+ opt_hdr_size = sizeof(struct grub_pe32_optional_header);
|
|
+ }
|
|
+
|
|
+ context->num_sections = pe_hdr->pe32.file_hdr.num_sections;
|
|
+
|
|
+ if (GRUB_PE32_NUM_DATA_DIRECTORIES < context->number_of_rva_and_sizes)
|
|
+ {
|
|
+ grub_printf("Image header too small\n");
|
|
+ return GRUB_ERR_FILE_READ_ERROR;
|
|
+ }
|
|
+
|
|
+ header_without_data_dir = opt_hdr_size
|
|
+ - sizeof (struct grub_pe32_data_directory)
|
|
+ * GRUB_PE32_NUM_DATA_DIRECTORIES;
|
|
+ if (((grub_efi_uint32_t)pe_hdr->pe32.file_hdr.optional_header_size
|
|
+ - header_without_data_dir) !=
|
|
+ context->number_of_rva_and_sizes * sizeof (struct grub_pe32_data_directory))
|
|
+ {
|
|
+ grub_printf("Image header overflows data directory\n");
|
|
+ return GRUB_ERR_FILE_READ_ERROR;
|
|
+ }
|
|
+
|
|
+ section_header_offset = dos_hdr->lfanew
|
|
+ + sizeof (grub_efi_uint32_t)
|
|
+ + sizeof (struct grub_pe32_coff_header)
|
|
+ + pe_hdr->pe32.file_hdr.optional_header_size;
|
|
+ if (((grub_efi_uint32_t)context->image_size - section_header_offset)
|
|
+ / sizeof (struct grub_pe32_section_table)
|
|
+ <= context->num_sections)
|
|
+ {
|
|
+ grub_printf("Image sections overflow image size\n");
|
|
+ return GRUB_ERR_FILE_READ_ERROR;
|
|
+ }
|
|
+
|
|
+ if ((context->header_size - section_header_offset)
|
|
+ / sizeof (struct grub_pe32_section_table)
|
|
+ < (grub_efi_uint32_t)context->num_sections)
|
|
+ {
|
|
+ grub_printf("Image sections overflow section headers\n");
|
|
+ return GRUB_ERR_FILE_READ_ERROR;
|
|
+ }
|
|
+
|
|
+ if ((((grub_efi_uint8_t *)pe_hdr
|
|
+ - (grub_efi_uint8_t *)data)
|
|
+ + sizeof(union grub_shim_optional_header_union )) > datasize)
|
|
+ {
|
|
+ grub_printf("Invalid image\n");
|
|
+ return GRUB_ERR_BAD_FILE_TYPE;
|
|
+ }
|
|
+
|
|
+ if (pe_hdr->te.signature != EFI_IMAGE_NT_SIGNATURE)
|
|
+ {
|
|
+ grub_printf("Unsupported image type\n");
|
|
+ return GRUB_ERR_BAD_FILE_TYPE;
|
|
+ }
|
|
+
|
|
+ if (pe_hdr->pe32.file_hdr.characteristics & GRUB_PE32_RELOCS_STRIPPED)
|
|
+ {
|
|
+ grub_printf("Unsupported image - Relocations have been stripped\n");
|
|
+ return GRUB_ERR_BAD_FILE_TYPE;
|
|
+ }
|
|
+
|
|
+ context->pe_hdr = pe_hdr;
|
|
+
|
|
+ if (grub_shim_image_is_64_bit(pe_hdr))
|
|
+ {
|
|
+ context->image_address = pe_hdr->pe32plus.opt_hdr.image_base;
|
|
+ context->entry_point = pe_hdr->pe32plus.opt_hdr.entry_addr;
|
|
+ context->reloc_dir = &pe_hdr->pe32plus.opt_hdr.base_relocation_table;
|
|
+ context->sec_dir = &pe_hdr->pe32plus.opt_hdr.certificate_table;
|
|
+ } else
|
|
+ {
|
|
+ context->image_address = pe_hdr->pe32.opt_hdr.image_base;
|
|
+ context->entry_point = pe_hdr->pe32.opt_hdr.entry_addr;
|
|
+ context->reloc_dir = &pe_hdr->pe32.opt_hdr.base_relocation_table;
|
|
+ context->sec_dir = &pe_hdr->pe32.opt_hdr.certificate_table;
|
|
+ }
|
|
+
|
|
+ context->first_section = (struct grub_pe32_section_table *)
|
|
+ ((char *)pe_hdr
|
|
+ + pe_hdr->pe32.file_hdr.optional_header_size
|
|
+ + sizeof(grub_efi_uint32_t)
|
|
+ + sizeof(struct grub_pe32_coff_header));
|
|
+
|
|
+ if (context->image_size < context->header_size)
|
|
+ {
|
|
+ grub_printf("Invalid image\n");
|
|
+ return GRUB_ERR_BAD_FILE_TYPE;
|
|
+ }
|
|
+
|
|
+ if ((unsigned long)((grub_efi_uint8_t *)context->sec_dir - (grub_efi_uint8_t *)data) >
|
|
+ (datasize - sizeof(struct grub_pe32_data_directory)))
|
|
+ {
|
|
+ grub_printf("Invalid image\n");
|
|
+ return GRUB_ERR_BAD_FILE_TYPE;
|
|
+ }
|
|
+
|
|
+ if (context->sec_dir->rva >= datasize)
|
|
+ {
|
|
+ grub_printf("Malformed security header\n");
|
|
+ return GRUB_ERR_BAD_FILE_TYPE;
|
|
+ }
|
|
+ return GRUB_ERR_NONE;
|
|
+}
|
|
+
|
|
+static grub_efi_status_t
|
|
+grub_shim_verify (grub_addr_t addr, grub_ssize_t size)
|
|
+{
|
|
+ struct grub_shim_lock *shim_lock;
|
|
+ shim_lock = grub_efi_locate_protocol (&grub_shim_protocol_guid, 0);
|
|
+ if (!shim_lock)
|
|
+ {
|
|
+ grub_error (GRUB_ERR_BAD_OS, "could not load shim protocol");
|
|
+ return GRUB_EFI_UNSUPPORTED;
|
|
+ }
|
|
+
|
|
+ return shim_lock->verify((void *) addr, size);
|
|
+}
|
|
+
|
|
+static grub_err_t
|
|
+grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
|
|
+ struct grub_shim_pe_coff_loader_image_context *context)
|
|
+{
|
|
+ grub_err_t status;
|
|
+ grub_efi_status_t efi_status;
|
|
+ grub_uint32_t sect_size;
|
|
+ /* TODO: can they be unsigned? */
|
|
+ grub_int8_t *base, *end;
|
|
+ grub_int32_t i;
|
|
+ struct grub_pe32_section_table *section;
|
|
+ grub_efi_boot_services_t *b;
|
|
+
|
|
+ shim_used = 0;
|
|
+ shim_buffer = 0;
|
|
+
|
|
+ status = grub_shim_verify (addr, size);
|
|
+ if (status != GRUB_ERR_NONE)
|
|
+ {
|
|
+ grub_error (GRUB_ERR_BAD_OS, "shim verification failed");
|
|
+ return GRUB_ERR_BAD_OS;
|
|
+ }
|
|
+
|
|
+ grub_memset(context, 0, sizeof(*context));
|
|
+ status = grub_shim_read_header (addr, size, context);
|
|
+ if (status != GRUB_ERR_NONE)
|
|
+ {
|
|
+ grub_error (GRUB_ERR_BAD_OS, "read header failed");
|
|
+ return GRUB_ERR_BAD_OS;
|
|
+ }
|
|
+
|
|
+ /* TODO: do we need to do this with efi_allocate? */
|
|
+ shim_pages = (((grub_efi_uintn_t) context->image_size + ((1 << 12) - 1)) >> 12);
|
|
+
|
|
+ b = grub_efi_system_table->boot_services;
|
|
+ efi_status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
|
|
+ GRUB_EFI_LOADER_CODE, shim_pages, &shim_buffer);
|
|
+ if (efi_status != GRUB_EFI_SUCCESS)
|
|
+ {
|
|
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory for shim buffer"));
|
|
+ return GRUB_ERR_OUT_OF_MEMORY;
|
|
+ }
|
|
+
|
|
+ /* TODO: do we need the double cast? */
|
|
+ grub_memcpy ((void *) ((grub_efi_physical_address_t) shim_buffer),
|
|
+ (void *) ((grub_addr_t) addr), context->header_size);
|
|
+ /*
|
|
+ * Copy the executable's sections to their desired offsets
|
|
+ */
|
|
+ section = context->first_section;
|
|
+ for (i = 0; i < context->num_sections; i++, section++)
|
|
+ {
|
|
+ if (section->characteristics & 0x02000000)
|
|
+ /* section has EFI_IMAGE_SCN_MEM_DISCARDABLE attr set */
|
|
+ continue;
|
|
+
|
|
+ sect_size = section->virtual_size;
|
|
+
|
|
+ if (sect_size > section->raw_data_size)
|
|
+ sect_size = section->raw_data_size;
|
|
+
|
|
+ base = (grub_int8_t *)
|
|
+ grub_shim_image_address (shim_buffer, context->image_size,
|
|
+ section->virtual_address);
|
|
+ end = (grub_int8_t *)
|
|
+ grub_shim_image_address (shim_buffer, context->image_size,
|
|
+ section->virtual_address
|
|
+ + sect_size - 1);
|
|
+ if (!base || !end)
|
|
+ {
|
|
+ grub_printf("Invalid section base\n");
|
|
+ status = GRUB_ERR_BAD_FILE_TYPE;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ if (section->virtual_address < context->header_size
|
|
+ || section->raw_data_offset < context->header_size)
|
|
+ {
|
|
+ grub_printf("Section is inside image headers\n");
|
|
+ status = GRUB_ERR_BAD_FILE_TYPE;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ if (section->raw_data_size > 0)
|
|
+ /* TODO: do we need the double cast? */
|
|
+ grub_memcpy ((void *)base,
|
|
+ (void *) (((grub_addr_t) addr)
|
|
+ + section->raw_data_offset), sect_size);
|
|
+
|
|
+ if (sect_size < section->virtual_size)
|
|
+ grub_memset ((void *)(base + sect_size), 0,
|
|
+ section->virtual_size - sect_size);
|
|
+ }
|
|
+
|
|
+ if (context->number_of_rva_and_sizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)
|
|
+ {
|
|
+ grub_printf("Image has no relocation entry\n");
|
|
+ status = GRUB_ERR_BAD_FILE_TYPE;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ if (context->reloc_dir->size)
|
|
+ {
|
|
+ status = grub_shim_relocate_coff (context, (void *) addr,
|
|
+ (void *) shim_buffer);
|
|
+ if (status != GRUB_ERR_NONE)
|
|
+ {
|
|
+ grub_printf("Relocation failed: [%u]\n", status);
|
|
+ status = GRUB_ERR_BAD_FILE_TYPE;
|
|
+ goto fail;
|
|
+ }
|
|
+ }
|
|
+ shim_entry_point = (void *)grub_shim_image_address (shim_buffer,
|
|
+ context->image_size,
|
|
+ context->entry_point);
|
|
+ if (!shim_entry_point)
|
|
+ {
|
|
+ grub_printf("Invalid entry point\n");
|
|
+ status = GRUB_ERR_BAD_FILE_TYPE;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ shim_used = 1;
|
|
+ return GRUB_ERR_NONE;
|
|
+fail:
|
|
+ efi_call_2 (b->free_pages, shim_buffer, shim_pages);
|
|
+ shim_buffer = 0;
|
|
+ return status;
|
|
+}
|
|
|
|
static grub_err_t
|
|
grub_chainloader_unload (void)
|
|
--
|
|
2.17.1
|
|
|