From 06e98a10f639ba53201876f2ff9fbd468bfa8189 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 2 Dec 2020 13:59:38 -0500 Subject: [PATCH] Move a bunch of PE-related stuff out of shim.c Signed-off-by: Peter Jones --- Makefile | 4 +- include/pe.h | 35 ++ pe.c | 940 +++++++++++++++++++++++++++++++++++++++++++++++++++ shim.c | 925 +------------------------------------------------- shim.h | 11 + 5 files changed, 995 insertions(+), 920 deletions(-) create mode 100644 include/pe.h create mode 100644 pe.c diff --git a/Makefile b/Makefile index 45d57fc..111f251 100644 --- a/Makefile +++ b/Makefile @@ -33,9 +33,9 @@ CFLAGS += -DENABLE_SHIM_CERT else TARGETS += $(MMNAME) $(FBNAME) endif -OBJS = shim.o mok.o netboot.o cert.o replacements.o tpm.o version.o errlog.o sbat.o +OBJS = shim.o mok.o netboot.o cert.o replacements.o tpm.o version.o errlog.o sbat.o pe.o KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer -ORIG_SOURCES = shim.c mok.c netboot.c replacements.c tpm.c errlog.c shim.h version.h $(wildcard include/*.h) +ORIG_SOURCES = shim.c mok.c netboot.c replacements.c tpm.c errlog.c pe.c shim.h version.h $(wildcard include/*.h) MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o errlog.o sbat.o ORIG_MOK_SOURCES = MokManager.c PasswordCrypt.c crypt_blowfish.c shim.h $(wildcard include/*.h) FALLBACK_OBJS = fallback.o tpm.o errlog.o sbat.o diff --git a/include/pe.h b/include/pe.h new file mode 100644 index 0000000..7f2236e --- /dev/null +++ b/include/pe.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * pe.h - helper functions for pe binaries. + * Copyright Peter Jones + */ + +#ifndef PE_H_ +#define PE_H_ + +void * +ImageAddress (void *image, uint64_t size, uint64_t address); + +EFI_STATUS +read_header(void *data, unsigned int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context); + +EFI_STATUS +handle_image (void *data, unsigned int datasize, + EFI_LOADED_IMAGE *li, + EFI_IMAGE_ENTRY_POINT *entry_point, + EFI_PHYSICAL_ADDRESS *alloc_address, + UINTN *alloc_pages); + +EFI_STATUS +generate_hash (char *data, unsigned int datasize_in, + PE_COFF_LOADER_IMAGE_CONTEXT *context, + UINT8 *sha256hash, UINT8 *sha1hash); + +EFI_STATUS +relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context, + EFI_IMAGE_SECTION_HEADER *Section, + void *orig, void *data); + +#endif /* !PE_H_ */ +// vim:fenc=utf-8:tw=75:noet diff --git a/pe.c b/pe.c new file mode 100644 index 0000000..43ed4f8 --- /dev/null +++ b/pe.c @@ -0,0 +1,940 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * pe.c - helper functions for pe binaries. + * Copyright Peter Jones + */ + +#include "shim.h" +#include "hexdump.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Perform basic bounds checking of the intra-image pointers + */ +void * +ImageAddress (void *image, uint64_t size, uint64_t address) +{ + /* ensure our local pointer isn't bigger than our size */ + if (address > size) + return NULL; + + /* Insure our math won't overflow */ + if (UINT64_MAX - address < (uint64_t)(intptr_t)image) + return NULL; + + /* return the absolute pointer */ + return image + address; +} + +/* + * Perform the actual relocation + */ +EFI_STATUS +relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context, + EFI_IMAGE_SECTION_HEADER *Section, + void *orig, void *data) +{ + EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd; + UINT64 Adjust; + UINT16 *Reloc, *RelocEnd; + char *Fixup, *FixupBase; + UINT16 *Fixup16; + UINT32 *Fixup32; + UINT64 *Fixup64; + int size = context->ImageSize; + void *ImageEnd = (char *)orig + size; + int n = 0; + + /* Alright, so here's how this works: + * + * context->RelocDir gives us two things: + * - the VA the table of base relocation blocks are (maybe) to be + * mapped at (RelocDir->VirtualAddress) + * - the virtual size (RelocDir->Size) + * + * The .reloc section (Section here) gives us some other things: + * - the name! kind of. (Section->Name) + * - the virtual size (Section->VirtualSize), which should be the same + * as RelocDir->Size + * - the virtual address (Section->VirtualAddress) + * - the file section size (Section->SizeOfRawData), which is + * a multiple of OptHdr->FileAlignment. Only useful for image + * validation, not really useful for iteration bounds. + * - the file address (Section->PointerToRawData) + * - a bunch of stuff we don't use that's 0 in our binaries usually + * - Flags (Section->Characteristics) + * + * and then the thing that's actually at the file address is an array + * of EFI_IMAGE_BASE_RELOCATION structs with some values packed behind + * them. The SizeOfBlock field of this structure includes the + * structure itself, and adding it to that structure's address will + * yield the next entry in the array. + */ + RelocBase = ImageAddress(orig, size, Section->PointerToRawData); + /* RelocBaseEnd here is the address of the first entry /past/ the + * table. */ + RelocBaseEnd = ImageAddress(orig, size, Section->PointerToRawData + + Section->Misc.VirtualSize); + + if (!RelocBase && !RelocBaseEnd) + return EFI_SUCCESS; + + if (!RelocBase || !RelocBaseEnd) { + perror(L"Reloc table overflows binary\n"); + return EFI_UNSUPPORTED; + } + + Adjust = (UINTN)data - context->ImageAddress; + + if (Adjust == 0) + return EFI_SUCCESS; + + while (RelocBase < RelocBaseEnd) { + Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION)); + + if (RelocBase->SizeOfBlock == 0) { + perror(L"Reloc %d block size 0 is invalid\n", n); + return EFI_UNSUPPORTED; + } else if (RelocBase->SizeOfBlock > context->RelocDir->Size) { + perror(L"Reloc %d block size %d greater than reloc dir" + "size %d, which is invalid\n", n, + RelocBase->SizeOfBlock, + context->RelocDir->Size); + return EFI_UNSUPPORTED; + } + + RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock); + if ((void *)RelocEnd < orig || (void *)RelocEnd > ImageEnd) { + perror(L"Reloc %d entry overflows binary\n", n); + return EFI_UNSUPPORTED; + } + + FixupBase = ImageAddress(data, size, RelocBase->VirtualAddress); + if (!FixupBase) { + perror(L"Reloc %d Invalid fixupbase\n", 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))); + break; + + case EFI_IMAGE_REL_BASED_LOW: + Fixup16 = (UINT16 *) Fixup; + *Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust); + break; + + case EFI_IMAGE_REL_BASED_HIGHLOW: + Fixup32 = (UINT32 *) Fixup; + *Fixup32 = *Fixup32 + (UINT32) Adjust; + break; + + case EFI_IMAGE_REL_BASED_DIR64: + Fixup64 = (UINT64 *) Fixup; + *Fixup64 = *Fixup64 + (UINT64) Adjust; + break; + + default: + perror(L"Reloc %d Unknown relocation\n", n); + return EFI_UNSUPPORTED; + } + Reloc += 1; + } + RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd; + n++; + } + + return EFI_SUCCESS; +} + +#define check_size_line(data, datasize_in, hashbase, hashsize, l) ({ \ + if ((unsigned long)hashbase > \ + (unsigned long)data + datasize_in) { \ + efi_status = EFI_INVALID_PARAMETER; \ + perror(L"shim.c:%d Invalid hash base 0x%016x\n", l, \ + hashbase); \ + goto done; \ + } \ + if ((unsigned long)hashbase + hashsize > \ + (unsigned long)data + datasize_in) { \ + efi_status = EFI_INVALID_PARAMETER; \ + perror(L"shim.c:%d Invalid hash size 0x%016x\n", l, \ + hashsize); \ + goto done; \ + } \ +}) +#define check_size(d, ds, h, hs) check_size_line(d, ds, h, hs, __LINE__) + +/* + * Calculate the SHA1 and SHA256 hashes of a binary + */ + +EFI_STATUS +generate_hash(char *data, unsigned int datasize_in, + PE_COFF_LOADER_IMAGE_CONTEXT *context, UINT8 *sha256hash, + UINT8 *sha1hash) +{ + unsigned int sha256ctxsize, sha1ctxsize; + unsigned int size = datasize_in; + void *sha256ctx = NULL, *sha1ctx = NULL; + char *hashbase; + unsigned int hashsize; + unsigned int SumOfBytesHashed, SumOfSectionBytes; + unsigned int index, pos; + unsigned int datasize; + EFI_IMAGE_SECTION_HEADER *Section; + EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL; + EFI_STATUS efi_status = EFI_SUCCESS; + EFI_IMAGE_DOS_HEADER *DosHdr = (void *)data; + unsigned int PEHdr_offset = 0; + + size = datasize = datasize_in; + + if (datasize <= sizeof (*DosHdr) || + DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + perror(L"Invalid signature\n"); + return EFI_INVALID_PARAMETER; + } + PEHdr_offset = DosHdr->e_lfanew; + + sha256ctxsize = Sha256GetContextSize(); + sha256ctx = AllocatePool(sha256ctxsize); + + sha1ctxsize = Sha1GetContextSize(); + sha1ctx = AllocatePool(sha1ctxsize); + + if (!sha256ctx || !sha1ctx) { + perror(L"Unable to allocate memory for hash context\n"); + return EFI_OUT_OF_RESOURCES; + } + + if (!Sha256Init(sha256ctx) || !Sha1Init(sha1ctx)) { + perror(L"Unable to initialise hash\n"); + efi_status = EFI_OUT_OF_RESOURCES; + goto done; + } + + /* Hash start to checksum */ + hashbase = data; + hashsize = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum - + hashbase; + check_size(data, datasize_in, hashbase, hashsize); + + if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || + !(Sha1Update(sha1ctx, hashbase, hashsize))) { + perror(L"Unable to generate hash\n"); + efi_status = EFI_OUT_OF_RESOURCES; + goto done; + } + + /* Hash post-checksum to start of certificate table */ + hashbase = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum + + sizeof (int); + hashsize = (char *)context->SecDir - hashbase; + check_size(data, datasize_in, hashbase, hashsize); + + if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || + !(Sha1Update(sha1ctx, hashbase, hashsize))) { + perror(L"Unable to generate hash\n"); + efi_status = EFI_OUT_OF_RESOURCES; + goto done; + } + + /* Hash end of certificate table to end of image header */ + EFI_IMAGE_DATA_DIRECTORY *dd = context->SecDir + 1; + hashbase = (char *)dd; + hashsize = context->SizeOfHeaders - (unsigned long)((char *)dd - data); + if (hashsize > datasize_in) { + perror(L"Data Directory size %d is invalid\n", hashsize); + efi_status = EFI_INVALID_PARAMETER; + goto done; + } + check_size(data, datasize_in, hashbase, hashsize); + + if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || + !(Sha1Update(sha1ctx, hashbase, hashsize))) { + perror(L"Unable to generate hash\n"); + efi_status = EFI_OUT_OF_RESOURCES; + goto done; + } + + /* Sort sections */ + SumOfBytesHashed = context->SizeOfHeaders; + + /* Validate section locations and sizes */ + for (index = 0, SumOfSectionBytes = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) { + EFI_IMAGE_SECTION_HEADER *SectionPtr; + + /* Validate SectionPtr is within image */ + SectionPtr = ImageAddress(data, datasize, + PEHdr_offset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + + (index * sizeof(*SectionPtr))); + if (!SectionPtr) { + perror(L"Malformed section %d\n", index); + efi_status = EFI_INVALID_PARAMETER; + goto done; + } + /* Validate section size is within image. */ + if (SectionPtr->SizeOfRawData > + datasize - SumOfBytesHashed - SumOfSectionBytes) { + perror(L"Malformed section %d size\n", index); + efi_status = EFI_INVALID_PARAMETER; + goto done; + } + SumOfSectionBytes += SectionPtr->SizeOfRawData; + } + + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * context->PEHdr->Pe32.FileHeader.NumberOfSections); + if (SectionHeader == NULL) { + perror(L"Unable to allocate section header\n"); + efi_status = EFI_OUT_OF_RESOURCES; + goto done; + } + + /* Already validated above */ + Section = ImageAddress(data, datasize, + PEHdr_offset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader); + /* But check it again just for better error messaging, and so + * clang-analyzer doesn't get confused. */ + if (Section == NULL) { + uint64_t addr; + + addr = PEHdr_offset + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER) + + context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader; + perror(L"Malformed file header.\n"); + perror(L"Image address for Section 0 is 0x%016llx\n", addr); + perror(L"File size is 0x%016llx\n", datasize); + efi_status = EFI_INVALID_PARAMETER; + goto done; + } + + /* Sort the section headers */ + for (index = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) { + pos = index; + while ((pos > 0) && (Section->PointerToRawData < SectionHeader[pos - 1].PointerToRawData)) { + CopyMem (&SectionHeader[pos], &SectionHeader[pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); + pos--; + } + CopyMem (&SectionHeader[pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); + Section += 1; + } + + /* Hash the sections */ + for (index = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) { + Section = &SectionHeader[index]; + if (Section->SizeOfRawData == 0) { + continue; + } + hashbase = ImageAddress(data, size, Section->PointerToRawData); + + if (!hashbase) { + perror(L"Malformed section header\n"); + efi_status = EFI_INVALID_PARAMETER; + goto done; + } + + /* Verify hashsize within image. */ + if (Section->SizeOfRawData > + datasize - Section->PointerToRawData) { + perror(L"Malformed section raw size %d\n", index); + efi_status = EFI_INVALID_PARAMETER; + goto done; + } + hashsize = (unsigned int) Section->SizeOfRawData; + check_size(data, datasize_in, hashbase, hashsize); + + if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || + !(Sha1Update(sha1ctx, hashbase, hashsize))) { + perror(L"Unable to generate hash\n"); + efi_status = EFI_OUT_OF_RESOURCES; + goto done; + } + SumOfBytesHashed += Section->SizeOfRawData; + } + + /* Hash all remaining data up to SecDir if SecDir->Size is not 0 */ + if (datasize > SumOfBytesHashed && context->SecDir->Size) { + hashbase = data + SumOfBytesHashed; + hashsize = datasize - context->SecDir->Size - SumOfBytesHashed; + + if ((datasize - SumOfBytesHashed < context->SecDir->Size) || + (SumOfBytesHashed + hashsize != context->SecDir->VirtualAddress)) { + perror(L"Malformed binary after Attribute Certificate Table\n"); + console_print(L"datasize: %u SumOfBytesHashed: %u SecDir->Size: %lu\n", + datasize, SumOfBytesHashed, context->SecDir->Size); + console_print(L"hashsize: %u SecDir->VirtualAddress: 0x%08lx\n", + hashsize, context->SecDir->VirtualAddress); + efi_status = EFI_INVALID_PARAMETER; + goto done; + } + check_size(data, datasize_in, hashbase, hashsize); + + if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || + !(Sha1Update(sha1ctx, hashbase, hashsize))) { + perror(L"Unable to generate hash\n"); + efi_status = EFI_OUT_OF_RESOURCES; + goto done; + } + +#if 1 + } +#else // we have to migrate to doing this later :/ + SumOfBytesHashed += hashsize; + } + + /* Hash all remaining data */ + if (datasize > SumOfBytesHashed) { + hashbase = data + SumOfBytesHashed; + hashsize = datasize - SumOfBytesHashed; + + check_size(data, datasize_in, hashbase, hashsize); + + if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || + !(Sha1Update(sha1ctx, hashbase, hashsize))) { + perror(L"Unable to generate hash\n"); + efi_status = EFI_OUT_OF_RESOURCES; + goto done; + } + + SumOfBytesHashed += hashsize; + } +#endif + + if (!(Sha256Final(sha256ctx, sha256hash)) || + !(Sha1Final(sha1ctx, sha1hash))) { + perror(L"Unable to finalise hash\n"); + efi_status = EFI_OUT_OF_RESOURCES; + goto done; + } + + dprint(L"sha1 authenticode hash:\n"); + dhexdumpat(sha1hash, SHA1_DIGEST_SIZE, 0); + dprint(L"sha256 authenticode hash:\n"); + dhexdumpat(sha256hash, SHA256_DIGEST_SIZE, 0); + +done: + if (SectionHeader) + FreePool(SectionHeader); + if (sha1ctx) + FreePool(sha1ctx); + if (sha256ctx) + FreePool(sha256ctx); + + return efi_status; +} + +/* here's a chart: + * i686 x86_64 aarch64 + * 64-on-64: nyet yes yes + * 64-on-32: nyet yes nyet + * 32-on-32: yes yes no + */ +static int +allow_64_bit(void) +{ +#if defined(__x86_64__) || defined(__aarch64__) + return 1; +#elif defined(__i386__) || defined(__i686__) + /* Right now blindly assuming the kernel will correctly detect this + * and /halt the system/ if you're not really on a 64-bit cpu */ + if (in_protocol) + return 1; + return 0; +#else /* assuming everything else is 32-bit... */ + return 0; +#endif +} + +static int +allow_32_bit(void) +{ +#if defined(__x86_64__) +#if defined(ALLOW_32BIT_KERNEL_ON_X64) + if (in_protocol) + return 1; + return 0; +#else + return 0; +#endif +#elif defined(__i386__) || defined(__i686__) + return 1; +#elif defined(__aarch64__) + return 0; +#else /* assuming everything else is 32-bit... */ + return 1; +#endif +} + +static int +image_is_64_bit(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr) +{ + /* .Magic is the same offset in all cases */ + if (PEHdr->Pe32Plus.OptionalHeader.Magic + == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) + return 1; + return 0; +} + +static const UINT16 machine_type = +#if defined(__x86_64__) + IMAGE_FILE_MACHINE_X64; +#elif defined(__aarch64__) + IMAGE_FILE_MACHINE_ARM64; +#elif defined(__arm__) + IMAGE_FILE_MACHINE_ARMTHUMB_MIXED; +#elif defined(__i386__) || defined(__i486__) || defined(__i686__) + IMAGE_FILE_MACHINE_I386; +#elif defined(__ia64__) + IMAGE_FILE_MACHINE_IA64; +#else +#error this architecture is not supported by shim +#endif + +static int +image_is_loadable(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr) +{ + /* If the machine type doesn't match the binary, bail, unless + * we're in an allowed 64-on-32 scenario */ + if (PEHdr->Pe32.FileHeader.Machine != machine_type) { + if (!(machine_type == IMAGE_FILE_MACHINE_I386 && + PEHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_X64 && + allow_64_bit())) { + return 0; + } + } + + /* If it's not a header type we recognize at all, bail */ + switch (PEHdr->Pe32Plus.OptionalHeader.Magic) { + case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC: + case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC: + break; + default: + return 0; + } + + /* and now just check for general 64-vs-32 compatibility */ + if (image_is_64_bit(PEHdr)) { + if (allow_64_bit()) + return 1; + } else { + if (allow_32_bit()) + return 1; + } + return 0; +} + +/* + * Read the binary header and grab appropriate information from it + */ +EFI_STATUS +read_header(void *data, unsigned int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context) +{ + EFI_IMAGE_DOS_HEADER *DosHdr = data; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data; + unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize; + unsigned long FileAlignment = 0; + + if (datasize < sizeof (PEHdr->Pe32)) { + perror(L"Invalid image\n"); + return EFI_UNSUPPORTED; + } + + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) + PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew); + + if (!image_is_loadable(PEHdr)) { + perror(L"Platform does not support this image\n"); + return EFI_UNSUPPORTED; + } + + if (image_is_64_bit(PEHdr)) { + context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes; + context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders; + context->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage; + context->SectionAlignment = PEHdr->Pe32Plus.OptionalHeader.SectionAlignment; + FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment; + OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64); + } else { + context->NumberOfRvaAndSizes = PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes; + context->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders; + context->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage; + context->SectionAlignment = PEHdr->Pe32.OptionalHeader.SectionAlignment; + FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment; + OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32); + } + + if (FileAlignment % 2 != 0) { + perror(L"File Alignment is invalid (%d)\n", FileAlignment); + return EFI_UNSUPPORTED; + } + if (FileAlignment == 0) + FileAlignment = 0x200; + if (context->SectionAlignment == 0) + context->SectionAlignment = PAGE_SIZE; + if (context->SectionAlignment < FileAlignment) + context->SectionAlignment = FileAlignment; + + context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections; + + if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < context->NumberOfRvaAndSizes) { + perror(L"Image header too small\n"); + return EFI_UNSUPPORTED; + } + + HeaderWithoutDataDir = OptHeaderSize + - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES; + if (((UINT32)PEHdr->Pe32.FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) != + context->NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) { + perror(L"Image header overflows data directory\n"); + return EFI_UNSUPPORTED; + } + + SectionHeaderOffset = DosHdr->e_lfanew + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader; + if (((UINT32)context->ImageSize - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER + <= context->NumberOfSections) { + perror(L"Image sections overflow image size\n"); + return EFI_UNSUPPORTED; + } + + if ((context->SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER + < (UINT32)context->NumberOfSections) { + perror(L"Image sections overflow section headers\n"); + return EFI_UNSUPPORTED; + } + + if ((((UINT8 *)PEHdr - (UINT8 *)data) + sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION)) > datasize) { + perror(L"Invalid image\n"); + return EFI_UNSUPPORTED; + } + + if (PEHdr->Te.Signature != EFI_IMAGE_NT_SIGNATURE) { + perror(L"Unsupported image type\n"); + return EFI_UNSUPPORTED; + } + + if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) { + perror(L"Unsupported image - Relocations have been stripped\n"); + return EFI_UNSUPPORTED; + } + + context->PEHdr = PEHdr; + + if (image_is_64_bit(PEHdr)) { + context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase; + context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint; + context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + } else { + context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase; + context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint; + context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + } + + context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER)); + + if (context->ImageSize < context->SizeOfHeaders) { + perror(L"Invalid image\n"); + return EFI_UNSUPPORTED; + } + + if ((unsigned long)((UINT8 *)context->SecDir - (UINT8 *)data) > + (datasize - sizeof(EFI_IMAGE_DATA_DIRECTORY))) { + perror(L"Invalid image\n"); + return EFI_UNSUPPORTED; + } + + if (context->SecDir->VirtualAddress > datasize || + (context->SecDir->VirtualAddress == datasize && + context->SecDir->Size > 0)) { + perror(L"Malformed security header\n"); + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + +/* + * Once the image has been loaded it needs to be validated and relocated + */ +EFI_STATUS +handle_image (void *data, unsigned int datasize, + EFI_LOADED_IMAGE *li, + EFI_IMAGE_ENTRY_POINT *entry_point, + EFI_PHYSICAL_ADDRESS *alloc_address, + UINTN *alloc_pages) +{ + EFI_STATUS efi_status; + char *buffer; + int i; + EFI_IMAGE_SECTION_HEADER *Section; + char *base, *end; + PE_COFF_LOADER_IMAGE_CONTEXT context; + unsigned int alignment, alloc_size; + int found_entry_point = 0; + UINT8 sha1hash[SHA1_DIGEST_SIZE]; + UINT8 sha256hash[SHA256_DIGEST_SIZE]; + + /* + * The binary header contains relevant context and section pointers + */ + efi_status = read_header(data, datasize, &context); + if (EFI_ERROR(efi_status)) { + perror(L"Failed to read header: %r\n", efi_status); + return efi_status; + } + + /* + * We only need to verify the binary if we're in secure mode + */ + efi_status = generate_hash(data, datasize, &context, sha256hash, + sha1hash); + if (EFI_ERROR(efi_status)) + return efi_status; + + /* Measure the binary into the TPM */ +#ifdef REQUIRE_TPM + efi_status = +#endif + tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize, + (EFI_PHYSICAL_ADDRESS)(UINTN)context.ImageAddress, + li->FilePath, sha1hash, 4); +#ifdef REQUIRE_TPM + if (efi_status != EFI_SUCCESS) { + return efi_status; + } +#endif + + if (secure_mode ()) { + efi_status = verify_buffer(data, datasize, &context, + sha256hash, sha1hash); + + if (EFI_ERROR(efi_status)) { + if (verbose) + console_print(L"Verification failed: %r\n", efi_status); + else + console_error(L"Verification failed", efi_status); + return efi_status; + } else { + if (verbose) + console_print(L"Verification succeeded\n"); + } + } + + /* The spec says, uselessly, of SectionAlignment: + * ===== + * The alignment (in bytes) of sections when they are loaded into + * memory. It must be greater than or equal to FileAlignment. The + * default is the page size for the architecture. + * ===== + * Which doesn't tell you whose responsibility it is to enforce the + * "default", or when. It implies that the value in the field must + * be > FileAlignment (also poorly defined), but it appears visual + * studio will happily write 512 for FileAlignment (its default) and + * 0 for SectionAlignment, intending to imply PAGE_SIZE. + * + * We only support one page size, so if it's zero, nerf it to 4096. + */ + alignment = context.SectionAlignment; + if (!alignment) + alignment = 4096; + + alloc_size = ALIGN_VALUE(context.ImageSize + context.SectionAlignment, + PAGE_SIZE); + *alloc_pages = alloc_size / PAGE_SIZE; + + efi_status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderCode, + *alloc_pages, alloc_address); + if (EFI_ERROR(efi_status)) { + perror(L"Failed to allocate image buffer\n"); + return EFI_OUT_OF_RESOURCES; + } + + buffer = (void *)ALIGN_VALUE((unsigned long)*alloc_address, alignment); + + CopyMem(buffer, data, context.SizeOfHeaders); + + *entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint); + if (!*entry_point) { + perror(L"Entry point is invalid\n"); + gBS->FreePages(*alloc_address, *alloc_pages); + return EFI_UNSUPPORTED; + } + + char *RelocBase, *RelocBaseEnd; + /* + * These are relative virtual addresses, so we have to check them + * against the image size, not the data size. + */ + RelocBase = ImageAddress(buffer, context.ImageSize, + context.RelocDir->VirtualAddress); + /* + * RelocBaseEnd here is the address of the last byte of the table + */ + RelocBaseEnd = ImageAddress(buffer, context.ImageSize, + context.RelocDir->VirtualAddress + + context.RelocDir->Size - 1); + + EFI_IMAGE_SECTION_HEADER *RelocSection = NULL; + + /* + * Copy the executable's sections to their desired offsets + */ + Section = context.FirstSection; + for (i = 0; i < context.NumberOfSections; i++, Section++) { + /* Don't try to copy discardable sections with zero size */ + if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) && + !Section->Misc.VirtualSize) + continue; + + base = ImageAddress (buffer, context.ImageSize, + Section->VirtualAddress); + end = ImageAddress (buffer, context.ImageSize, + Section->VirtualAddress + + Section->Misc.VirtualSize - 1); + + if (end < base) { + perror(L"Section %d has negative size\n", i); + gBS->FreePages(*alloc_address, *alloc_pages); + return EFI_UNSUPPORTED; + } + + if (Section->VirtualAddress <= context.EntryPoint && + (Section->VirtualAddress + Section->SizeOfRawData - 1) + > context.EntryPoint) + found_entry_point++; + + /* We do want to process .reloc, but it's often marked + * discardable, so we don't want to memcpy it. */ + if (CompareMem(Section->Name, ".reloc\0\0", 8) == 0) { + if (RelocSection) { + perror(L"Image has multiple relocation sections\n"); + return EFI_UNSUPPORTED; + } + /* If it has nonzero sizes, and our bounds check + * made sense, and the VA and size match RelocDir's + * versions, then we believe in this section table. */ + if (Section->SizeOfRawData && + Section->Misc.VirtualSize && + base && end && + RelocBase == base && + RelocBaseEnd == end) { + RelocSection = Section; + } + } + + if (Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) { + continue; + } + + if (!base) { + perror(L"Section %d has invalid base address\n", i); + return EFI_UNSUPPORTED; + } + if (!end) { + perror(L"Section %d has zero size\n", i); + return EFI_UNSUPPORTED; + } + + if (!(Section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) && + (Section->VirtualAddress < context.SizeOfHeaders || + Section->PointerToRawData < context.SizeOfHeaders)) { + perror(L"Section %d is inside image headers\n", i); + return EFI_UNSUPPORTED; + } + + if (Section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) { + ZeroMem(base, Section->Misc.VirtualSize); + } else { + if (Section->PointerToRawData < context.SizeOfHeaders) { + perror(L"Section %d is inside image headers\n", i); + return EFI_UNSUPPORTED; + } + + if (Section->SizeOfRawData > 0) + CopyMem(base, data + Section->PointerToRawData, + Section->SizeOfRawData); + + if (Section->SizeOfRawData < Section->Misc.VirtualSize) + ZeroMem(base + Section->SizeOfRawData, + Section->Misc.VirtualSize - Section->SizeOfRawData); + } + } + + if (context.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + perror(L"Image has no relocation entry\n"); + FreePool(buffer); + return EFI_UNSUPPORTED; + } + + if (context.RelocDir->Size && RelocSection) { + /* + * Run the relocation fixups + */ + efi_status = relocate_coff(&context, RelocSection, data, + buffer); + + if (EFI_ERROR(efi_status)) { + perror(L"Relocation failed: %r\n", efi_status); + FreePool(buffer); + return efi_status; + } + } + + /* + * grub needs to know its location and size in memory, so fix up + * the loaded image protocol values + */ + li->ImageBase = buffer; + li->ImageSize = context.ImageSize; + + /* Pass the load options to the second stage loader */ + if ( load_options ) { + li->LoadOptions = load_options; + li->LoadOptionsSize = load_options_size; + } + + if (!found_entry_point) { + perror(L"Entry point is not within sections\n"); + return EFI_UNSUPPORTED; + } + if (found_entry_point > 1) { + perror(L"%d sections contain entry point\n"); + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + + +// vim:fenc=utf-8:tw=75:noet diff --git a/shim.c b/shim.c index 0d00ada..eb8192d 100644 --- a/shim.c +++ b/shim.c @@ -62,8 +62,8 @@ static EFI_SYSTEM_TABLE *systab; static EFI_HANDLE global_image_handle; static CHAR16 *second_stage; -static void *load_options; -static UINT32 load_options_size; +void *load_options; +UINT32 load_options_size; /* * The vendor certificate used for validating the second stage loader @@ -108,250 +108,6 @@ typedef struct { UINT8 *Mok; } MokListNode; -/* - * Perform basic bounds checking of the intra-image pointers - */ -static void *ImageAddress (void *image, uint64_t size, uint64_t address) -{ - /* ensure our local pointer isn't bigger than our size */ - if (address > size) - return NULL; - - /* Insure our math won't overflow */ - if (UINT64_MAX - address < (uint64_t)(intptr_t)image) - return NULL; - - /* return the absolute pointer */ - return image + address; -} - -/* here's a chart: - * i686 x86_64 aarch64 - * 64-on-64: nyet yes yes - * 64-on-32: nyet yes nyet - * 32-on-32: yes yes no - */ -static int -allow_64_bit(void) -{ -#if defined(__x86_64__) || defined(__aarch64__) - return 1; -#elif defined(__i386__) || defined(__i686__) - /* Right now blindly assuming the kernel will correctly detect this - * and /halt the system/ if you're not really on a 64-bit cpu */ - if (in_protocol) - return 1; - return 0; -#else /* assuming everything else is 32-bit... */ - return 0; -#endif -} - -static int -allow_32_bit(void) -{ -#if defined(__x86_64__) -#if defined(ALLOW_32BIT_KERNEL_ON_X64) - if (in_protocol) - return 1; - return 0; -#else - return 0; -#endif -#elif defined(__i386__) || defined(__i686__) - return 1; -#elif defined(__aarch64__) - return 0; -#else /* assuming everything else is 32-bit... */ - return 1; -#endif -} - -static int -image_is_64_bit(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr) -{ - /* .Magic is the same offset in all cases */ - if (PEHdr->Pe32Plus.OptionalHeader.Magic - == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) - return 1; - return 0; -} - -static const UINT16 machine_type = -#if defined(__x86_64__) - IMAGE_FILE_MACHINE_X64; -#elif defined(__aarch64__) - IMAGE_FILE_MACHINE_ARM64; -#elif defined(__arm__) - IMAGE_FILE_MACHINE_ARMTHUMB_MIXED; -#elif defined(__i386__) || defined(__i486__) || defined(__i686__) - IMAGE_FILE_MACHINE_I386; -#elif defined(__ia64__) - IMAGE_FILE_MACHINE_IA64; -#else -#error this architecture is not supported by shim -#endif - -static int -image_is_loadable(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr) -{ - /* If the machine type doesn't match the binary, bail, unless - * we're in an allowed 64-on-32 scenario */ - if (PEHdr->Pe32.FileHeader.Machine != machine_type) { - if (!(machine_type == IMAGE_FILE_MACHINE_I386 && - PEHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_X64 && - allow_64_bit())) { - return 0; - } - } - - /* If it's not a header type we recognize at all, bail */ - switch (PEHdr->Pe32Plus.OptionalHeader.Magic) { - case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC: - case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC: - break; - default: - return 0; - } - - /* and now just check for general 64-vs-32 compatibility */ - if (image_is_64_bit(PEHdr)) { - if (allow_64_bit()) - return 1; - } else { - if (allow_32_bit()) - return 1; - } - return 0; -} - -/* - * Perform the actual relocation - */ -static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context, - EFI_IMAGE_SECTION_HEADER *Section, - void *orig, void *data) -{ - EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd; - UINT64 Adjust; - UINT16 *Reloc, *RelocEnd; - char *Fixup, *FixupBase; - UINT16 *Fixup16; - UINT32 *Fixup32; - UINT64 *Fixup64; - int size = context->ImageSize; - void *ImageEnd = (char *)orig + size; - int n = 0; - - /* Alright, so here's how this works: - * - * context->RelocDir gives us two things: - * - the VA the table of base relocation blocks are (maybe) to be - * mapped at (RelocDir->VirtualAddress) - * - the virtual size (RelocDir->Size) - * - * The .reloc section (Section here) gives us some other things: - * - the name! kind of. (Section->Name) - * - the virtual size (Section->VirtualSize), which should be the same - * as RelocDir->Size - * - the virtual address (Section->VirtualAddress) - * - the file section size (Section->SizeOfRawData), which is - * a multiple of OptHdr->FileAlignment. Only useful for image - * validation, not really useful for iteration bounds. - * - the file address (Section->PointerToRawData) - * - a bunch of stuff we don't use that's 0 in our binaries usually - * - Flags (Section->Characteristics) - * - * and then the thing that's actually at the file address is an array - * of EFI_IMAGE_BASE_RELOCATION structs with some values packed behind - * them. The SizeOfBlock field of this structure includes the - * structure itself, and adding it to that structure's address will - * yield the next entry in the array. - */ - RelocBase = ImageAddress(orig, size, Section->PointerToRawData); - /* RelocBaseEnd here is the address of the first entry /past/ the - * table. */ - RelocBaseEnd = ImageAddress(orig, size, Section->PointerToRawData + - Section->Misc.VirtualSize); - - if (!RelocBase && !RelocBaseEnd) - return EFI_SUCCESS; - - if (!RelocBase || !RelocBaseEnd) { - perror(L"Reloc table overflows binary\n"); - return EFI_UNSUPPORTED; - } - - Adjust = (UINTN)data - context->ImageAddress; - - if (Adjust == 0) - return EFI_SUCCESS; - - while (RelocBase < RelocBaseEnd) { - Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION)); - - if (RelocBase->SizeOfBlock == 0) { - perror(L"Reloc %d block size 0 is invalid\n", n); - return EFI_UNSUPPORTED; - } else if (RelocBase->SizeOfBlock > context->RelocDir->Size) { - perror(L"Reloc %d block size %d greater than reloc dir" - "size %d, which is invalid\n", n, - RelocBase->SizeOfBlock, - context->RelocDir->Size); - return EFI_UNSUPPORTED; - } - - RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock); - if ((void *)RelocEnd < orig || (void *)RelocEnd > ImageEnd) { - perror(L"Reloc %d entry overflows binary\n", n); - return EFI_UNSUPPORTED; - } - - FixupBase = ImageAddress(data, size, RelocBase->VirtualAddress); - if (!FixupBase) { - perror(L"Reloc %d Invalid fixupbase\n", 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))); - break; - - case EFI_IMAGE_REL_BASED_LOW: - Fixup16 = (UINT16 *) Fixup; - *Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust); - break; - - case EFI_IMAGE_REL_BASED_HIGHLOW: - Fixup32 = (UINT32 *) Fixup; - *Fixup32 = *Fixup32 + (UINT32) Adjust; - break; - - case EFI_IMAGE_REL_BASED_DIR64: - Fixup64 = (UINT64 *) Fixup; - *Fixup64 = *Fixup64 + (UINT64) Adjust; - break; - - default: - perror(L"Reloc %d Unknown relocation\n", n); - return EFI_UNSUPPORTED; - } - Reloc += 1; - } - RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd; - n++; - } - - return EFI_SUCCESS; -} - static void drain_openssl_errors(void) { @@ -709,8 +465,7 @@ static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert, /* * Check whether we're in Secure Boot and user mode */ - -static BOOLEAN secure_mode (void) +BOOLEAN secure_mode (void) { static int first = 1; if (user_insecure_mode) @@ -740,288 +495,6 @@ static BOOLEAN secure_mode (void) return TRUE; } -#define check_size_line(data, datasize_in, hashbase, hashsize, l) ({ \ - if ((unsigned long)hashbase > \ - (unsigned long)data + datasize_in) { \ - efi_status = EFI_INVALID_PARAMETER; \ - perror(L"shim.c:%d Invalid hash base 0x%016x\n", l, \ - hashbase); \ - goto done; \ - } \ - if ((unsigned long)hashbase + hashsize > \ - (unsigned long)data + datasize_in) { \ - efi_status = EFI_INVALID_PARAMETER; \ - perror(L"shim.c:%d Invalid hash size 0x%016x\n", l, \ - hashsize); \ - goto done; \ - } \ -}) -#define check_size(d, ds, h, hs) check_size_line(d, ds, h, hs, __LINE__) - -/* - * Calculate the SHA1 and SHA256 hashes of a binary - */ - -static EFI_STATUS generate_hash (char *data, unsigned int datasize_in, - PE_COFF_LOADER_IMAGE_CONTEXT *context, - UINT8 *sha256hash, UINT8 *sha1hash) - -{ - unsigned int sha256ctxsize, sha1ctxsize; - unsigned int size = datasize_in; - void *sha256ctx = NULL, *sha1ctx = NULL; - char *hashbase; - unsigned int hashsize; - unsigned int SumOfBytesHashed, SumOfSectionBytes; - unsigned int index, pos; - unsigned int datasize; - EFI_IMAGE_SECTION_HEADER *Section; - EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL; - EFI_STATUS efi_status = EFI_SUCCESS; - EFI_IMAGE_DOS_HEADER *DosHdr = (void *)data; - unsigned int PEHdr_offset = 0; - - size = datasize = datasize_in; - - if (datasize <= sizeof (*DosHdr) || - DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { - perror(L"Invalid signature\n"); - return EFI_INVALID_PARAMETER; - } - PEHdr_offset = DosHdr->e_lfanew; - - sha256ctxsize = Sha256GetContextSize(); - sha256ctx = AllocatePool(sha256ctxsize); - - sha1ctxsize = Sha1GetContextSize(); - sha1ctx = AllocatePool(sha1ctxsize); - - if (!sha256ctx || !sha1ctx) { - perror(L"Unable to allocate memory for hash context\n"); - return EFI_OUT_OF_RESOURCES; - } - - if (!Sha256Init(sha256ctx) || !Sha1Init(sha1ctx)) { - perror(L"Unable to initialise hash\n"); - efi_status = EFI_OUT_OF_RESOURCES; - goto done; - } - - /* Hash start to checksum */ - hashbase = data; - hashsize = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum - - hashbase; - check_size(data, datasize_in, hashbase, hashsize); - - if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || - !(Sha1Update(sha1ctx, hashbase, hashsize))) { - perror(L"Unable to generate hash\n"); - efi_status = EFI_OUT_OF_RESOURCES; - goto done; - } - - /* Hash post-checksum to start of certificate table */ - hashbase = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum + - sizeof (int); - hashsize = (char *)context->SecDir - hashbase; - check_size(data, datasize_in, hashbase, hashsize); - - if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || - !(Sha1Update(sha1ctx, hashbase, hashsize))) { - perror(L"Unable to generate hash\n"); - efi_status = EFI_OUT_OF_RESOURCES; - goto done; - } - - /* Hash end of certificate table to end of image header */ - EFI_IMAGE_DATA_DIRECTORY *dd = context->SecDir + 1; - hashbase = (char *)dd; - hashsize = context->SizeOfHeaders - (unsigned long)((char *)dd - data); - if (hashsize > datasize_in) { - perror(L"Data Directory size %d is invalid\n", hashsize); - efi_status = EFI_INVALID_PARAMETER; - goto done; - } - check_size(data, datasize_in, hashbase, hashsize); - - if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || - !(Sha1Update(sha1ctx, hashbase, hashsize))) { - perror(L"Unable to generate hash\n"); - efi_status = EFI_OUT_OF_RESOURCES; - goto done; - } - - /* Sort sections */ - SumOfBytesHashed = context->SizeOfHeaders; - - /* Validate section locations and sizes */ - for (index = 0, SumOfSectionBytes = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) { - EFI_IMAGE_SECTION_HEADER *SectionPtr; - - /* Validate SectionPtr is within image */ - SectionPtr = ImageAddress(data, datasize, - PEHdr_offset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + - (index * sizeof(*SectionPtr))); - if (!SectionPtr) { - perror(L"Malformed section %d\n", index); - efi_status = EFI_INVALID_PARAMETER; - goto done; - } - /* Validate section size is within image. */ - if (SectionPtr->SizeOfRawData > - datasize - SumOfBytesHashed - SumOfSectionBytes) { - perror(L"Malformed section %d size\n", index); - efi_status = EFI_INVALID_PARAMETER; - goto done; - } - SumOfSectionBytes += SectionPtr->SizeOfRawData; - } - - SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * context->PEHdr->Pe32.FileHeader.NumberOfSections); - if (SectionHeader == NULL) { - perror(L"Unable to allocate section header\n"); - efi_status = EFI_OUT_OF_RESOURCES; - goto done; - } - - /* Already validated above */ - Section = ImageAddress(data, datasize, - PEHdr_offset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader); - /* But check it again just for better error messaging, and so - * clang-analyzer doesn't get confused. */ - if (Section == NULL) { - uint64_t addr; - - addr = PEHdr_offset + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER) - + context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader; - perror(L"Malformed file header.\n"); - perror(L"Image address for Section 0 is 0x%016llx\n", addr); - perror(L"File size is 0x%016llx\n", datasize); - efi_status = EFI_INVALID_PARAMETER; - goto done; - } - - /* Sort the section headers */ - for (index = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) { - pos = index; - while ((pos > 0) && (Section->PointerToRawData < SectionHeader[pos - 1].PointerToRawData)) { - CopyMem (&SectionHeader[pos], &SectionHeader[pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); - pos--; - } - CopyMem (&SectionHeader[pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); - Section += 1; - } - - /* Hash the sections */ - for (index = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) { - Section = &SectionHeader[index]; - if (Section->SizeOfRawData == 0) { - continue; - } - hashbase = ImageAddress(data, size, Section->PointerToRawData); - - if (!hashbase) { - perror(L"Malformed section header\n"); - efi_status = EFI_INVALID_PARAMETER; - goto done; - } - - /* Verify hashsize within image. */ - if (Section->SizeOfRawData > - datasize - Section->PointerToRawData) { - perror(L"Malformed section raw size %d\n", index); - efi_status = EFI_INVALID_PARAMETER; - goto done; - } - hashsize = (unsigned int) Section->SizeOfRawData; - check_size(data, datasize_in, hashbase, hashsize); - - if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || - !(Sha1Update(sha1ctx, hashbase, hashsize))) { - perror(L"Unable to generate hash\n"); - efi_status = EFI_OUT_OF_RESOURCES; - goto done; - } - SumOfBytesHashed += Section->SizeOfRawData; - } - - /* Hash all remaining data up to SecDir if SecDir->Size is not 0 */ - if (datasize > SumOfBytesHashed && context->SecDir->Size) { - hashbase = data + SumOfBytesHashed; - hashsize = datasize - context->SecDir->Size - SumOfBytesHashed; - - if ((datasize - SumOfBytesHashed < context->SecDir->Size) || - (SumOfBytesHashed + hashsize != context->SecDir->VirtualAddress)) { - perror(L"Malformed binary after Attribute Certificate Table\n"); - console_print(L"datasize: %u SumOfBytesHashed: %u SecDir->Size: %lu\n", - datasize, SumOfBytesHashed, context->SecDir->Size); - console_print(L"hashsize: %u SecDir->VirtualAddress: 0x%08lx\n", - hashsize, context->SecDir->VirtualAddress); - efi_status = EFI_INVALID_PARAMETER; - goto done; - } - check_size(data, datasize_in, hashbase, hashsize); - - if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || - !(Sha1Update(sha1ctx, hashbase, hashsize))) { - perror(L"Unable to generate hash\n"); - efi_status = EFI_OUT_OF_RESOURCES; - goto done; - } - -#if 1 - } -#else // we have to migrate to doing this later :/ - SumOfBytesHashed += hashsize; - } - - /* Hash all remaining data */ - if (datasize > SumOfBytesHashed) { - hashbase = data + SumOfBytesHashed; - hashsize = datasize - SumOfBytesHashed; - - check_size(data, datasize_in, hashbase, hashsize); - - if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || - !(Sha1Update(sha1ctx, hashbase, hashsize))) { - perror(L"Unable to generate hash\n"); - efi_status = EFI_OUT_OF_RESOURCES; - goto done; - } - - SumOfBytesHashed += hashsize; - } -#endif - - if (!(Sha256Final(sha256ctx, sha256hash)) || - !(Sha1Final(sha1ctx, sha1hash))) { - perror(L"Unable to finalise hash\n"); - efi_status = EFI_OUT_OF_RESOURCES; - goto done; - } - - dprint(L"sha1 authenticode hash:\n"); - dhexdumpat(sha1hash, SHA1_DIGEST_SIZE, 0); - dprint(L"sha256 authenticode hash:\n"); - dhexdumpat(sha256hash, SHA256_DIGEST_SIZE, 0); - -done: - if (SectionHeader) - FreePool(SectionHeader); - if (sha1ctx) - FreePool(sha1ctx); - if (sha256ctx) - FreePool(sha256ctx); - - return efi_status; -} - static EFI_STATUS verify_one_signature(WIN_CERTIFICATE_EFI_PKCS *sig, UINT8 *sha256hash, UINT8 *sha1hash) @@ -1122,9 +595,10 @@ verify_one_signature(WIN_CERTIFICATE_EFI_PKCS *sig, /* * Check that the signature is valid and matches the binary */ -static EFI_STATUS verify_buffer (char *data, int datasize, - PE_COFF_LOADER_IMAGE_CONTEXT *context, - UINT8 *sha256hash, UINT8 *sha1hash) +EFI_STATUS +verify_buffer (char *data, int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context, + UINT8 *sha256hash, UINT8 *sha1hash) { EFI_STATUS ret_efi_status; size_t size = datasize; @@ -1257,391 +731,6 @@ static EFI_STATUS verify_buffer (char *data, int datasize, return ret_efi_status; } -/* - * Read the binary header and grab appropriate information from it - */ -static EFI_STATUS read_header(void *data, unsigned int datasize, - PE_COFF_LOADER_IMAGE_CONTEXT *context) -{ - EFI_IMAGE_DOS_HEADER *DosHdr = data; - EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data; - unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize; - unsigned long FileAlignment = 0; - - if (datasize < sizeof (PEHdr->Pe32)) { - perror(L"Invalid image\n"); - return EFI_UNSUPPORTED; - } - - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) - PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew); - - if (!image_is_loadable(PEHdr)) { - perror(L"Platform does not support this image\n"); - return EFI_UNSUPPORTED; - } - - if (image_is_64_bit(PEHdr)) { - context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes; - context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders; - context->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage; - context->SectionAlignment = PEHdr->Pe32Plus.OptionalHeader.SectionAlignment; - FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment; - OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64); - } else { - context->NumberOfRvaAndSizes = PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes; - context->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders; - context->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage; - context->SectionAlignment = PEHdr->Pe32.OptionalHeader.SectionAlignment; - FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment; - OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32); - } - - if (FileAlignment % 2 != 0) { - perror(L"File Alignment is invalid (%d)\n", FileAlignment); - return EFI_UNSUPPORTED; - } - if (FileAlignment == 0) - FileAlignment = 0x200; - if (context->SectionAlignment == 0) - context->SectionAlignment = PAGE_SIZE; - if (context->SectionAlignment < FileAlignment) - context->SectionAlignment = FileAlignment; - - context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections; - - if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < context->NumberOfRvaAndSizes) { - perror(L"Image header too small\n"); - return EFI_UNSUPPORTED; - } - - HeaderWithoutDataDir = OptHeaderSize - - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES; - if (((UINT32)PEHdr->Pe32.FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) != - context->NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) { - perror(L"Image header overflows data directory\n"); - return EFI_UNSUPPORTED; - } - - SectionHeaderOffset = DosHdr->e_lfanew - + sizeof (UINT32) - + sizeof (EFI_IMAGE_FILE_HEADER) - + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader; - if (((UINT32)context->ImageSize - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER - <= context->NumberOfSections) { - perror(L"Image sections overflow image size\n"); - return EFI_UNSUPPORTED; - } - - if ((context->SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER - < (UINT32)context->NumberOfSections) { - perror(L"Image sections overflow section headers\n"); - return EFI_UNSUPPORTED; - } - - if ((((UINT8 *)PEHdr - (UINT8 *)data) + sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION)) > datasize) { - perror(L"Invalid image\n"); - return EFI_UNSUPPORTED; - } - - if (PEHdr->Te.Signature != EFI_IMAGE_NT_SIGNATURE) { - perror(L"Unsupported image type\n"); - return EFI_UNSUPPORTED; - } - - if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) { - perror(L"Unsupported image - Relocations have been stripped\n"); - return EFI_UNSUPPORTED; - } - - context->PEHdr = PEHdr; - - if (image_is_64_bit(PEHdr)) { - context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase; - context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint; - context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; - context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; - } else { - context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase; - context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint; - context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; - context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; - } - - context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER)); - - if (context->ImageSize < context->SizeOfHeaders) { - perror(L"Invalid image\n"); - return EFI_UNSUPPORTED; - } - - if ((unsigned long)((UINT8 *)context->SecDir - (UINT8 *)data) > - (datasize - sizeof(EFI_IMAGE_DATA_DIRECTORY))) { - perror(L"Invalid image\n"); - return EFI_UNSUPPORTED; - } - - if (context->SecDir->VirtualAddress > datasize || - (context->SecDir->VirtualAddress == datasize && - context->SecDir->Size > 0)) { - perror(L"Malformed 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_image (void *data, unsigned int datasize, - EFI_LOADED_IMAGE *li, - EFI_IMAGE_ENTRY_POINT *entry_point, - EFI_PHYSICAL_ADDRESS *alloc_address, - UINTN *alloc_pages) -{ - EFI_STATUS efi_status; - char *buffer; - int i; - EFI_IMAGE_SECTION_HEADER *Section; - char *base, *end; - PE_COFF_LOADER_IMAGE_CONTEXT context; - unsigned int alignment, alloc_size; - int found_entry_point = 0; - UINT8 sha1hash[SHA1_DIGEST_SIZE]; - UINT8 sha256hash[SHA256_DIGEST_SIZE]; - - /* - * The binary header contains relevant context and section pointers - */ - efi_status = read_header(data, datasize, &context); - if (EFI_ERROR(efi_status)) { - perror(L"Failed to read header: %r\n", efi_status); - return efi_status; - } - - /* - * We only need to verify the binary if we're in secure mode - */ - efi_status = generate_hash(data, datasize, &context, sha256hash, - sha1hash); - if (EFI_ERROR(efi_status)) - return efi_status; - - /* Measure the binary into the TPM */ -#ifdef REQUIRE_TPM - efi_status = -#endif - tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize, - (EFI_PHYSICAL_ADDRESS)(UINTN)context.ImageAddress, - li->FilePath, sha1hash, 4); -#ifdef REQUIRE_TPM - if (efi_status != EFI_SUCCESS) { - return efi_status; - } -#endif - - if (secure_mode ()) { - efi_status = verify_buffer(data, datasize, &context, - sha256hash, sha1hash); - - if (EFI_ERROR(efi_status)) { - if (verbose) - console_print(L"Verification failed: %r\n", efi_status); - else - console_error(L"Verification failed", efi_status); - return efi_status; - } else { - if (verbose) - console_print(L"Verification succeeded\n"); - } - } - - /* The spec says, uselessly, of SectionAlignment: - * ===== - * The alignment (in bytes) of sections when they are loaded into - * memory. It must be greater than or equal to FileAlignment. The - * default is the page size for the architecture. - * ===== - * Which doesn't tell you whose responsibility it is to enforce the - * "default", or when. It implies that the value in the field must - * be > FileAlignment (also poorly defined), but it appears visual - * studio will happily write 512 for FileAlignment (its default) and - * 0 for SectionAlignment, intending to imply PAGE_SIZE. - * - * We only support one page size, so if it's zero, nerf it to 4096. - */ - alignment = context.SectionAlignment; - if (!alignment) - alignment = 4096; - - alloc_size = ALIGN_VALUE(context.ImageSize + context.SectionAlignment, - PAGE_SIZE); - *alloc_pages = alloc_size / PAGE_SIZE; - - efi_status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderCode, - *alloc_pages, alloc_address); - if (EFI_ERROR(efi_status)) { - perror(L"Failed to allocate image buffer\n"); - return EFI_OUT_OF_RESOURCES; - } - - buffer = (void *)ALIGN_VALUE((unsigned long)*alloc_address, alignment); - - CopyMem(buffer, data, context.SizeOfHeaders); - - *entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint); - if (!*entry_point) { - perror(L"Entry point is invalid\n"); - gBS->FreePages(*alloc_address, *alloc_pages); - return EFI_UNSUPPORTED; - } - - - char *RelocBase, *RelocBaseEnd; - /* - * These are relative virtual addresses, so we have to check them - * against the image size, not the data size. - */ - RelocBase = ImageAddress(buffer, context.ImageSize, - context.RelocDir->VirtualAddress); - /* - * RelocBaseEnd here is the address of the last byte of the table - */ - RelocBaseEnd = ImageAddress(buffer, context.ImageSize, - context.RelocDir->VirtualAddress + - context.RelocDir->Size - 1); - - EFI_IMAGE_SECTION_HEADER *RelocSection = NULL; - - /* - * Copy the executable's sections to their desired offsets - */ - Section = context.FirstSection; - for (i = 0; i < context.NumberOfSections; i++, Section++) { - /* Don't try to copy discardable sections with zero size */ - if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) && - !Section->Misc.VirtualSize) - continue; - - base = ImageAddress (buffer, context.ImageSize, - Section->VirtualAddress); - end = ImageAddress (buffer, context.ImageSize, - Section->VirtualAddress - + Section->Misc.VirtualSize - 1); - - if (end < base) { - perror(L"Section %d has negative size\n", i); - gBS->FreePages(*alloc_address, *alloc_pages); - return EFI_UNSUPPORTED; - } - - if (Section->VirtualAddress <= context.EntryPoint && - (Section->VirtualAddress + Section->SizeOfRawData - 1) - > context.EntryPoint) - found_entry_point++; - - /* We do want to process .reloc, but it's often marked - * discardable, so we don't want to memcpy it. */ - if (CompareMem(Section->Name, ".reloc\0\0", 8) == 0) { - if (RelocSection) { - perror(L"Image has multiple relocation sections\n"); - return EFI_UNSUPPORTED; - } - /* If it has nonzero sizes, and our bounds check - * made sense, and the VA and size match RelocDir's - * versions, then we believe in this section table. */ - if (Section->SizeOfRawData && - Section->Misc.VirtualSize && - base && end && - RelocBase == base && - RelocBaseEnd == end) { - RelocSection = Section; - } - } - - if (Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) { - continue; - } - - if (!base) { - perror(L"Section %d has invalid base address\n", i); - return EFI_UNSUPPORTED; - } - if (!end) { - perror(L"Section %d has zero size\n", i); - return EFI_UNSUPPORTED; - } - - if (!(Section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) && - (Section->VirtualAddress < context.SizeOfHeaders || - Section->PointerToRawData < context.SizeOfHeaders)) { - perror(L"Section %d is inside image headers\n", i); - return EFI_UNSUPPORTED; - } - - if (Section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) { - ZeroMem(base, Section->Misc.VirtualSize); - } else { - if (Section->PointerToRawData < context.SizeOfHeaders) { - perror(L"Section %d is inside image headers\n", i); - return EFI_UNSUPPORTED; - } - - if (Section->SizeOfRawData > 0) - CopyMem(base, data + Section->PointerToRawData, - Section->SizeOfRawData); - - if (Section->SizeOfRawData < Section->Misc.VirtualSize) - ZeroMem(base + Section->SizeOfRawData, - Section->Misc.VirtualSize - Section->SizeOfRawData); - } - } - - if (context.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { - perror(L"Image has no relocation entry\n"); - FreePool(buffer); - return EFI_UNSUPPORTED; - } - - if (context.RelocDir->Size && RelocSection) { - /* - * Run the relocation fixups - */ - efi_status = relocate_coff(&context, RelocSection, data, - buffer); - - if (EFI_ERROR(efi_status)) { - perror(L"Relocation failed: %r\n", efi_status); - FreePool(buffer); - return efi_status; - } - } - - /* - * grub needs to know its location and size in memory, so fix up - * the loaded image protocol values - */ - li->ImageBase = buffer; - li->ImageSize = context.ImageSize; - - /* Pass the load options to the second stage loader */ - if ( load_options ) { - li->LoadOptions = load_options; - li->LoadOptionsSize = load_options_size; - } - - if (!found_entry_point) { - perror(L"Entry point is not within sections\n"); - return EFI_UNSUPPORTED; - } - if (found_entry_point > 1) { - perror(L"%d sections contain entry point\n"); - return EFI_UNSUPPORTED; - } - - return EFI_SUCCESS; -} - static int should_use_fallback(EFI_HANDLE image_handle) { diff --git a/shim.h b/shim.h index 433a34d..0162229 100644 --- a/shim.h +++ b/shim.h @@ -29,6 +29,7 @@ #undef uefi_call_wrapper #include +#include #define nonnull(...) __attribute__((__nonnull__(__VA_ARGS__))) @@ -135,6 +136,7 @@ #include "include/netboot.h" #include "include/passwordcrypt.h" #include "include/peimage.h" +#include "include/pe.h" #include "include/replacements.h" #if defined(OVERRIDE_SECURITY_POLICY) #include "include/security_policy.h" @@ -204,6 +206,15 @@ extern UINT8 *build_cert; extern UINT8 user_insecure_mode; extern UINT8 ignore_db; extern UINT8 in_protocol; +extern void *load_options; +extern UINT32 load_options_size; + +BOOLEAN secure_mode (void); + +EFI_STATUS +verify_buffer (char *data, int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context, + UINT8 *sha256hash, UINT8 *sha1hash); #define perror_(file, line, func, fmt, ...) ({ \ UINTN __perror_ret = 0; \