|
|
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 |
|