Blame SOURCES/0055-Actually-refer-to-the-base-relocation-table-of-our-l.patch

e97c83
From a7249a65aff174d2a51d6a7bf77dbbf58744a170 Mon Sep 17 00:00:00 2001
e97c83
From: Peter Jones <pjones@redhat.com>
e97c83
Date: Thu, 18 Sep 2014 18:34:38 -0400
e97c83
Subject: [PATCH 55/74] Actually refer to the base relocation table of our
e97c83
 loaded image.
e97c83
e97c83
Currently when we process base relocations, we get the correct Data
e97c83
Directory pointer from the headers (context->RelocDir), and that header
e97c83
has been copied into our pristine allocated image when we copied up to
e97c83
SizeOfHeaders.  But the data it points to has not been mirrored in to
e97c83
the new image, so it is whatever data AllocPool() gave us.
e97c83
e97c83
This patch changes relocate_coff() to refer to the base relocation table
e97c83
from the image we loaded from disk, but apply the fixups to the new
e97c83
copy.
e97c83
e97c83
I have no idea how x86_64 worked without this, but I can't make aarch64
e97c83
work without it.  I also don't know how Ard or Leif have seen aarch64
e97c83
work.  Maybe they haven't?  Leif indicated on irc that they may have
e97c83
only tested shim with simple "hello world" applications from gnu-efi;
e97c83
they are certainly much less complex than grub.efi, and are generated
e97c83
through a different linking process.
e97c83
e97c83
My only theory is that we're getting recycled data there pretty reliably
e97c83
that just makes us /not/ process any relocations, but since our
e97c83
ImageBase is 0, and I don't think we ever load grub with 0 as its base
e97c83
virtual address, that doesn't follow.  I'm open to any other ideas
e97c83
anybody has.
e97c83
e97c83
I do know that on x86_64 (and presumably aarch64 as well), we don't
e97c83
actually start seeing *symptoms* of this bug until the first chunk[0] of
e97c83
94c9a77f is applied[1].  Once that is applied, relocate_coff() starts
e97c83
seeing zero[2] for both RelocBase->VirtualAddress and
e97c83
RelocBase->SizeOfBlock, because RelocBase is a (generated, relative)
e97c83
pointer that only makes sense in the context of the original binary, not
e97c83
our partial copy.  Since RelocBase->SizeOfBlock is tested first,
e97c83
relocate_base() gives us "Reloc block size is invalid"[3] and returns
e97c83
EFI_UNSUPPORTED.  At that point shim exits with an error.
e97c83
e97c83
[0] The second chunk of 94c9a77f patch makes no difference on this
e97c83
    issue.
e97c83
[1] I don't see why at all.
e97c83
[2] Which could really be any value since it's AllocatePool() and not
e97c83
    AllocateZeroPool() results, but 0 is all I've observed; I think
e97c83
    AllocatePool() has simply never recycled any memory in my test
e97c83
    cases.
e97c83
[3] which is silent because perror() tries to avoid talking because that
e97c83
    has caused much crashing in the past; work needs to go in to 0.9 for
e97c83
    this.
e97c83
e97c83
Signed-off-by: Peter Jones <pjones@redhat.com>
e97c83
---
e97c83
 shim.c | 42 +++++++++++++++++++++---------------------
e97c83
 1 file changed, 21 insertions(+), 21 deletions(-)
e97c83
e97c83
diff --git a/shim.c b/shim.c
e97c83
index 1ec1e11..4b4d31a 100644
e97c83
--- a/shim.c
e97c83
+++ b/shim.c
e97c83
@@ -122,7 +122,7 @@ static void *ImageAddress (void *image, unsigned int size, unsigned int address)
e97c83
  * Perform the actual relocation
e97c83
  */
e97c83
 static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
e97c83
-				 void *data)
e97c83
+				 void *orig, void *data)
e97c83
 {
e97c83
 	EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
e97c83
 	UINT64 Adjust;
e97c83
@@ -132,7 +132,7 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
e97c83
 	UINT32 *Fixup32;
e97c83
 	UINT64 *Fixup64;
e97c83
 	int size = context->ImageSize;
e97c83
-	void *ImageEnd = (char *)data + size;
e97c83
+	void *ImageEnd = (char *)orig + size;
e97c83
 
e97c83
 #if __LP64__
e97c83
 	context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)data;
e97c83
@@ -140,16 +140,8 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
e97c83
 	context->PEHdr->Pe32.OptionalHeader.ImageBase = (UINT32)data;
e97c83
 #endif
e97c83
 
e97c83
-	if (context->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
e97c83
-		perror(L"Image has no relocation entry\n");
e97c83
-		return EFI_UNSUPPORTED;
e97c83
-	}
e97c83
-
e97c83
-	if (!context->RelocDir->Size)
e97c83
-		return EFI_SUCCESS;
e97c83
-
e97c83
-	RelocBase = ImageAddress(data, size, context->RelocDir->VirtualAddress);
e97c83
-	RelocBaseEnd = ImageAddress(data, size, context->RelocDir->VirtualAddress + context->RelocDir->Size - 1);
e97c83
+	RelocBase = ImageAddress(orig, size, context->RelocDir->VirtualAddress);
e97c83
+	RelocBaseEnd = ImageAddress(orig, size, context->RelocDir->VirtualAddress + context->RelocDir->Size - 1);
e97c83
 
e97c83
 	if (!RelocBase || !RelocBaseEnd) {
e97c83
 		perror(L"Reloc table overflows binary\n");
e97c83
@@ -170,7 +162,7 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
e97c83
 		}
e97c83
 
e97c83
 		RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
e97c83
-		if ((void *)RelocEnd < data || (void *)RelocEnd > ImageEnd) {
e97c83
+		if ((void *)RelocEnd < orig || (void *)RelocEnd > ImageEnd) {
e97c83
 			perror(L"Reloc entry overflows binary\n");
e97c83
 			return EFI_UNSUPPORTED;
e97c83
 		}
e97c83
@@ -1049,15 +1041,23 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
e97c83
 			ZeroMem (base + size, Section->Misc.VirtualSize - size);
e97c83
 	}
e97c83
 
e97c83
-	/*
e97c83
-	 * Run the relocation fixups
e97c83
-	 */
e97c83
-	efi_status = relocate_coff(&context, buffer);
e97c83
-
e97c83
-	if (efi_status != EFI_SUCCESS) {
e97c83
-		perror(L"Relocation failed: %r\n", efi_status);
e97c83
+	if (context.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
e97c83
+		perror(L"Image has no relocation entry\n");
e97c83
 		FreePool(buffer);
e97c83
-		return efi_status;
e97c83
+		return EFI_UNSUPPORTED;
e97c83
+	}
e97c83
+
e97c83
+	if (context.RelocDir->Size) {
e97c83
+		/*
e97c83
+		 * Run the relocation fixups
e97c83
+		 */
e97c83
+		efi_status = relocate_coff(&context, data, buffer);
e97c83
+
e97c83
+		if (efi_status != EFI_SUCCESS) {
e97c83
+			perror(L"Relocation failed: %r\n", efi_status);
e97c83
+			FreePool(buffer);
e97c83
+			return efi_status;
e97c83
+		}
e97c83
 	}
e97c83
 
e97c83
 	entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint);
e97c83
-- 
e97c83
1.9.3
e97c83