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

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