Blame SOURCES/0056-Make-64-on-32-maybe-work-on-x86_64.patch

e97c83
From 750584c207757688cbab47f51a18a33c3e36fb8b Mon Sep 17 00:00:00 2001
e97c83
From: Peter Jones <pjones@redhat.com>
e97c83
Date: Fri, 19 Sep 2014 11:37:35 -0400
e97c83
Subject: [PATCH 56/74] Make 64-on-32 maybe work on x86_64.
e97c83
e97c83
This is mostly based on a patch (https://github.com/mjg59/shim/issues/30)
e97c83
from https://github.com/TBOpen , which refactors our __LP64__
e97c83
tests to be tests of the header magic instead.  I've simplified things
e97c83
by using what we've pre-loaded into "context" and making some helper
e97c83
functions so the conditionals in most of the code say what they do,
e97c83
instead of how they work.
e97c83
e97c83
Note that we're only allowing that from in_protocol's loader - that is,
e97c83
we'll let 64-bit grub load a 32-bit kernel or 32-bit grub load a 64-bit
e97c83
kernel, but 32-bit shim isn't loading a 64-bit grub.
e97c83
e97c83
Signed-off-by: Peter Jones <pjones@redhat.com>
e97c83
---
e97c83
 shim.c | 220 ++++++++++++++++++++++++++++++++++++++++++++---------------------
e97c83
 1 file changed, 148 insertions(+), 72 deletions(-)
e97c83
e97c83
diff --git a/shim.c b/shim.c
e97c83
index 4b4d31a..c1b5c17 100644
e97c83
--- a/shim.c
e97c83
+++ b/shim.c
e97c83
@@ -118,6 +118,106 @@ static void *ImageAddress (void *image, unsigned int size, unsigned int address)
e97c83
 	return image + address;
e97c83
 }
e97c83
 
e97c83
+/* here's a chart:
e97c83
+ *		i686	x86_64	aarch64
e97c83
+ *  64-on-64:	nyet	yes	yes
e97c83
+ *  64-on-32:	nyet	yes	nyet
e97c83
+ *  32-on-32:	yes	yes	no
e97c83
+ */
e97c83
+static int
e97c83
+allow_64_bit(void)
e97c83
+{
e97c83
+#if defined(__x86_64__) || defined(__aarch64__)
e97c83
+	return 1;
e97c83
+#elif defined(__i386__) || defined(__i686__)
e97c83
+	/* Right now blindly assuming the kernel will correctly detect this
e97c83
+	 * and /halt the system/ if you're not really on a 64-bit cpu */
e97c83
+	if (in_protocol)
e97c83
+		return 1;
e97c83
+	return 0;
e97c83
+#else /* assuming everything else is 32-bit... */
e97c83
+	return 0;
e97c83
+#endif
e97c83
+}
e97c83
+
e97c83
+static int
e97c83
+allow_32_bit(void)
e97c83
+{
e97c83
+#if defined(__x86_64__)
e97c83
+#if defined(ALLOW_32BIT_KERNEL_ON_X64)
e97c83
+	if (in_protocol)
e97c83
+		return 1;
e97c83
+	return 0;
e97c83
+#else
e97c83
+	return 0;
e97c83
+#endif
e97c83
+#elif defined(__i386__) || defined(__i686__)
e97c83
+	return 1;
e97c83
+#elif defined(__arch64__)
e97c83
+	return 0;
e97c83
+#else /* assuming everything else is 32-bit... */
e97c83
+	return 1;
e97c83
+#endif
e97c83
+}
e97c83
+
e97c83
+static int
e97c83
+image_is_64_bit(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
e97c83
+{
e97c83
+	/* .Magic is the same offset in all cases */
e97c83
+	if (PEHdr->Pe32Plus.OptionalHeader.Magic
e97c83
+			== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC)
e97c83
+		return 1;
e97c83
+	return 0;
e97c83
+}
e97c83
+
e97c83
+static const UINT16 machine_type =
e97c83
+#if defined(__x86_64__)
e97c83
+	IMAGE_FILE_MACHINE_X64;
e97c83
+#elif defined(__aarch64__)
e97c83
+	IMAGE_FILE_MACHINE_ARM64;
e97c83
+#elif defined(__arm__)
e97c83
+	IMAGE_FILE_MACHINE_ARMTHUMB_MIXED;
e97c83
+#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
e97c83
+	IMAGE_FILE_MACHINE_I386;
e97c83
+#elif defined(__ia64__)
e97c83
+	IMAGE_FILE_MACHINE_IA64;
e97c83
+#else
e97c83
+#error this architecture is not supported by shim
e97c83
+#endif
e97c83
+
e97c83
+static int
e97c83
+image_is_loadable(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
e97c83
+{
e97c83
+	/* If the machine type doesn't match the binary, bail, unless
e97c83
+	 * we're in an allowed 64-on-32 scenario */
e97c83
+	if (PEHdr->Pe32.FileHeader.Machine != machine_type) {
e97c83
+		if (!(machine_type == IMAGE_FILE_MACHINE_I386 &&
e97c83
+		      PEHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_X64 &&
e97c83
+		      allow_64_bit())) {
e97c83
+			return 0;
e97c83
+		}
e97c83
+	}
e97c83
+
e97c83
+	/* If it's not a header type we recognize at all, bail */
e97c83
+	switch (PEHdr->Pe32Plus.OptionalHeader.Magic) {
e97c83
+	case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
e97c83
+	case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
e97c83
+		break;
e97c83
+	default:
e97c83
+		return 0;
e97c83
+	}
e97c83
+
e97c83
+	/* and now just check for general 64-vs-32 compatibility */
e97c83
+	if (image_is_64_bit(PEHdr)) {
e97c83
+		if (allow_64_bit())
e97c83
+			return 1;
e97c83
+	} else {
e97c83
+		if (allow_32_bit())
e97c83
+			return 1;
e97c83
+	}
e97c83
+	return 0;
e97c83
+}
e97c83
+
e97c83
 /*
e97c83
  * Perform the actual relocation
e97c83
  */
e97c83
@@ -134,11 +234,10 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
e97c83
 	int size = context->ImageSize;
e97c83
 	void *ImageEnd = (char *)orig + size;
e97c83
 
e97c83
-#if __LP64__
e97c83
-	context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)data;
e97c83
-#else
e97c83
-	context->PEHdr->Pe32.OptionalHeader.ImageBase = (UINT32)data;
e97c83
-#endif
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
@@ -157,7 +256,7 @@ 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 is invalid\n");
e97c83
+			perror(L"Reloc block size %d is invalid\n", RelocBase->SizeOfBlock);
e97c83
 			return EFI_UNSUPPORTED;
e97c83
 		}
e97c83
 
e97c83
@@ -498,7 +597,7 @@ static BOOLEAN secure_mode (void)
e97c83
  * Calculate the SHA1 and SHA256 hashes of a binary
e97c83
  */
e97c83
 
e97c83
-static EFI_STATUS generate_hash (char *data, int datasize_in,
e97c83
+static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
e97c83
 				 PE_COFF_LOADER_IMAGE_CONTEXT *context,
e97c83
 				 UINT8 *sha256hash, UINT8 *sha1hash)
e97c83
 
e97c83
@@ -572,15 +671,14 @@ static EFI_STATUS generate_hash (char *data, int datasize_in,
e97c83
 	}
e97c83
 
e97c83
 	/* Hash end of certificate table to end of image header */
e97c83
-#if __LP64__
e97c83
-	hashbase = (char *) &context->PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
e97c83
-	hashsize = context->PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders -
e97c83
-		(int) ((char *) (&context->PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - data);
e97c83
-#else
e97c83
-	hashbase = (char *) &context->PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
e97c83
-	hashsize = context->PEHdr->Pe32.OptionalHeader.SizeOfHeaders -
e97c83
-		(int) ((char *) (&context->PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - data);
e97c83
-#endif
e97c83
+	EFI_IMAGE_DATA_DIRECTORY *dd = context->SecDir + 1;
e97c83
+	hashbase = (char *)dd;
e97c83
+	hashsize = context->SizeOfHeaders - (unsigned long)((char *)dd - data);
e97c83
+	if (hashsize > datasize_in) {
e97c83
+		perror(L"Data Directory size %d is invalid\n", hashsize);
e97c83
+		status = EFI_INVALID_PARAMETER;
e97c83
+		goto done;
e97c83
+	}
e97c83
 
e97c83
 	if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
e97c83
 	    !(Sha1Update(sha1ctx, hashbase, hashsize))) {
e97c83
@@ -590,11 +688,7 @@ static EFI_STATUS generate_hash (char *data, int datasize_in,
e97c83
 	}
e97c83
 
e97c83
 	/* Sort sections */
e97c83
-#if __LP64__
e97c83
-	SumOfBytesHashed = context->PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
e97c83
-#else
e97c83
-	SumOfBytesHashed = context->PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
e97c83
-#endif
e97c83
+	SumOfBytesHashed = context->SizeOfHeaders;
e97c83
 
e97c83
 	/* Validate section locations and sizes */
e97c83
 	for (index = 0, SumOfSectionBytes = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) {
e97c83
@@ -682,14 +776,7 @@ static EFI_STATUS generate_hash (char *data, int datasize_in,
e97c83
 	/* Hash all remaining data */
e97c83
 	if (datasize > SumOfBytesHashed) {
e97c83
 		hashbase = data + SumOfBytesHashed;
e97c83
-		hashsize = (unsigned int)(
e97c83
-			datasize -
e97c83
-#if __LP64__
e97c83
-			context->PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
e97c83
-#else
e97c83
-			context->PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
e97c83
-#endif
e97c83
-			SumOfBytesHashed);
e97c83
+		hashsize = datasize - context->SecDir->Size - SumOfBytesHashed;
e97c83
 
e97c83
 		if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
e97c83
 		    !(Sha1Update(sha1ctx, hashbase, hashsize))) {
e97c83
@@ -843,24 +930,31 @@ static EFI_STATUS read_header(void *data, unsigned int datasize,
e97c83
 	EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
e97c83
 	unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
e97c83
 
e97c83
-	if (datasize < sizeof(EFI_IMAGE_DOS_HEADER)) {
e97c83
+	if (datasize < sizeof (PEHdr->Pe32)) {
e97c83
 		perror(L"Invalid image\n");
e97c83
 		return EFI_UNSUPPORTED;
e97c83
 	}
e97c83
 
e97c83
 	if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
e97c83
 		PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew);
e97c83
-#if __LP64__
e97c83
-	context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
e97c83
-	context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
e97c83
-	context->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
e97c83
-	OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64);
e97c83
-#else
e97c83
-	context->NumberOfRvaAndSizes = PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes;
e97c83
-	context->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
e97c83
-	context->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage;
e97c83
-	OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32);
e97c83
-#endif
e97c83
+
e97c83
+	if (!image_is_loadable(PEHdr)) {
e97c83
+		perror(L"Platform does not support this image\n");
e97c83
+		return EFI_UNSUPPORTED;
e97c83
+	}
e97c83
+
e97c83
+	if (image_is_64_bit(PEHdr)) {
e97c83
+		context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
e97c83
+		context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
e97c83
+		context->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
e97c83
+		OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64);
e97c83
+	} else {
e97c83
+		context->NumberOfRvaAndSizes = PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes;
e97c83
+		context->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
e97c83
+		context->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage;
e97c83
+		OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32);
e97c83
+	}
e97c83
+
e97c83
 	context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
e97c83
 
e97c83
 	if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < context->NumberOfRvaAndSizes) {
e97c83
@@ -908,17 +1002,19 @@ static EFI_STATUS read_header(void *data, unsigned int datasize,
e97c83
 	}
e97c83
 
e97c83
 	context->PEHdr = PEHdr;
e97c83
-#if __LP64__
e97c83
-	context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
e97c83
-	context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
e97c83
-	context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
e97c83
-	context->SecDir = (EFI_IMAGE_DATA_DIRECTORY *) &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
e97c83
-#else
e97c83
-	context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
e97c83
-	context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
e97c83
-	context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
e97c83
-	context->SecDir = (EFI_IMAGE_DATA_DIRECTORY *) &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
e97c83
-#endif
e97c83
+
e97c83
+	if (image_is_64_bit(PEHdr)) {
e97c83
+		context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
e97c83
+		context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
e97c83
+		context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
e97c83
+		context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
e97c83
+	} else {
e97c83
+		context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
e97c83
+		context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
e97c83
+		context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
e97c83
+		context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
e97c83
+	}
e97c83
+
e97c83
 	context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER));
e97c83
 
e97c83
 	if (context->ImageSize < context->SizeOfHeaders) {
e97c83
@@ -939,21 +1035,6 @@ static EFI_STATUS read_header(void *data, unsigned int datasize,
e97c83
 	return EFI_SUCCESS;
e97c83
 }
e97c83
 
e97c83
-static const UINT16 machine_type =
e97c83
-#if defined(__x86_64__)
e97c83
-	IMAGE_FILE_MACHINE_X64;
e97c83
-#elif defined(__aarch64__)
e97c83
-	IMAGE_FILE_MACHINE_ARM64;
e97c83
-#elif defined(__arm__)
e97c83
-	IMAGE_FILE_MACHINE_ARMTHUMB_MIXED;
e97c83
-#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
e97c83
-	IMAGE_FILE_MACHINE_I386;
e97c83
-#elif defined(__ia64__)
e97c83
-	IMAGE_FILE_MACHINE_IA64;
e97c83
-#else
e97c83
-#error this architecture is not supported by shim
e97c83
-#endif
e97c83
-
e97c83
 /*
e97c83
  * Once the image has been loaded it needs to be validated and relocated
e97c83
  */
e97c83
@@ -977,11 +1058,6 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
e97c83
 		return efi_status;
e97c83
 	}
e97c83
 
e97c83
-	if (context.PEHdr->Pe32.FileHeader.Machine != machine_type) {
e97c83
-		perror(L"Image is for a different architecture\n");
e97c83
-		return EFI_UNSUPPORTED;
e97c83
-	}
e97c83
-
e97c83
 	/*
e97c83
 	 * We only need to verify the binary if we're in secure mode
e97c83
 	 */
e97c83
-- 
e97c83
1.9.3
e97c83