summaryrefslogtreecommitdiff
path: root/shim.c
diff options
context:
space:
mode:
Diffstat (limited to 'shim.c')
-rw-r--r--shim.c643
1 files changed, 357 insertions, 286 deletions
diff --git a/shim.c b/shim.c
index b99b81f7..f6311ada 100644
--- a/shim.c
+++ b/shim.c
@@ -1,234 +1,174 @@
+/*
+ * shim - trivial UEFI first-stage bootloader
+ *
+ * Copyright 2012 Red Hat, Inc <mjg@redhat.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Significant portions of this code are derived from Tianocore
+ * (http://tianocore.sf.net) and are Copyright 2009-2012 Intel
+ * Corporation.
+ */
+
#include <efi.h>
#include <efilib.h>
#include <Library/BaseCryptLib.h>
#include "PeImage.h"
+#define SECOND_STAGE L"grub.efi"
+
static EFI_SYSTEM_TABLE *systab;
static EFI_STATUS (EFIAPI *entry_point) (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
+/*
+ * The vendor certificate used for validating the second stage loader
+ */
+
#include "cert.h"
-static EFI_STATUS load_grub (EFI_HANDLE image_handle, void **grubdata,
- int *grubsize)
+/*
+ * Perform basic bounds checking of the intra-image pointers
+ */
+static void *ImageAddress (void *image, int size, unsigned int address)
{
- EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL;
- EFI_GUID simple_file_system_protocol = SIMPLE_FILE_SYSTEM_PROTOCOL;
- EFI_GUID file_info_id = EFI_FILE_INFO_ID;
- EFI_STATUS efi_status;
- EFI_LOADED_IMAGE *li;
- EFI_FILE_IO_INTERFACE *drive;
- EFI_FILE_INFO *fileinfo = NULL;
- EFI_FILE *root, *grub;
- FILEPATH_DEVICE_PATH *FilePath;
- CHAR16 *PathName;
- CHAR16 *Dir;
- EFI_HANDLE device;
- unsigned int buffersize = sizeof(EFI_FILE_INFO);
- int i;
-
- efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
- &loaded_image_protocol, &li);
-
- if (efi_status != EFI_SUCCESS)
- return efi_status;
-
- if (DevicePathType(li->FilePath) != MEDIA_DEVICE_PATH ||
- DevicePathSubType(li->FilePath) != MEDIA_FILEPATH_DP)
- return EFI_NOT_FOUND;
-
- device = li->DeviceHandle;
-
- efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device,
- &simple_file_system_protocol, &drive);
-
- if (efi_status != EFI_SUCCESS) {
- Print(L"Failed to find fs\n");
- return efi_status;
- }
-
- efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
-
- if (efi_status != EFI_SUCCESS) {
- Print(L"Failed to open fs\n");
- return efi_status;
- }
-
- FilePath = (FILEPATH_DEVICE_PATH *)li->FilePath;
+ if (address > size)
+ return NULL;
- efi_status = uefi_call_wrapper(root->Open, 5, root, &grub,
- FilePath->PathName, EFI_FILE_MODE_READ,
- 0);
+ return image + address;
+}
- if (efi_status != EFI_SUCCESS) {
- Print(L"Failed to open %s - %lx\n", FilePath->PathName,
- efi_status);
- return efi_status;
- }
+/*
+ * Perform the actual relocation
+ */
+static EFI_STATUS relocate_grub (PE_COFF_LOADER_IMAGE_CONTEXT *context,
+ void *grubdata)
+{
+ EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
+ UINT64 Adjust;
+ UINT16 *Reloc, *RelocEnd;
+ char *Fixup, *FixupBase, *FixupData = NULL;
+ UINT16 *Fixup16;
+ UINT32 *Fixup32;
+ UINT64 *Fixup64;
+ int size = context->ImageSize;
+ void *ImageEnd = (char *)grubdata + size;
- fileinfo = AllocatePool(buffersize);
+ context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)grubdata;
- if (!fileinfo) {
- Print(L"Unable to allocate info buffer\n");
- return EFI_OUT_OF_RESOURCES;
+ if (context->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
+ Print(L"Image has no relocation entry\n");
+ return EFI_UNSUPPORTED;
}
- efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub, &file_info_id,
- &buffersize, fileinfo);
+ RelocBase = ImageAddress(grubdata, size, context->RelocDir->VirtualAddress);
+ RelocBaseEnd = ImageAddress(grubdata, size, context->RelocDir->VirtualAddress + context->RelocDir->Size - 1);
- if (efi_status == EFI_BUFFER_TOO_SMALL) {
- fileinfo = AllocatePool(buffersize);
- if (!fileinfo) {
- Print(L"Unable to allocate info buffer\n");
- return EFI_OUT_OF_RESOURCES;
- }
- efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub,
- &file_info_id, &buffersize,
- fileinfo);
+ if (!RelocBase || !RelocBaseEnd) {
+ Print(L"Reloc table overflows binary\n");
+ return EFI_UNSUPPORTED;
}
- if (efi_status != EFI_SUCCESS) {
- Print(L"Unable to get file info\n");
- return efi_status;
- }
+ Adjust = (UINT64)grubdata - context->ImageAddress;
- efi_status = uefi_call_wrapper(grub->Close, 1, grub);
+ while (RelocBase < RelocBaseEnd) {
+ Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
+ RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
- if (fileinfo->Attribute & EFI_FILE_DIRECTORY) {
- Dir = FilePath->PathName;
- } else {
- for (i=StrLen(FilePath->PathName); i > 0; i--) {
- if (FilePath->PathName[i] == '\\')
- break;
+ if ((void *)RelocEnd < grubdata || (void *)RelocEnd > ImageEnd) {
+ Print(L"Reloc entry overflows binary\n");
+ return EFI_UNSUPPORTED;
}
- if (i) {
- Dir = AllocatePool(i * 2);
- CopyMem(Dir, FilePath->PathName, i * 2);
- Dir[i] = '\0';
- } else {
- Dir = AllocatePool(2);
- Dir[0] = '\0';
+ FixupBase = ImageAddress(grubdata, size, RelocBase->VirtualAddress);
+ if (!FixupBase) {
+ Print(L"Invalid fixupbase\n");
+ return EFI_UNSUPPORTED;
}
- }
- PathName = AllocatePool(StrLen(Dir) + StrLen(L"grub.efi"));
-
- if (!PathName)
- return EFI_LOAD_ERROR;
-
- StrCpy(PathName, Dir);
+ while (Reloc < RelocEnd) {
+ Fixup = FixupBase + (*Reloc & 0xFFF);
+ switch ((*Reloc) >> 12) {
+ case EFI_IMAGE_REL_BASED_ABSOLUTE:
+ break;
- StrCat(PathName, L"grub.efi");
+ case EFI_IMAGE_REL_BASED_HIGH:
+ Fixup16 = (UINT16 *) Fixup;
+ *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
+ if (FixupData != NULL) {
+ *(UINT16 *) FixupData = *Fixup16;
+ FixupData = FixupData + sizeof (UINT16);
+ }
+ break;
- efi_status = uefi_call_wrapper(root->Open, 5, root, &grub, PathName,
- EFI_FILE_MODE_READ, 0);
+ case EFI_IMAGE_REL_BASED_LOW:
+ Fixup16 = (UINT16 *) Fixup;
+ *Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);
+ if (FixupData != NULL) {
+ *(UINT16 *) FixupData = *Fixup16;
+ FixupData = FixupData + sizeof (UINT16);
+ }
+ break;
- if (efi_status != EFI_SUCCESS) {
- Print(L"Failed to open %s - %lx\n", PathName, efi_status);
- return efi_status;
- }
+ case EFI_IMAGE_REL_BASED_HIGHLOW:
+ Fixup32 = (UINT32 *) Fixup;
+ *Fixup32 = *Fixup32 + (UINT32) Adjust;
+ if (FixupData != NULL) {
+ FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
+ *(UINT32 *)FixupData = *Fixup32;
+ FixupData = FixupData + sizeof (UINT32);
+ }
+ break;
- efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub, &file_info_id,
- &buffersize, fileinfo);
+ case EFI_IMAGE_REL_BASED_DIR64:
+ Fixup64 = (UINT64 *) Fixup;
+ *Fixup64 = *Fixup64 + (UINT64) Adjust;
+ if (FixupData != NULL) {
+ FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
+ *(UINT64 *)(FixupData) = *Fixup64;
+ FixupData = FixupData + sizeof(UINT64);
+ }
+ break;
- if (efi_status == EFI_BUFFER_TOO_SMALL) {
- fileinfo = AllocatePool(buffersize);
- if (!fileinfo) {
- Print(L"Unable to allocate info buffer\n");
- return EFI_OUT_OF_RESOURCES;
+ default:
+ Print(L"Unknown relocation\n");
+ return EFI_UNSUPPORTED;
+ }
+ Reloc += 1;
}
- efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub,
- &file_info_id, &buffersize,
- fileinfo);
- }
-
- if (efi_status != EFI_SUCCESS) {
- Print(L"Unable to get file info\n");
- return efi_status;
- }
-
- buffersize = fileinfo->FileSize;
- *grubdata = AllocatePool(buffersize);
-
- if (!*grubdata) {
- Print(L"Unable to allocate file buffer\n");
- return EFI_OUT_OF_RESOURCES;
- }
-
- efi_status = uefi_call_wrapper(grub->Read, 3, grub, &buffersize,
- *grubdata);
-
- if (efi_status != EFI_SUCCESS) {
- Print(L"Unexpected return from initial read: %x, buffersize %x\n", efi_status, buffersize);
- return efi_status;
- }
-
- if (efi_status != EFI_SUCCESS) {
- Print(L"Unable to read grub\n");
- return efi_status;
- }
-
- *grubsize = buffersize;
-
- return EFI_SUCCESS;
-}
-
-static EFI_STATUS read_header(void *grubdata, PE_COFF_LOADER_IMAGE_CONTEXT *context)
-{
- EFI_IMAGE_DOS_HEADER *DosHdr = grubdata;
- EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = grubdata;
-
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
- PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)grubdata + DosHdr->e_lfanew);
-
- if (PEHdr->Te.Signature != EFI_IMAGE_NT_SIGNATURE) {
- Print(L"Unsupported image type\n");
- return EFI_UNSUPPORTED;
- }
-
- if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) {
- Print(L"Unsupported image - Relocations have been stripped\n");
- return EFI_UNSUPPORTED;
- }
-
- if (PEHdr->Pe32.OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- Print(L"Only 64-bit images supported\n");
- return EFI_UNSUPPORTED;
- }
-
- context->PEHdr = PEHdr;
- context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
- context->ImageSize = (UINT64)PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
- context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
- context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
- context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
- context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
- context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
- context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER));
- context->SecDir = (EFI_IMAGE_DATA_DIRECTORY *) &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
-
- if (context->SecDir->VirtualAddress >= context->ImageSize) {
- Print(L"Malformed security header\n");
- return EFI_INVALID_PARAMETER;
- }
-
- if (context->SecDir->Size == 0) {
- Print(L"Empty security header\n");
- return EFI_INVALID_PARAMETER;
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
}
return EFI_SUCCESS;
}
-static void *ImageAddress (void *image, int size, unsigned int address)
-{
- if (address > size)
- return NULL;
-
- return image + address;
-}
-
-static EFI_STATUS verify_grub (PE_COFF_LOADER_IMAGE_CONTEXT *context, char *grubdata, int grubsize)
+/*
+ * Check that the signature is valid and matches the binary
+ */
+static EFI_STATUS verify_grub (PE_COFF_LOADER_IMAGE_CONTEXT *context,
+ char *grubdata, int grubsize)
{
unsigned int size = grubsize;
unsigned int ctxsize;
@@ -237,7 +177,7 @@ static EFI_STATUS verify_grub (PE_COFF_LOADER_IMAGE_CONTEXT *context, char *grub
EFI_STATUS status = EFI_ACCESS_DENIED;
char *hashbase;
unsigned int hashsize;
- WIN_CERTIFICATE_EFI_PKCS *cer;
+ WIN_CERTIFICATE_EFI_PKCS *cert;
unsigned int SumOfBytesHashed, SumOfSectionBytes;
unsigned int index, pos;
EFI_IMAGE_SECTION_HEADER *Section;
@@ -246,13 +186,18 @@ static EFI_STATUS verify_grub (PE_COFF_LOADER_IMAGE_CONTEXT *context, char *grub
cert = ImageAddress (grubdata, size, context->SecDir->VirtualAddress);
- if (cer->Hdr.wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
+ if (!cert) {
+ Print(L"Certificate located outside the image\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (cert->Hdr.wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
Print(L"Unsupported certificate type %x\n",
cert->Hdr.wCertificateType);
return EFI_UNSUPPORTED;
}
- /* Check which kind of hash */
+ /* FIXME: Check which kind of hash */
ctxsize = Sha256GetContextSize();
ctx = AllocatePool(ctxsize);
@@ -300,7 +245,7 @@ static EFI_STATUS verify_grub (PE_COFF_LOADER_IMAGE_CONTEXT *context, char *grub
goto done;
}
- /* Sort sections and hash SizeOfRawData of each section */
+ /* Sort sections */
SumOfBytesHashed = context->PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
Section = (EFI_IMAGE_SECTION_HEADER *) (
@@ -348,6 +293,11 @@ static EFI_STATUS verify_grub (PE_COFF_LOADER_IMAGE_CONTEXT *context, char *grub
hashbase = ImageAddress(grubdata, size, Section->PointerToRawData);
hashsize = (unsigned int) Section->SizeOfRawData;
+ if (!hashbase) {
+ Print(L"Malformed section header\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
if (!(Sha256Update(ctx, hashbase, hashsize))) {
Print(L"Unable to generate hash\n");
status = EFI_OUT_OF_RESOURCES;
@@ -377,10 +327,10 @@ static EFI_STATUS verify_grub (PE_COFF_LOADER_IMAGE_CONTEXT *context, char *grub
goto done;
}
- if (!AuthenticodeVerify(WinCertificate->CertData,
- context->SecDir->Size - sizeof(WinCertificate->Hdr),
- cert, sizeof(cert), hash,
- SHA256_DIGEST_SIZE)) {
+ if (!AuthenticodeVerify(cert->CertData,
+ context->SecDir->Size - sizeof(cert->Hdr),
+ vendor_cert, sizeof(cert), hash,
+ SHA256_DIGEST_SIZE)) {
Print(L"Invalid signature\n");
status = EFI_ACCESS_DENIED;
} else {
@@ -394,107 +344,60 @@ done:
return status;
}
-static EFI_STATUS relocate_grub (PE_COFF_LOADER_IMAGE_CONTEXT *context, void *grubdata)
+/*
+ * Read the binary header and grab appropriate information from it
+ */
+static EFI_STATUS read_header(void *grubdata,
+ PE_COFF_LOADER_IMAGE_CONTEXT *context)
{
- EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
- UINT64 Adjust;
- UINT16 *Reloc, *RelocEnd;
- char *Fixup, *FixupBase, *FixupData = NULL;
- UINT16 *Fixup16;
- UINT32 *Fixup32;
- UINT64 *Fixup64;
- int size = context->ImageSize;
- void *ImageEnd = (char *)grubdata + size;
+ EFI_IMAGE_DOS_HEADER *DosHdr = grubdata;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = grubdata;
- context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)grubdata;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
+ PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)grubdata + DosHdr->e_lfanew);
- if (context->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
- Print(L"Image has no relocation entry\n");
+ if (PEHdr->Te.Signature != EFI_IMAGE_NT_SIGNATURE) {
+ Print(L"Unsupported image type\n");
return EFI_UNSUPPORTED;
}
- RelocBase = ImageAddress(grubdata, size, context->RelocDir->VirtualAddress);
- RelocBaseEnd = ImageAddress(grubdata, size, context->RelocDir->VirtualAddress + context->RelocDir->Size - 1);
-
- if (!RelocBase || !RelocBaseEnd) {
- Print(L"Reloc table overflows binary\n");
+ if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) {
+ Print(L"Unsupported image - Relocations have been stripped\n");
return EFI_UNSUPPORTED;
}
- Adjust = (UINT64)grubdata - context->ImageAddress;
-
- while (RelocBase < RelocBaseEnd) {
- Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
- RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
-
- if ((void *)RelocEnd < grubdata || (void *)RelocEnd > ImageEnd) {
- Print(L"Reloc entry overflows binary\n");
- return EFI_UNSUPPORTED;
- }
-
- FixupBase = ImageAddress(grubdata, size, RelocBase->VirtualAddress);
- if (!FixupBase) {
- Print(L"Invalid fixupbase\n");
- return EFI_UNSUPPORTED;
- }
-
- while (Reloc < RelocEnd) {
- Fixup = FixupBase + (*Reloc & 0xFFF);
- switch ((*Reloc) >> 12) {
- case EFI_IMAGE_REL_BASED_ABSOLUTE:
- break;
-
- case EFI_IMAGE_REL_BASED_HIGH:
- Fixup16 = (UINT16 *) Fixup;
- *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
- if (FixupData != NULL) {
- *(UINT16 *) FixupData = *Fixup16;
- FixupData = FixupData + sizeof (UINT16);
- }
- break;
-
- case EFI_IMAGE_REL_BASED_LOW:
- Fixup16 = (UINT16 *) Fixup;
- *Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);
- if (FixupData != NULL) {
- *(UINT16 *) FixupData = *Fixup16;
- FixupData = FixupData + sizeof (UINT16);
- }
- break;
+ if (PEHdr->Pe32.OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ Print(L"Only 64-bit images supported\n");
+ return EFI_UNSUPPORTED;
+ }
- case EFI_IMAGE_REL_BASED_HIGHLOW:
- Fixup32 = (UINT32 *) Fixup;
- *Fixup32 = *Fixup32 + (UINT32) Adjust;
- if (FixupData != NULL) {
- FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
- *(UINT32 *)FixupData = *Fixup32;
- FixupData = FixupData + sizeof (UINT32);
- }
- break;
+ context->PEHdr = PEHdr;
+ context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
+ context->ImageSize = (UINT64)PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
+ context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
+ context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
+ context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
+ context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
+ context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER));
+ context->SecDir = (EFI_IMAGE_DATA_DIRECTORY *) &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
- case EFI_IMAGE_REL_BASED_DIR64:
- Fixup64 = (UINT64 *) Fixup;
- *Fixup64 = *Fixup64 + (UINT64) Adjust;
- if (FixupData != NULL) {
- FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
- *(UINT64 *)(FixupData) = *Fixup64;
- FixupData = FixupData + sizeof(UINT64);
- }
- break;
+ if (context->SecDir->VirtualAddress >= context->ImageSize) {
+ Print(L"Malformed security header\n");
+ return EFI_INVALID_PARAMETER;
+ }
- default:
- Print(L"Unknown relocation\n");
- return EFI_UNSUPPORTED;
- }
- Reloc += 1;
- }
- RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
+ if (context->SecDir->Size == 0) {
+ Print(L"Empty security header\n");
+ return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
-
}
+/*
+ * Once the image has been loaded it needs to be validated and relocated
+ */
static EFI_STATUS handle_grub (void *grubdata, int grubsize)
{
EFI_STATUS efi_status;
@@ -566,6 +469,174 @@ static EFI_STATUS handle_grub (void *grubdata, int grubsize)
return EFI_SUCCESS;
}
+/*
+ * Locate the second stage bootloader and read it into a buffer
+ */
+static EFI_STATUS load_grub (EFI_HANDLE image_handle, void **grubdata,
+ int *grubsize)
+{
+ EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL;
+ EFI_GUID simple_file_system_protocol = SIMPLE_FILE_SYSTEM_PROTOCOL;
+ EFI_GUID file_info_id = EFI_FILE_INFO_ID;
+ EFI_STATUS efi_status;
+ EFI_LOADED_IMAGE *li;
+ EFI_FILE_IO_INTERFACE *drive;
+ EFI_FILE_INFO *fileinfo = NULL;
+ EFI_FILE *root, *grub;
+ FILEPATH_DEVICE_PATH *FilePath;
+ CHAR16 *PathName;
+ CHAR16 *Dir;
+ EFI_HANDLE device;
+ unsigned int buffersize = sizeof(EFI_FILE_INFO);
+ int i;
+
+ efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
+ &loaded_image_protocol, &li);
+
+ if (efi_status != EFI_SUCCESS)
+ return efi_status;
+
+ if (DevicePathType(li->FilePath) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType(li->FilePath) != MEDIA_FILEPATH_DP)
+ return EFI_NOT_FOUND;
+
+ device = li->DeviceHandle;
+
+ efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device,
+ &simple_file_system_protocol, &drive);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to find fs\n");
+ return efi_status;
+ }
+
+ efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to open fs\n");
+ return efi_status;
+ }
+
+ FilePath = (FILEPATH_DEVICE_PATH *)li->FilePath;
+
+ efi_status = uefi_call_wrapper(root->Open, 5, root, &grub,
+ FilePath->PathName, EFI_FILE_MODE_READ,
+ 0);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to open %s - %lx\n", FilePath->PathName,
+ efi_status);
+ return efi_status;
+ }
+
+ fileinfo = AllocatePool(buffersize);
+
+ if (!fileinfo) {
+ Print(L"Unable to allocate info buffer\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub, &file_info_id,
+ &buffersize, fileinfo);
+
+ if (efi_status == EFI_BUFFER_TOO_SMALL) {
+ fileinfo = AllocatePool(buffersize);
+ if (!fileinfo) {
+ Print(L"Unable to allocate info buffer\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub,
+ &file_info_id, &buffersize,
+ fileinfo);
+ }
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Unable to get file info\n");
+ return efi_status;
+ }
+
+ efi_status = uefi_call_wrapper(grub->Close, 1, grub);
+
+ if (fileinfo->Attribute & EFI_FILE_DIRECTORY) {
+ Dir = FilePath->PathName;
+ } else {
+ for (i=StrLen(FilePath->PathName); i > 0; i--) {
+ if (FilePath->PathName[i] == '\\')
+ break;
+ }
+
+ if (i) {
+ Dir = AllocatePool(i * 2);
+ CopyMem(Dir, FilePath->PathName, i * 2);
+ Dir[i] = '\0';
+ } else {
+ Dir = AllocatePool(2);
+ Dir[0] = '\0';
+ }
+ }
+
+ PathName = AllocatePool(StrLen(Dir) + StrLen(SECOND_STAGE));
+
+ if (!PathName)
+ return EFI_LOAD_ERROR;
+
+ StrCpy(PathName, Dir);
+
+ StrCat(PathName, SECOND_STAGE);
+
+ efi_status = uefi_call_wrapper(root->Open, 5, root, &grub, PathName,
+ EFI_FILE_MODE_READ, 0);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to open %s - %lx\n", PathName, efi_status);
+ return efi_status;
+ }
+
+ efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub, &file_info_id,
+ &buffersize, fileinfo);
+
+ if (efi_status == EFI_BUFFER_TOO_SMALL) {
+ fileinfo = AllocatePool(buffersize);
+ if (!fileinfo) {
+ Print(L"Unable to allocate info buffer\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub,
+ &file_info_id, &buffersize,
+ fileinfo);
+ }
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Unable to get file info\n");
+ return efi_status;
+ }
+
+ buffersize = fileinfo->FileSize;
+ *grubdata = AllocatePool(buffersize);
+
+ if (!*grubdata) {
+ Print(L"Unable to allocate file buffer\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ efi_status = uefi_call_wrapper(grub->Read, 3, grub, &buffersize,
+ *grubdata);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Unexpected return from initial read: %x, buffersize %x\n", efi_status, buffersize);
+ return efi_status;
+ }
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Unable to read grub\n");
+ return efi_status;
+ }
+
+ *grubsize = buffersize;
+
+ return EFI_SUCCESS;
+}
+
EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
{
EFI_STATUS efi_status;