arrfab / rpms / shim

Forked from rpms/shim 4 years ago
Clone

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

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