|
|
4210fa |
From a846aedd0e9dfe26ca6afaf6a1db8a54c20363c1 Mon Sep 17 00:00:00 2001
|
|
|
4210fa |
From: Peter Jones <pjones@redhat.com>
|
|
|
4210fa |
Date: Tue, 30 Sep 2014 18:52:59 -0400
|
|
|
4210fa |
Subject: [PATCH 64/74] Actually find the relocations correctly and process
|
|
|
4210fa |
them that way.
|
|
|
4210fa |
|
|
|
4210fa |
Find the relocations based on the *file* address in the old binary,
|
|
|
4210fa |
because it's only the same as the virtual address some of the time.
|
|
|
4210fa |
|
|
|
4210fa |
Also perform some extra validation before processing it, and don't bail
|
|
|
4210fa |
out in /error/ if both ReloceBase and RelocEnd are null - that condition
|
|
|
4210fa |
is fine.
|
|
|
4210fa |
|
|
|
4210fa |
Signed-off-by: Peter Jones <pjones@redhat.com>
|
|
|
4210fa |
---
|
|
|
4210fa |
shim.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
|
|
|
4210fa |
1 file changed, 77 insertions(+), 13 deletions(-)
|
|
|
4210fa |
|
|
|
4210fa |
diff --git a/shim.c b/shim.c
|
|
|
4210fa |
index 7cd4182..4baf8b1 100644
|
|
|
4210fa |
--- a/shim.c
|
|
|
4210fa |
+++ b/shim.c
|
|
|
4210fa |
@@ -222,6 +222,7 @@ image_is_loadable(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
|
|
|
4210fa |
* Perform the actual relocation
|
|
|
4210fa |
*/
|
|
|
4210fa |
static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
|
|
|
4210fa |
+ EFI_IMAGE_SECTION_HEADER *Section,
|
|
|
4210fa |
void *orig, void *data)
|
|
|
4210fa |
{
|
|
|
4210fa |
EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
|
|
|
4210fa |
@@ -233,14 +234,46 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
|
|
|
4210fa |
UINT64 *Fixup64;
|
|
|
4210fa |
int size = context->ImageSize;
|
|
|
4210fa |
void *ImageEnd = (char *)orig + size;
|
|
|
4210fa |
+ int n = 0;
|
|
|
4210fa |
|
|
|
4210fa |
if (image_is_64_bit(context->PEHdr))
|
|
|
4210fa |
context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)(unsigned long)data;
|
|
|
4210fa |
else
|
|
|
4210fa |
context->PEHdr->Pe32.OptionalHeader.ImageBase = (UINT32)(unsigned long)data;
|
|
|
4210fa |
|
|
|
4210fa |
- RelocBase = ImageAddress(orig, size, context->RelocDir->VirtualAddress);
|
|
|
4210fa |
- RelocBaseEnd = ImageAddress(orig, size, context->RelocDir->VirtualAddress + context->RelocDir->Size - 1);
|
|
|
4210fa |
+ /* Alright, so here's how this works:
|
|
|
4210fa |
+ *
|
|
|
4210fa |
+ * context->RelocDir gives us two things:
|
|
|
4210fa |
+ * - the VA the table of base relocation blocks are (maybe) to be
|
|
|
4210fa |
+ * mapped at (RelocDir->VirtualAddress)
|
|
|
4210fa |
+ * - the virtual size (RelocDir->Size)
|
|
|
4210fa |
+ *
|
|
|
4210fa |
+ * The .reloc section (Section here) gives us some other things:
|
|
|
4210fa |
+ * - the name! kind of. (Section->Name)
|
|
|
4210fa |
+ * - the virtual size (Section->VirtualSize), which should be the same
|
|
|
4210fa |
+ * as RelocDir->Size
|
|
|
4210fa |
+ * - the virtual address (Section->VirtualAddress)
|
|
|
4210fa |
+ * - the file section size (Section->SizeOfRawData), which is
|
|
|
4210fa |
+ * a multiple of OptHdr->FileAlignment. Only useful for image
|
|
|
4210fa |
+ * validation, not really useful for iteration bounds.
|
|
|
4210fa |
+ * - the file address (Section->PointerToRawData)
|
|
|
4210fa |
+ * - a bunch of stuff we don't use that's 0 in our binaries usually
|
|
|
4210fa |
+ * - Flags (Section->Characteristics)
|
|
|
4210fa |
+ *
|
|
|
4210fa |
+ * and then the thing that's actually at the file address is an array
|
|
|
4210fa |
+ * of EFI_IMAGE_BASE_RELOCATION structs with some values packed behind
|
|
|
4210fa |
+ * them. The SizeOfBlock field of this structure includes the
|
|
|
4210fa |
+ * structure itself, and adding it to that structure's address will
|
|
|
4210fa |
+ * yield the next entry in the array.
|
|
|
4210fa |
+ */
|
|
|
4210fa |
+ RelocBase = ImageAddress(orig, size, Section->PointerToRawData);
|
|
|
4210fa |
+ /* RelocBaseEnd here is the address of the first entry /past/ the
|
|
|
4210fa |
+ * table. */
|
|
|
4210fa |
+ RelocBaseEnd = ImageAddress(orig, size, Section->PointerToRawData +
|
|
|
4210fa |
+ Section->Misc.VirtualSize);
|
|
|
4210fa |
+
|
|
|
4210fa |
+ if (!RelocBase && !RelocBaseEnd)
|
|
|
4210fa |
+ return EFI_SUCCESS;
|
|
|
4210fa |
|
|
|
4210fa |
if (!RelocBase || !RelocBaseEnd) {
|
|
|
4210fa |
perror(L"Reloc table overflows binary\n");
|
|
|
4210fa |
@@ -256,19 +289,19 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
|
|
|
4210fa |
Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
|
|
|
4210fa |
|
|
|
4210fa |
if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > context->RelocDir->Size)) {
|
|
|
4210fa |
- perror(L"Reloc block size %d is invalid\n", RelocBase->SizeOfBlock);
|
|
|
4210fa |
+ perror(L"Reloc %d block size %d is invalid\n", n, RelocBase->SizeOfBlock);
|
|
|
4210fa |
return EFI_UNSUPPORTED;
|
|
|
4210fa |
}
|
|
|
4210fa |
|
|
|
4210fa |
RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
|
|
|
4210fa |
if ((void *)RelocEnd < orig || (void *)RelocEnd > ImageEnd) {
|
|
|
4210fa |
- perror(L"Reloc entry overflows binary\n");
|
|
|
4210fa |
+ perror(L"Reloc %d entry overflows binary\n", n);
|
|
|
4210fa |
return EFI_UNSUPPORTED;
|
|
|
4210fa |
}
|
|
|
4210fa |
|
|
|
4210fa |
FixupBase = ImageAddress(data, size, RelocBase->VirtualAddress);
|
|
|
4210fa |
if (!FixupBase) {
|
|
|
4210fa |
- perror(L"Invalid fixupbase\n");
|
|
|
4210fa |
+ perror(L"Reloc %d Invalid fixupbase\n", n);
|
|
|
4210fa |
return EFI_UNSUPPORTED;
|
|
|
4210fa |
}
|
|
|
4210fa |
|
|
|
4210fa |
@@ -317,12 +350,13 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
|
|
|
4210fa |
break;
|
|
|
4210fa |
|
|
|
4210fa |
default:
|
|
|
4210fa |
- perror(L"Unknown relocation\n");
|
|
|
4210fa |
+ perror(L"Reloc %d Unknown relocation\n", n);
|
|
|
4210fa |
return EFI_UNSUPPORTED;
|
|
|
4210fa |
}
|
|
|
4210fa |
Reloc += 1;
|
|
|
4210fa |
}
|
|
|
4210fa |
RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
|
|
|
4210fa |
+ n++;
|
|
|
4210fa |
}
|
|
|
4210fa |
|
|
|
4210fa |
return EFI_SUCCESS;
|
|
|
4210fa |
@@ -1102,15 +1136,21 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
|
|
|
4210fa |
|
|
|
4210fa |
CopyMem(buffer, data, context.SizeOfHeaders);
|
|
|
4210fa |
|
|
|
4210fa |
+ char *RelocBase, *RelocBaseEnd;
|
|
|
4210fa |
+ RelocBase = ImageAddress(buffer, datasize,
|
|
|
4210fa |
+ context.RelocDir->VirtualAddress);
|
|
|
4210fa |
+ /* RelocBaseEnd here is the address of the last byte of the table */
|
|
|
4210fa |
+ RelocBaseEnd = ImageAddress(buffer, datasize,
|
|
|
4210fa |
+ context.RelocDir->VirtualAddress +
|
|
|
4210fa |
+ context.RelocDir->Size - 1);
|
|
|
4210fa |
+
|
|
|
4210fa |
+ EFI_IMAGE_SECTION_HEADER *RelocSection = NULL;
|
|
|
4210fa |
+
|
|
|
4210fa |
/*
|
|
|
4210fa |
* Copy the executable's sections to their desired offsets
|
|
|
4210fa |
*/
|
|
|
4210fa |
Section = context.FirstSection;
|
|
|
4210fa |
for (i = 0; i < context.NumberOfSections; i++, Section++) {
|
|
|
4210fa |
- if (Section->Characteristics & 0x02000000)
|
|
|
4210fa |
- /* section has EFI_IMAGE_SCN_MEM_DISCARDABLE attr set */
|
|
|
4210fa |
- continue;
|
|
|
4210fa |
-
|
|
|
4210fa |
size = Section->Misc.VirtualSize;
|
|
|
4210fa |
|
|
|
4210fa |
if (size > Section->SizeOfRawData)
|
|
|
4210fa |
@@ -1118,7 +1158,6 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
|
|
|
4210fa |
|
|
|
4210fa |
base = ImageAddress (buffer, context.ImageSize, Section->VirtualAddress);
|
|
|
4210fa |
end = ImageAddress (buffer, context.ImageSize, Section->VirtualAddress + size - 1);
|
|
|
4210fa |
-
|
|
|
4210fa |
if (!base || !end) {
|
|
|
4210fa |
perror(L"Invalid section size\n");
|
|
|
4210fa |
return EFI_UNSUPPORTED;
|
|
|
4210fa |
@@ -1130,6 +1169,30 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
|
|
|
4210fa |
return EFI_UNSUPPORTED;
|
|
|
4210fa |
}
|
|
|
4210fa |
|
|
|
4210fa |
+ /* We do want to process .reloc, but it's often marked
|
|
|
4210fa |
+ * discardable, so we don't want to memcpy it. */
|
|
|
4210fa |
+ if (CompareMem(Section->Name, ".reloc\0\0", 8) == 0) {
|
|
|
4210fa |
+ if (RelocSection) {
|
|
|
4210fa |
+ perror(L"Image has multiple relocation sections\n");
|
|
|
4210fa |
+ return EFI_UNSUPPORTED;
|
|
|
4210fa |
+ }
|
|
|
4210fa |
+ /* If it has nonzero sizes, and our bounds check
|
|
|
4210fa |
+ * made sense, and the VA and size match RelocDir's
|
|
|
4210fa |
+ * versions, then we believe in this section table. */
|
|
|
4210fa |
+ if (Section->SizeOfRawData &&
|
|
|
4210fa |
+ Section->Misc.VirtualSize &&
|
|
|
4210fa |
+ base && end &&
|
|
|
4210fa |
+ RelocBase == base &&
|
|
|
4210fa |
+ RelocBaseEnd == end) {
|
|
|
4210fa |
+ RelocSection = Section;
|
|
|
4210fa |
+ }
|
|
|
4210fa |
+ }
|
|
|
4210fa |
+
|
|
|
4210fa |
+ if (Section->Characteristics & 0x02000000) {
|
|
|
4210fa |
+ /* section has EFI_IMAGE_SCN_MEM_DISCARDABLE attr set */
|
|
|
4210fa |
+ continue;
|
|
|
4210fa |
+ }
|
|
|
4210fa |
+
|
|
|
4210fa |
if (Section->SizeOfRawData > 0)
|
|
|
4210fa |
CopyMem(base, data + Section->PointerToRawData, size);
|
|
|
4210fa |
|
|
|
4210fa |
@@ -1143,11 +1206,12 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
|
|
|
4210fa |
return EFI_UNSUPPORTED;
|
|
|
4210fa |
}
|
|
|
4210fa |
|
|
|
4210fa |
- if (context.RelocDir->Size) {
|
|
|
4210fa |
+ if (context.RelocDir->Size && RelocSection) {
|
|
|
4210fa |
/*
|
|
|
4210fa |
* Run the relocation fixups
|
|
|
4210fa |
*/
|
|
|
4210fa |
- efi_status = relocate_coff(&context, data, buffer);
|
|
|
4210fa |
+ efi_status = relocate_coff(&context, RelocSection, data,
|
|
|
4210fa |
+ buffer);
|
|
|
4210fa |
|
|
|
4210fa |
if (efi_status != EFI_SUCCESS) {
|
|
|
4210fa |
perror(L"Relocation failed: %r\n", efi_status);
|
|
|
4210fa |
--
|
|
|
4210fa |
1.9.3
|
|
|
4210fa |
|