arrfab / rpms / shim

Forked from rpms/shim 4 years ago
Clone

Blame SOURCES/0064-Actually-find-the-relocations-correctly-and-process-.patch

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