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
224 lines
8.5 KiB
Diff
224 lines
8.5 KiB
Diff
From 3df0895087be6affb95db4f42239bc0160c16bfa Mon Sep 17 00:00:00 2001
|
|
From: Lans Zhang <jia.zhang@windriver.com>
|
|
Date: Sun, 24 Apr 2016 19:02:28 +0800
|
|
Subject: [PATCH] chainloader: find the relocations correctly
|
|
|
|
Upstream-Status: Pending
|
|
|
|
Refer to a846aedd0e9dfe26ca6afaf6a1db8a54c20363c1 in shim.
|
|
|
|
Actually find the relocations correctly and process them that way
|
|
in chainloader.
|
|
|
|
Find the relocations based on the *file* address in the old binary,
|
|
because it's only the same as the virtual address some of the time.
|
|
|
|
Also perform some extra validation before processing it, and don't bail
|
|
out in /error/ if both reloc_base and reloc_base_end are null - that
|
|
condition is fine.
|
|
|
|
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
|
|
[lz: Adapt git log and do some whitespaces cleanups.]
|
|
Signed-off-by: Li Zhou <li.zhou@windriver.com>
|
|
---
|
|
grub-core/loader/efi/chainloader.c | 97 +++++++++++++++++++++++++-----
|
|
1 file changed, 81 insertions(+), 16 deletions(-)
|
|
|
|
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
|
|
index f736bee..0979dc0 100644
|
|
--- a/grub-core/loader/efi/chainloader.c
|
|
+++ b/grub-core/loader/efi/chainloader.c
|
|
@@ -166,6 +166,7 @@ grub_shim_image_address (grub_addr_t image, grub_uint32_t size, grub_uint32_t ad
|
|
*/
|
|
static grub_err_t
|
|
grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
|
|
+ struct grub_pe32_section_table *section,
|
|
void *orig, void *data)
|
|
{
|
|
struct grub_image_base_relocation *reloc_base, *reloc_base_end;
|
|
@@ -177,19 +178,53 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
|
|
grub_efi_uint64_t *fixup64;
|
|
grub_int32_t size = context->image_size;
|
|
void *image_end = (char *)orig + size;
|
|
+ int n = 0;
|
|
|
|
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;
|
|
|
|
+
|
|
+ /* Alright, so here's how this works:
|
|
+ *
|
|
+ * context->RelocDir gives us two things:
|
|
+ * - the VA the table of base relocation blocks are (maybe) to be
|
|
+ * mapped at (RelocDir->VirtualAddress)
|
|
+ * - the virtual size (RelocDir->Size)
|
|
+ *
|
|
+ * The .reloc section (Section here) gives us some other things:
|
|
+ * - the name! kind of. (Section->Name)
|
|
+ * - the virtual size (Section->VirtualSize), which should be the same
|
|
+ * as RelocDir->Size
|
|
+ * - the virtual address (Section->VirtualAddress)
|
|
+ * - the file section size (Section->SizeOfRawData), which is
|
|
+ * a multiple of OptHdr->FileAlignment. Only useful for image
|
|
+ * validation, not really useful for iteration bounds.
|
|
+ * - the file address (Section->PointerToRawData)
|
|
+ * - a bunch of stuff we don't use that's 0 in our binaries usually
|
|
+ * - Flags (Section->Characteristics)
|
|
+ *
|
|
+ * and then the thing that's actually at the file address is an array
|
|
+ * of EFI_IMAGE_BASE_RELOCATION structs with some values packed behind
|
|
+ * them. The SizeOfBlock field of this structure includes the
|
|
+ * structure itself, and adding it to that structure's address will
|
|
+ * yield the next entry in the array.
|
|
+ */
|
|
reloc_base = (struct grub_image_base_relocation *)
|
|
grub_shim_image_address ((grub_efi_uint64_t)orig, size,
|
|
- context->reloc_dir->rva);
|
|
+ section->raw_data_offset);
|
|
+ /* reloc_base_end is the address of the first entry /past/ the
|
|
+ * table. */
|
|
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);
|
|
+ section->raw_data_offset
|
|
+ + section->virtual_size - 1);
|
|
+
|
|
+ if (!reloc_base && !reloc_base_end)
|
|
+ {
|
|
+ return GRUB_EFI_SUCCESS;
|
|
+ }
|
|
|
|
if (!reloc_base || !reloc_base_end)
|
|
{
|
|
@@ -210,7 +245,7 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
|
|
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);
|
|
+ grub_printf("Reloc %d block size %d is invalid\n", n, reloc_base->block_size);
|
|
return GRUB_ERR_FILE_READ_ERROR;
|
|
}
|
|
|
|
@@ -218,7 +253,7 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
|
|
((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");
|
|
+ grub_printf("Reloc %d entry overflows binary\n", n);
|
|
return GRUB_ERR_FILE_READ_ERROR;
|
|
}
|
|
|
|
@@ -228,7 +263,7 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
|
|
reloc_base->virtual_address);
|
|
if (!fixup_base)
|
|
{
|
|
- grub_printf("Invalid fixup_base\n");
|
|
+ grub_printf("Reloc %d invalid fixup_base\n", n);
|
|
return GRUB_ERR_FILE_READ_ERROR;
|
|
}
|
|
|
|
@@ -286,12 +321,13 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
|
|
break;
|
|
|
|
default:
|
|
- grub_printf("Unknown relocation\n");
|
|
+ grub_printf("Reloc %d unknown relocation\n", n);
|
|
return GRUB_ERR_FILE_READ_ERROR;
|
|
}
|
|
reloc += 1;
|
|
}
|
|
reloc_base = (struct grub_image_base_relocation *) reloc_end;
|
|
+ n++;
|
|
}
|
|
|
|
return GRUB_EFI_SUCCESS;
|
|
@@ -462,9 +498,9 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
|
|
grub_efi_status_t efi_status;
|
|
grub_uint32_t sect_size;
|
|
/* TODO: can they be unsigned? */
|
|
- grub_int8_t *base, *end;
|
|
+ grub_int8_t *base, *end, *reloc_base, *reloc_base_end;
|
|
grub_int32_t i;
|
|
- struct grub_pe32_section_table *section;
|
|
+ struct grub_pe32_section_table *section, *reloc_section;
|
|
grub_efi_boot_services_t *b;
|
|
|
|
shim_used = 0;
|
|
@@ -500,16 +536,21 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
|
|
/* 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);
|
|
+
|
|
+ reloc_base = (grub_int8_t *) grub_shim_image_address (shim_buffer, size,
|
|
+ context->reloc_dir->rva);
|
|
+ /* reloc_base_end here is the address of the last byte of the table */
|
|
+ reloc_base_end = (grub_int8_t *) grub_shim_image_address (shim_buffer, size,
|
|
+ context->reloc_dir->rva +
|
|
+ context->reloc_dir->size - 1);
|
|
+ reloc_section = NULL;
|
|
+
|
|
/*
|
|
* 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)
|
|
@@ -522,6 +563,30 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
|
|
grub_shim_image_address (shim_buffer, context->image_size,
|
|
section->virtual_address
|
|
+ sect_size - 1);
|
|
+
|
|
+ /* We do want to process .reloc, but it's often marked
|
|
+ * discardable, so we don't want to memcpy it. */
|
|
+ if (grub_memcmp (section->name, ".reloc\0\0", 8) == 0) {
|
|
+ if (reloc_section) {
|
|
+ grub_printf("Image has multiple relocation sections\n");
|
|
+ status = GRUB_ERR_BAD_FILE_TYPE;
|
|
+ goto fail;
|
|
+ }
|
|
+ /* If it has nonzero sizes, and our bounds check
|
|
+ * made sense, and the VA and size match RelocDir's
|
|
+ * versions, then we believe in this section table. */
|
|
+ if (section->raw_data_size && section->virtual_size &&
|
|
+ base && end &&
|
|
+ reloc_base == base &&
|
|
+ reloc_base_end == end) {
|
|
+ reloc_section = section;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (section->characteristics & 0x02000000)
|
|
+ /* section has EFI_IMAGE_SCN_MEM_DISCARDABLE attr set */
|
|
+ continue;
|
|
+
|
|
if (!base || !end)
|
|
{
|
|
grub_printf("Invalid section base\n");
|
|
@@ -555,10 +620,10 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
|
|
goto fail;
|
|
}
|
|
|
|
- if (context->reloc_dir->size)
|
|
+ if (context->reloc_dir->size && reloc_section)
|
|
{
|
|
- status = grub_shim_relocate_coff (context, (void *) addr,
|
|
- (void *) shim_buffer);
|
|
+ status = grub_shim_relocate_coff (context, reloc_section,
|
|
+ (void *) addr, (void *) shim_buffer);
|
|
if (status != GRUB_ERR_NONE)
|
|
{
|
|
grub_printf("Relocation failed: [%u]\n", status);
|
|
--
|
|
2.17.1
|
|
|