diff --git a/.gitignore b/.gitignore
index 1515ee14..c3aef8d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,7 @@ Utilities/TestKextInject/Result.xml
Utilities/TestMacho/Macho
Utilities/TestRsaPreprocess/RsaPreprocess
Utilities/TestSmbios/Smbios
+Utilities/TestPeCoff/PeCoff
*.o
*.exe
DICT
diff --git a/Include/Acidanthera/IndustryStandard/OcPeImage.h b/Include/Acidanthera/IndustryStandard/OcPeImage.h
new file mode 100644
index 00000000..dd132bd8
--- /dev/null
+++ b/Include/Acidanthera/IndustryStandard/OcPeImage.h
@@ -0,0 +1,722 @@
+/** @file
+ EFI image format for PE32, PE32+ and TE. Please note some data structures are
+ different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and
+ EFI_IMAGE_NT_HEADERS64 is for PE32+.
+
+ This file is coded to the Visual Studio, Microsoft Portable Executable and
+ Common Object File Format Specification, Revision 8.3 - February 6, 2013.
+ This file also includes some definitions in PI Specification, Revision 1.0.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+Portions Copyright (c) 2016 - 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef OC_PE_IMAGE_H
+#define OC_PE_IMAGE_H
+
+//
+// PE32+ Subsystem type for EFI images
+//
+#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10
+#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
+#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
+#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 ///< defined PI Specification, 1.0
+
+
+//
+// PE32+ Machine type for EFI images
+//
+#define IMAGE_FILE_MACHINE_I386 0x014c
+#define IMAGE_FILE_MACHINE_IA64 0x0200
+#define IMAGE_FILE_MACHINE_EBC 0x0EBC
+#define IMAGE_FILE_MACHINE_X64 0x8664
+#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x01c2
+#define IMAGE_FILE_MACHINE_ARM64 0xAA64
+
+//
+// EXE file formats
+//
+#define EFI_IMAGE_DOS_SIGNATURE SIGNATURE_16('M', 'Z')
+#define EFI_IMAGE_OS2_SIGNATURE SIGNATURE_16('N', 'E')
+#define EFI_IMAGE_OS2_SIGNATURE_LE SIGNATURE_16('L', 'E')
+#define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0')
+
+///
+/// PE images can start with an optional DOS header, so if an image is run
+/// under DOS it can print an error message.
+///
+typedef struct {
+ UINT16 e_magic; ///< Magic number.
+ UINT16 e_cblp; ///< Bytes on last page of file.
+ UINT16 e_cp; ///< Pages in file.
+ UINT16 e_crlc; ///< Relocations.
+ UINT16 e_cparhdr; ///< Size of header in paragraphs.
+ UINT16 e_minalloc; ///< Minimum extra paragraphs needed.
+ UINT16 e_maxalloc; ///< Maximum extra paragraphs needed.
+ UINT16 e_ss; ///< Initial (relative) SS value.
+ UINT16 e_sp; ///< Initial SP value.
+ UINT16 e_csum; ///< Checksum.
+ UINT16 e_ip; ///< Initial IP value.
+ UINT16 e_cs; ///< Initial (relative) CS value.
+ UINT16 e_lfarlc; ///< File address of relocation table.
+ UINT16 e_ovno; ///< Overlay number.
+ UINT16 e_res[4]; ///< Reserved words.
+ UINT16 e_oemid; ///< OEM identifier (for e_oeminfo).
+ UINT16 e_oeminfo; ///< OEM information; e_oemid specific.
+ UINT16 e_res2[10]; ///< Reserved words.
+ UINT32 e_lfanew; ///< File address of new exe header.
+} EFI_IMAGE_DOS_HEADER;
+
+///
+/// COFF File Header (Object and Image).
+///
+typedef struct {
+ UINT16 Machine;
+ UINT16 NumberOfSections;
+ UINT32 TimeDateStamp;
+ UINT32 PointerToSymbolTable;
+ UINT32 NumberOfSymbols;
+ UINT16 SizeOfOptionalHeader;
+ UINT16 Characteristics;
+} EFI_IMAGE_FILE_HEADER;
+
+///
+/// Size of EFI_IMAGE_FILE_HEADER.
+///
+#define EFI_IMAGE_SIZEOF_FILE_HEADER 20
+
+//
+// Characteristics
+//
+#define EFI_IMAGE_FILE_RELOCS_STRIPPED 1 ///< 0x0001 Relocation info stripped from file.
+
+///
+/// Header Data Directories.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 Size;
+} EFI_IMAGE_DATA_DIRECTORY;
+
+//
+// Directory Entries
+//
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0
+#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1
+#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
+#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4
+#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5
+#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6
+#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
+#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
+#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9
+#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
+
+#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and
+/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and
+/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+
+
+///
+/// @attention
+/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools.
+///
+typedef struct {
+ UINT32 Signature;
+ EFI_IMAGE_FILE_HEADER FileHeader;
+} EFI_IMAGE_NT_HEADERS_COMMON_HDR;
+
+STATIC_ASSERT (
+ sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) == sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER),
+ "Unsupported padding."
+ );
+
+///
+/// @attention
+/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools.
+///
+typedef struct {
+ EFI_IMAGE_NT_HEADERS_COMMON_HDR CommonHeader;
+ ///
+ /// Standard fields.
+ ///
+ UINT16 Magic;
+ UINT8 MajorLinkerVersion;
+ UINT8 MinorLinkerVersion;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializedData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ UINT32 BaseOfData; ///< PE32 contains this additional field, which is absent in PE32+.
+ ///
+ /// Optional Header Windows-Specific Fields.
+ ///
+ UINT32 ImageBase;
+ UINT32 SectionAlignment;
+ UINT32 FileAlignment;
+ UINT16 MajorOperatingSystemVersion;
+ UINT16 MinorOperatingSystemVersion;
+ UINT16 MajorImageVersion;
+ UINT16 MinorImageVersion;
+ UINT16 MajorSubsystemVersion;
+ UINT16 MinorSubsystemVersion;
+ UINT32 Win32VersionValue;
+ UINT32 SizeOfImage;
+ UINT32 SizeOfHeaders;
+ UINT32 CheckSum;
+ UINT16 Subsystem;
+ UINT16 DllCharacteristics;
+ UINT32 SizeOfStackReserve;
+ UINT32 SizeOfStackCommit;
+ UINT32 SizeOfHeapReserve;
+ UINT32 SizeOfHeapCommit;
+ UINT32 LoaderFlags;
+ UINT32 NumberOfRvaAndSizes;
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[];
+} EFI_IMAGE_NT_HEADERS32;
+
+///
+/// @attention
+/// EFI_IMAGE_HEADERS64 is for use ONLY by tools.
+///
+typedef struct {
+ EFI_IMAGE_NT_HEADERS_COMMON_HDR CommonHeader;
+ ///
+ /// Standard fields.
+ ///
+ UINT16 Magic;
+ UINT8 MajorLinkerVersion;
+ UINT8 MinorLinkerVersion;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializedData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ ///
+ /// Optional Header Windows-Specific Fields.
+ ///
+ UINT64 ImageBase;
+ UINT32 SectionAlignment;
+ UINT32 FileAlignment;
+ UINT16 MajorOperatingSystemVersion;
+ UINT16 MinorOperatingSystemVersion;
+ UINT16 MajorImageVersion;
+ UINT16 MinorImageVersion;
+ UINT16 MajorSubsystemVersion;
+ UINT16 MinorSubsystemVersion;
+ UINT32 Win32VersionValue;
+ UINT32 SizeOfImage;
+ UINT32 SizeOfHeaders;
+ UINT32 CheckSum;
+ UINT16 Subsystem;
+ UINT16 DllCharacteristics;
+ UINT64 SizeOfStackReserve;
+ UINT64 SizeOfStackCommit;
+ UINT64 SizeOfHeapReserve;
+ UINT64 SizeOfHeapCommit;
+ UINT32 LoaderFlags;
+ UINT32 NumberOfRvaAndSizes;
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[];
+} EFI_IMAGE_NT_HEADERS64;
+
+//
+// Other Windows Subsystem Values
+//
+#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0
+#define EFI_IMAGE_SUBSYSTEM_NATIVE 1
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3
+#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5
+#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7
+
+///
+/// Length of ShortName.
+///
+#define EFI_IMAGE_SIZEOF_SHORT_NAME 8
+
+///
+/// Section Table. This table immediately follows the optional header.
+///
+typedef struct {
+ UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME];
+ UINT32 VirtualSize;
+ UINT32 VirtualAddress;
+ UINT32 SizeOfRawData;
+ UINT32 PointerToRawData;
+ UINT32 PointerToRelocations;
+ UINT32 PointerToLinenumbers;
+ UINT16 NumberOfRelocations;
+ UINT16 NumberOfLinenumbers;
+ UINT32 Characteristics;
+} EFI_IMAGE_SECTION_HEADER;
+
+//
+// Section Flags Values
+//
+#define EFI_IMAGE_SCN_TYPE_NO_PAD BIT3 ///< 0x00000008 ///< Reserved.
+#define EFI_IMAGE_SCN_CNT_CODE BIT5 ///< 0x00000020
+#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA BIT6 ///< 0x00000040
+#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA BIT7 ///< 0x00000080
+
+#define EFI_IMAGE_SCN_LNK_OTHER BIT8 ///< 0x00000100 ///< Reserved.
+#define EFI_IMAGE_SCN_LNK_INFO BIT9 ///< 0x00000200 ///< Section contains comments or some other type of information.
+#define EFI_IMAGE_SCN_LNK_REMOVE BIT11 ///< 0x00000800 ///< Section contents will not become part of image.
+#define EFI_IMAGE_SCN_LNK_COMDAT BIT12 ///< 0x00001000
+
+#define EFI_IMAGE_SCN_ALIGN_1BYTES BIT20 ///< 0x00100000
+#define EFI_IMAGE_SCN_ALIGN_2BYTES BIT21 ///< 0x00200000
+#define EFI_IMAGE_SCN_ALIGN_4BYTES (BIT20|BIT21) ///< 0x00300000
+#define EFI_IMAGE_SCN_ALIGN_8BYTES BIT22 ///< 0x00400000
+#define EFI_IMAGE_SCN_ALIGN_16BYTES (BIT20|BIT22) ///< 0x00500000
+#define EFI_IMAGE_SCN_ALIGN_32BYTES (BIT21|BIT22) ///< 0x00600000
+#define EFI_IMAGE_SCN_ALIGN_64BYTES (BIT20|BIT21|BIT22) ///< 0x00700000
+
+#define EFI_IMAGE_SCN_MEM_DISCARDABLE BIT25 ///< 0x02000000
+#define EFI_IMAGE_SCN_MEM_NOT_CACHED BIT26 ///< 0x04000000
+#define EFI_IMAGE_SCN_MEM_NOT_PAGED BIT27 ///< 0x08000000
+#define EFI_IMAGE_SCN_MEM_SHARED BIT28 ///< 0x10000000
+#define EFI_IMAGE_SCN_MEM_EXECUTE BIT29 ///< 0x20000000
+#define EFI_IMAGE_SCN_MEM_READ BIT30 ///< 0x40000000
+#define EFI_IMAGE_SCN_MEM_WRITE BIT31 ///< 0x80000000
+
+///
+/// Size of a Symbol Table Record.
+///
+#define EFI_IMAGE_SIZEOF_SYMBOL 18
+
+//
+// Symbols have a section number of the section in which they are
+// defined. Otherwise, section numbers have the following meanings:
+//
+#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 ///< Symbol is undefined or is common.
+#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 ///< Symbol is an absolute value.
+#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 ///< Symbol is a special debug item.
+
+//
+// Symbol Type (fundamental) values.
+//
+#define EFI_IMAGE_SYM_TYPE_NULL 0 ///< no type.
+#define EFI_IMAGE_SYM_TYPE_VOID 1 ///< no valid type.
+#define EFI_IMAGE_SYM_TYPE_CHAR 2 ///< type character.
+#define EFI_IMAGE_SYM_TYPE_SHORT 3 ///< type short integer.
+#define EFI_IMAGE_SYM_TYPE_INT 4
+#define EFI_IMAGE_SYM_TYPE_LONG 5
+#define EFI_IMAGE_SYM_TYPE_FLOAT 6
+#define EFI_IMAGE_SYM_TYPE_DOUBLE 7
+#define EFI_IMAGE_SYM_TYPE_STRUCT 8
+#define EFI_IMAGE_SYM_TYPE_UNION 9
+#define EFI_IMAGE_SYM_TYPE_ENUM 10 ///< enumeration.
+#define EFI_IMAGE_SYM_TYPE_MOE 11 ///< member of enumeration.
+#define EFI_IMAGE_SYM_TYPE_BYTE 12
+#define EFI_IMAGE_SYM_TYPE_WORD 13
+#define EFI_IMAGE_SYM_TYPE_UINT 14
+#define EFI_IMAGE_SYM_TYPE_DWORD 15
+
+//
+// Symbol Type (derived) values.
+//
+#define EFI_IMAGE_SYM_DTYPE_NULL 0 ///< no derived type.
+#define EFI_IMAGE_SYM_DTYPE_POINTER 1
+#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2
+#define EFI_IMAGE_SYM_DTYPE_ARRAY 3
+
+//
+// Storage classes.
+//
+#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION ((UINT8) -1)
+#define EFI_IMAGE_SYM_CLASS_NULL 0
+#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2
+#define EFI_IMAGE_SYM_CLASS_STATIC 3
+#define EFI_IMAGE_SYM_CLASS_REGISTER 4
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define EFI_IMAGE_SYM_CLASS_LABEL 6
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9
+#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12
+#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18
+#define EFI_IMAGE_SYM_CLASS_BLOCK 100
+#define EFI_IMAGE_SYM_CLASS_FUNCTION 101
+#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define EFI_IMAGE_SYM_CLASS_FILE 103
+#define EFI_IMAGE_SYM_CLASS_SECTION 104
+#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+
+//
+// type packing constants
+//
+#define EFI_IMAGE_N_BTMASK 017
+#define EFI_IMAGE_N_TMASK 060
+#define EFI_IMAGE_N_TMASK1 0300
+#define EFI_IMAGE_N_TMASK2 0360
+#define EFI_IMAGE_N_BTSHFT 4
+#define EFI_IMAGE_N_TSHIFT 2
+
+//
+// Communal selection types.
+//
+#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1
+#define EFI_IMAGE_COMDAT_SELECT_ANY 2
+#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3
+#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4
+#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5
+
+//
+// the following values only be referred in PeCoff, not defined in PECOFF.
+//
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3
+
+///
+/// Relocation format.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 SymbolTableIndex;
+ UINT16 Type;
+} EFI_IMAGE_RELOCATION;
+
+///
+/// Size of EFI_IMAGE_RELOCATION
+///
+#define EFI_IMAGE_SIZEOF_RELOCATION 10
+
+//
+// I386 relocation types.
+//
+#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 ///< Reference is absolute, no relocation is necessary.
+#define EFI_IMAGE_REL_I386_DIR16 0x0001 ///< Direct 16-bit reference to the symbols virtual address.
+#define EFI_IMAGE_REL_I386_REL16 0x0002 ///< PC-relative 16-bit reference to the symbols virtual address.
+#define EFI_IMAGE_REL_I386_DIR32 0x0006 ///< Direct 32-bit reference to the symbols virtual address.
+#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 ///< Direct 32-bit reference to the symbols virtual address, base not included.
+#define EFI_IMAGE_REL_I386_SEG12 0x0009 ///< Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address.
+#define EFI_IMAGE_REL_I386_SECTION 0x000A
+#define EFI_IMAGE_REL_I386_SECREL 0x000B
+#define EFI_IMAGE_REL_I386_REL32 0x0014 ///< PC-relative 32-bit reference to the symbols virtual address.
+
+//
+// x64 processor relocation types.
+//
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
+#define IMAGE_REL_AMD64_ADDR64 0x0001
+#define IMAGE_REL_AMD64_ADDR32 0x0002
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003
+#define IMAGE_REL_AMD64_REL32 0x0004
+#define IMAGE_REL_AMD64_REL32_1 0x0005
+#define IMAGE_REL_AMD64_REL32_2 0x0006
+#define IMAGE_REL_AMD64_REL32_3 0x0007
+#define IMAGE_REL_AMD64_REL32_4 0x0008
+#define IMAGE_REL_AMD64_REL32_5 0x0009
+#define IMAGE_REL_AMD64_SECTION 0x000A
+#define IMAGE_REL_AMD64_SECREL 0x000B
+#define IMAGE_REL_AMD64_SECREL7 0x000C
+#define IMAGE_REL_AMD64_TOKEN 0x000D
+#define IMAGE_REL_AMD64_SREL32 0x000E
+#define IMAGE_REL_AMD64_PAIR 0x000F
+#define IMAGE_REL_AMD64_SSPAN32 0x0010
+
+///
+/// Based relocation format.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 SizeOfBlock;
+ UINT16 Relocations[];
+} EFI_IMAGE_BASE_RELOCATION;
+
+///
+/// Size of EFI_IMAGE_BASE_RELOCATION.
+///
+#define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8
+
+//
+// Based relocation types.
+//
+#define EFI_IMAGE_REL_BASED_ABSOLUTE 0
+#define EFI_IMAGE_REL_BASED_HIGH 1
+#define EFI_IMAGE_REL_BASED_LOW 2
+#define EFI_IMAGE_REL_BASED_HIGHLOW 3
+#define EFI_IMAGE_REL_BASED_HIGHADJ 4
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5
+#define EFI_IMAGE_REL_BASED_ARM_MOV32A 5
+#define EFI_IMAGE_REL_BASED_ARM_MOV32T 7
+#define EFI_IMAGE_REL_BASED_IA64_IMM64 9
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16 9
+#define EFI_IMAGE_REL_BASED_DIR64 10
+
+///
+/// Line number format.
+///
+typedef struct {
+ union {
+ UINT32 SymbolTableIndex; ///< Symbol table index of function name if Linenumber is 0.
+ UINT32 VirtualAddress; ///< Virtual address of line number.
+ } Type;
+ UINT16 Linenumber; ///< Line number.
+} EFI_IMAGE_LINENUMBER;
+
+///
+/// Size of EFI_IMAGE_LINENUMBER.
+///
+#define EFI_IMAGE_SIZEOF_LINENUMBER 6
+
+//
+// Archive format.
+//
+#define EFI_IMAGE_ARCHIVE_START_SIZE 8
+#define EFI_IMAGE_ARCHIVE_START "!\n"
+#define EFI_IMAGE_ARCHIVE_END "`\n"
+#define EFI_IMAGE_ARCHIVE_PAD "\n"
+#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ "
+#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// "
+
+///
+/// Archive Member Headers
+///
+typedef struct {
+ UINT8 Name[16]; ///< File member name - `/' terminated.
+ UINT8 Date[12]; ///< File member date - decimal.
+ UINT8 UserID[6]; ///< File member user id - decimal.
+ UINT8 GroupID[6]; ///< File member group id - decimal.
+ UINT8 Mode[8]; ///< File member mode - octal.
+ UINT8 Size[10]; ///< File member size - decimal.
+ UINT8 EndHeader[2]; ///< String to end header. (0x60 0x0A).
+} EFI_IMAGE_ARCHIVE_MEMBER_HEADER;
+
+///
+/// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER.
+///
+#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
+
+
+//
+// DLL Support
+//
+
+///
+/// Export Directory Table.
+///
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT16 MajorVersion;
+ UINT16 MinorVersion;
+ UINT32 Name;
+ UINT32 Base;
+ UINT32 NumberOfFunctions;
+ UINT32 NumberOfNames;
+ UINT32 AddressOfFunctions;
+ UINT32 AddressOfNames;
+ UINT32 AddressOfNameOrdinals;
+} EFI_IMAGE_EXPORT_DIRECTORY;
+
+///
+/// Hint/Name Table.
+///
+typedef struct {
+ UINT16 Hint;
+ UINT8 Name[1];
+} EFI_IMAGE_IMPORT_BY_NAME;
+
+///
+/// Import Address Table RVA (Thunk Table).
+///
+typedef struct {
+ union {
+ UINT32 Function;
+ UINT32 Ordinal;
+ EFI_IMAGE_IMPORT_BY_NAME *AddressOfData;
+ } u1;
+} EFI_IMAGE_THUNK_DATA;
+
+#define EFI_IMAGE_ORDINAL_FLAG BIT31 ///< Flag for PE32.
+#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0)
+#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff)
+
+///
+/// Import Directory Table
+///
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT32 ForwarderChain;
+ UINT32 Name;
+ EFI_IMAGE_THUNK_DATA *FirstThunk;
+} EFI_IMAGE_IMPORT_DESCRIPTOR;
+
+
+///
+/// Debug Directory Format.
+///
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT16 MajorVersion;
+ UINT16 MinorVersion;
+ UINT32 Type;
+ UINT32 SizeOfData;
+ UINT32 RVA; ///< The address of the debug data when loaded, relative to the image base.
+ UINT32 FileOffset; ///< The file pointer to the debug data.
+} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
+
+#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information.
+
+///
+/// Debug Data Structure defined in Microsoft C++.
+///
+#define CODEVIEW_SIGNATURE_NB10 SIGNATURE_32('N', 'B', '1', '0')
+typedef struct {
+ UINT32 Signature; ///< "NB10"
+ UINT32 Unknown;
+ UINT32 Unknown2;
+ UINT32 Unknown3;
+ //
+ // Filename of .PDB goes here
+ //
+} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY;
+
+///
+/// Debug Data Structure defined in Microsoft C++.
+///
+#define CODEVIEW_SIGNATURE_RSDS SIGNATURE_32('R', 'S', 'D', 'S')
+typedef struct {
+ UINT32 Signature; ///< "RSDS".
+ UINT32 Unknown;
+ UINT32 Unknown2;
+ UINT32 Unknown3;
+ UINT32 Unknown4;
+ UINT32 Unknown5;
+ //
+ // Filename of .PDB goes here
+ //
+} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY;
+
+
+///
+/// Debug Data Structure defined by Apple Mach-O to Coff utility.
+///
+#define CODEVIEW_SIGNATURE_MTOC SIGNATURE_32('M', 'T', 'O', 'C')
+typedef struct {
+ UINT32 Signature; ///< "MTOC".
+ UINT64 MachOUuid[2];
+ //
+ // Filename of .DLL (Mach-O with debug info) goes here
+ //
+} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY;
+
+///
+/// Resource directory entry format.
+///
+typedef struct {
+ union {
+ struct {
+ UINT32 NameOffset:31;
+ UINT32 NameIsString:1;
+ } s;
+ UINT32 Id;
+ } u1;
+ union {
+ UINT32 OffsetToData;
+ struct {
+ UINT32 OffsetToDirectory:31;
+ UINT32 DataIsDirectory:1;
+ } s;
+ } u2;
+} EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY;
+
+///
+/// Resource format.
+///
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT16 MajorVersion;
+ UINT16 MinorVersion;
+ UINT16 NumberOfNamedEntries;
+ UINT16 NumberOfIdEntries;
+ EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY Entires[];
+} EFI_IMAGE_RESOURCE_DIRECTORY;
+
+///
+/// Resource directory entry for string.
+///
+typedef struct {
+ UINT16 Length;
+ CHAR16 String[1];
+} EFI_IMAGE_RESOURCE_DIRECTORY_STRING;
+
+///
+/// Resource directory entry for data array.
+///
+typedef struct {
+ UINT32 OffsetToData;
+ UINT32 Size;
+ UINT32 CodePage;
+ UINT32 Reserved;
+} EFI_IMAGE_RESOURCE_DATA_ENTRY;
+
+///
+/// Header format for TE images, defined in the PI Specification, 1.0.
+///
+typedef struct {
+ UINT16 Signature; ///< The signature for TE format = "VZ".
+ UINT16 Machine; ///< From the original file header.
+ UINT8 NumberOfSections; ///< From the original file header.
+ UINT8 Subsystem; ///< From original optional header.
+ UINT16 StrippedSize; ///< Number of bytes we removed from the header.
+ UINT32 AddressOfEntryPoint; ///< Offset to entry point -- from original optional header.
+ UINT32 BaseOfCode; ///< From original image -- required for ITP debug.
+ UINT64 ImageBase; ///< From original file header.
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; ///< Only base relocation and debug directory.
+} EFI_TE_IMAGE_HEADER;
+
+
+#define EFI_TE_IMAGE_HEADER_SIGNATURE SIGNATURE_16('V', 'Z')
+
+//
+// Data directory indexes in our TE image header
+//
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1
+
+
+///
+/// Union of PE32, PE32+, and TE headers.
+///
+typedef union {
+ EFI_IMAGE_NT_HEADERS_COMMON_HDR PeCommon;
+ EFI_IMAGE_NT_HEADERS32 Pe32;
+ EFI_IMAGE_NT_HEADERS64 Pe32Plus;
+ EFI_TE_IMAGE_HEADER Te;
+} EFI_IMAGE_OPTIONAL_HEADER_UNION;
+
+#endif // OC_PE_IMAGE_H
diff --git a/Include/Acidanthera/Library/OcAppleSecureBootLib.h b/Include/Acidanthera/Library/OcAppleSecureBootLib.h
index 7336ddcb..30d08e85 100644
--- a/Include/Acidanthera/Library/OcAppleSecureBootLib.h
+++ b/Include/Acidanthera/Library/OcAppleSecureBootLib.h
@@ -72,11 +72,13 @@ OcAppleSecureBootSetDmgLoading (
/**
Get DMG loading status on Apple Secure Boot protocol.
+ @param[out] RealPolicy Actual secure boot policy, optional.
+
@retval TRUE when loading DMG.
**/
BOOLEAN
OcAppleSecureBootGetDmgLoading (
- VOID
+ OUT UINT8 *RealPolicy OPTIONAL
);
/**
diff --git a/Include/Acidanthera/Library/OcBootManagementLib.h b/Include/Acidanthera/Library/OcBootManagementLib.h
index fa619af2..a339f3a8 100755
--- a/Include/Acidanthera/Library/OcBootManagementLib.h
+++ b/Include/Acidanthera/Library/OcBootManagementLib.h
@@ -1238,4 +1238,43 @@ OcRegisterBootOption (
IN CONST CHAR16 *FilePath
);
+/**
+ Initialises custom Boot Services overrides to support direct images.
+**/
+VOID
+OcInitDirectImageLoader (
+ VOID
+ );
+
+/**
+ Make DirectImageLoader the default for Apple Secure Boot.
+**/
+VOID
+OcActivateDirectImageLoader (
+ VOID
+ );
+
+/**
+ Simplified load image routine, which bypasses UEFI and loads the image directly.
+
+ @param[in] BootPolicy Ignored.
+ @param[in] ParentImageHandle The caller's image handle.
+ @param[in] DevicePath Ignored.
+ @param[in] SourceBuffer Pointer to the memory location containing image to be loaded.
+ @param[in] SourceSize The size in bytes of SourceBuffer.
+ @param[out] ImageHandle The pointer to the returned image handle created on success.
+
+ @retval EFI_SUCCESS on success.
+**/
+EFI_STATUS
+EFIAPI
+OcDirectLoadImage (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ );
+
#endif // OC_BOOT_MANAGEMENT_LIB_H
diff --git a/Include/Acidanthera/Library/OcGuardLib.h b/Include/Acidanthera/Library/OcGuardLib.h
index 29b1d623..9f08de46 100644
--- a/Include/Acidanthera/Library/OcGuardLib.h
+++ b/Include/Acidanthera/Library/OcGuardLib.h
@@ -109,6 +109,13 @@ OcOverflowMulAddU32 (
UINT32 *Result
);
+BOOLEAN
+OcOverflowAlignUpU32 (
+ UINT32 Value,
+ UINT32 Alignment,
+ UINT32 *Result
+ );
+
BOOLEAN
OcOverflowAddS32 (
INT32 A,
diff --git a/Include/Acidanthera/Library/OcPeCoffLib.h b/Include/Acidanthera/Library/OcPeCoffLib.h
new file mode 100644
index 00000000..f38b4cf1
--- /dev/null
+++ b/Include/Acidanthera/Library/OcPeCoffLib.h
@@ -0,0 +1,198 @@
+/** @file
+ Provides services to load and relocate a PE/COFF image.
+
+ The PE/COFF Loader Library abstracts the implementation of a PE/COFF loader for
+ IA-32, x86, and EBC processor types. The library functions are memory-based
+ and can be ported easily to any environment.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef OC_PE_COFF_LIB_H
+#define OC_PE_COFF_LIB_H
+
+#include
+
+// TODO: move?
+/**
+ Performs digest on a data buffer of the specified length. This function can
+ be called multiple times to compute the digest of long or discontinuous data streams.
+
+ If HashContext is NULL, then ASSERT().
+
+ @param[in,out] HashContext Pointer to the MD5 context.
+ @param[in] Data Pointer to the buffer containing the data to be hashed.
+ @param[in] DataLength Length of Data buffer in bytes.
+
+ @retval TRUE HASH data digest succeeded.
+ @retval FALSE Invalid HASH context. After HashFinal function has been called, the
+ HASH context cannot be reused.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *HASH_UPDATE)(
+ IN OUT VOID *HashContext,
+ IN CONST VOID *Data,
+ IN UINTN DataLength
+ );
+
+//
+// Return status codes from the PE/COFF Loader services
+//
+#define IMAGE_ERROR_SUCCESS 0U
+#define IMAGE_ERROR_IMAGE_READ 1U
+#define IMAGE_ERROR_INVALID_PE_HEADER_SIGNATURE 2U
+#define IMAGE_ERROR_INVALID_MACHINE_TYPE 3U
+#define IMAGE_ERROR_INVALID_SUBSYSTEM 4U
+#define IMAGE_ERROR_INVALID_IMAGE_ADDRESS 5U
+#define IMAGE_ERROR_INVALID_IMAGE_SIZE 6U
+#define IMAGE_ERROR_INVALID_SECTION_ALIGNMENT 7U
+#define IMAGE_ERROR_SECTION_NOT_LOADED 8U
+#define IMAGE_ERROR_FAILED_RELOCATION 9U
+#define IMAGE_ERROR_FAILED_ICACHE_FLUSH 10U
+#define IMAGE_ERROR_UNSUPPORTED 11U
+
+typedef UINTN IMAGE_STATUS;
+
+typedef enum {
+ ImageTypeTe,
+ ImageTypePe32,
+ ImageTypePe32Plus,
+ ImageTypeMax
+} IMAGE_LOADER_IMAGE_TYPE;
+
+///
+/// The context structure used while PE/COFF image is being loaded and relocated.
+///
+typedef struct {
+ ///
+ /// Set by OcPeCoffLoaderInitializeContext() to the ImageBase in the PE/COFF header.
+ ///
+ UINT64 ImageBase;
+ //
+ // Before LoadImage returns, a pointer to the raw file image.
+ // After LoadImage returns, a pointer to the loaded image.
+ //
+ VOID *FileBuffer;
+ ///
+ /// Set by OcPeCoffLoaderInitializeContext() to the SizeOfImage in the PE/COFF header.
+ /// Image size includes the size of Debug Entry if it is present.
+ ///
+ UINT32 SizeOfImage;
+ UINT32 SectionAlignment;
+ ///
+ /// Set by OcPeCoffLoaderInitializeContext() to offset to the PE/COFF header.
+ /// If the PE/COFF image does not start with a DOS header, this value is zero.
+ /// Otherwise, it's the offset to the PE/COFF header.
+ ///
+ UINT32 ExeHdrOffset;
+ ///
+ /// Is set by OcPeCoffLoaderInitializeContext() to the Section Alignment in the PE/COFF header.
+ ///
+ UINT32 SizeOfHeaders;
+ UINT32 AddressOfEntryPoint;
+ ///
+ /// Set by OcPeCoffLoaderInitializeContext() to TRUE if the PE/COFF image does not contain
+ /// relocation information.
+ ///
+ BOOLEAN RelocsStripped;
+ ///
+ /// Set by OcPeCoffLoaderInitializeContext() to TRUE if the image is a TE image.
+ /// For a definition of the TE Image format, see the Platform Initialization Pre-EFI
+ /// Initialization Core Interface Specification.
+ ///
+ UINT8 ImageType;
+ UINT16 Subsystem;
+ UINT16 Machine;
+ UINT32 TeStrippedOffset;
+
+ UINT32 RelocDirRva;
+ UINT32 RelocDirSize;
+} PE_COFF_LOADER_IMAGE_CONTEXT;
+
+/**
+ Retrieves information about a PE/COFF image.
+
+ Computes the ExeHdrOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
+ DestinationAddress, RelocsStripped, SectionAlignment, SizeOfHeaders, and
+ DebugDirectoryEntryRva fields of the ImageContext structure.
+ If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
+ If the PE/COFF image accessed through the ImageRead service in the ImageContext
+ structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
+ If any errors occur while computing the fields of ImageContext,
+ then the error status is returned in the ImageError field of ImageContext.
+ If the image is a TE image, then SectionAlignment is set to 0.
+ The ImageRead and Handle fields of ImageContext structure must be valid prior
+ to invoking this service.
+
+ @param ImageContext The pointer to the image context structure that
+ describes the PE/COFF image that needs to be
+ examined by this function.
+
+ @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
+ @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
+ @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
+
+**/
+IMAGE_STATUS
+OcPeCoffLoaderInitializeContext (
+ OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN CONST VOID *FileBuffer,
+ IN UINTN FileSize
+ );
+
+/**
+ Loads a PE/COFF image into memory.
+
+ Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
+ specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
+ the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
+ The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
+ The ImageRead, Handle, ExeHdrOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
+ DestinationAddress, RelocsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
+ fields of the ImageContext structure must be valid prior to invoking this service.
+
+ If ImageContext is NULL, then ASSERT().
+
+ Note that if the platform does not maintain coherency between the instruction cache(s) and the data
+ cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
+ prior to transferring control to a PE/COFF image that is loaded using this library.
+
+ @param ImageContext The pointer to the image context structure that describes the PE/COFF
+ image that is being loaded.
+
+ @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
+ the ImageAddress and ImageSize fields of ImageContext.
+ Extended status information is in the ImageError field of ImageContext.
+ @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
+ Extended status information is in the ImageError field of ImageContext.
+ @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
+ Extended status information is in the ImageError field of ImageContext.
+ @retval RETURN_INVALID_PARAMETER The image address is invalid.
+ Extended status information is in the ImageError field of ImageContext.
+
+**/
+IMAGE_STATUS
+OcPeCoffLoaderLoadImage (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ OUT VOID *Destination,
+ IN UINT32 DestinationSize
+ );
+
+IMAGE_STATUS
+OcPeCoffLoaderRelocateImage (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINTN BaseAddress
+ );
+
+BOOLEAN
+OcPeCoffLoaderHashImage (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN HASH_UPDATE HashUpdate,
+ IN OUT VOID *HashContext
+ );
+
+#endif // OC_PE_COFF_LIB_H
diff --git a/Library/OcApfsLib/OcApfsConnect.c b/Library/OcApfsLib/OcApfsConnect.c
index ca7ef3f0..adb42824 100644
--- a/Library/OcApfsLib/OcApfsConnect.c
+++ b/Library/OcApfsLib/OcApfsConnect.c
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -239,6 +240,9 @@ ApfsStartDriver (
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_HANDLE ImageHandle;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_IMAGE_LOAD LoadImage;
+ APPLE_SECURE_BOOT_PROTOCOL *SecureBoot;
+ UINT8 Policy;
Status = VerifyApplePeImageSignature (
DriverBuffer,
@@ -272,8 +276,26 @@ ApfsStartDriver (
DevicePath = NULL;
}
+ SecureBoot = OcAppleSecureBootGetProtocol ();
+ ASSERT (SecureBoot != NULL);
+ Status = SecureBoot->GetPolicy (
+ SecureBoot,
+ &Policy
+ );
+ //
+ // Load directly when we have Apple Secure Boot.
+ // - Either normal.
+ // - Or during DMG loading.
+ //
+ if ((!EFI_ERROR (Status) && Policy != AppleImg4SbModeDisabled)
+ || (OcAppleSecureBootGetDmgLoading (&Policy) && Policy != AppleImg4SbModeDisabled)) {
+ LoadImage = OcDirectLoadImage;
+ } else {
+ LoadImage = gBS->LoadImage;
+ }
+
ImageHandle = NULL;
- Status = gBS->LoadImage (
+ Status = LoadImage (
FALSE,
gImageHandle,
DevicePath,
diff --git a/Library/OcAppleSecureBootLib/OcAppleSecureBootLib.c b/Library/OcAppleSecureBootLib/OcAppleSecureBootLib.c
index 9cb66b9e..efbe313a 100644
--- a/Library/OcAppleSecureBootLib/OcAppleSecureBootLib.c
+++ b/Library/OcAppleSecureBootLib/OcAppleSecureBootLib.c
@@ -37,6 +37,7 @@ STATIC APPLE_SECURE_BOOT_PROTOCOL *mSecureBoot;
STATIC CHAR8 mSbHardwareModel[16];
STATIC UINT64 mSbEcid;
STATIC BOOLEAN mDmgLoading = FALSE;
+STATIC UINT8 mDmgLoadingPolicy = AppleImg4SbModeMedium;
STATIC BOOLEAN mSbAvailable = TRUE;
STATIC UINT8 mSbPolicy = AppleImg4SbModeMedium;
STATIC UINT8 mSbWindowsPolicy = 1;
@@ -958,24 +959,33 @@ OcAppleSecureBootSetDmgLoading (
IN BOOLEAN LoadingDmg
)
{
+ EFI_STATUS Status;
ASSERT (mSecureBoot != NULL);
mDmgLoading = LoadingDmg;
+ Status = mSecureBoot->GetPolicy (mSecureBoot, &mDmgLoadingPolicy);
+ if (EFI_ERROR (Status)) {
+ mDmgLoadingPolicy = AppleImg4SbModeMedium;
+ }
+
if (LoadingDmg) {
- DEBUG ((DEBUG_INFO, "OCB: Disabling secure boot for Apple images\n"));
+ DEBUG ((DEBUG_INFO, "OCSB: Disabling secure boot for Apple images\n"));
mSecureBoot->SetAvailability (mSecureBoot, FALSE);
} else {
- DEBUG ((DEBUG_INFO, "OCB: Reenabling secure boot after Apple images\n"));
+ DEBUG ((DEBUG_INFO, "OCSB: Reenabling secure boot after Apple images\n"));
mSecureBoot->SetAvailability (mSecureBoot, FALSE);
}
}
BOOLEAN
OcAppleSecureBootGetDmgLoading (
- VOID
+ OUT UINT8 *RealPolicy OPTIONAL
)
{
+ if (RealPolicy != NULL) {
+ *RealPolicy = mDmgLoadingPolicy;
+ }
return mDmgLoading;
}
@@ -1015,7 +1025,8 @@ OcAppleSecureBootVerify (
// they do not even have global manifests in DMG images.
// Can consider checking boot.efi codesign integrity if we want.
//
- if (Policy == AppleImg4SbModeDisabled && OcAppleSecureBootGetDmgLoading ()) {
+ if (Policy == AppleImg4SbModeDisabled && OcAppleSecureBootGetDmgLoading (NULL)) {
+ DEBUG ((DEBUG_INFO, "OCSB: Direct booting for DMG image\n"));
return EFI_SUCCESS;
}
@@ -1023,6 +1034,7 @@ OcAppleSecureBootVerify (
// For everything else it is unsupported, meaning let the system decide.
//
if (Policy == AppleImg4SbModeDisabled) {
+ DEBUG ((DEBUG_INFO, "OCSB: Secure boot is disabled, skipping\n"));
return EFI_UNSUPPORTED;
}
@@ -1034,7 +1046,7 @@ OcAppleSecureBootVerify (
&ManifestSize
);
if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO, "OCB: No IMG4 found - %r\n", Status));
+ DEBUG ((DEBUG_INFO, "OCSB: No IMG4 found - %r\n", Status));
return EFI_UNSUPPORTED;
}
@@ -1055,18 +1067,12 @@ OcAppleSecureBootVerify (
FALSE
);
- //
- // This is our signature, but the file is corrupted.
- //
- if (Status == EFI_SECURITY_VIOLATION) {
- DEBUG ((DEBUG_WARN, "OCB: IMG4 %08X verification gave secure violation\n"));
- return EFI_SECURITY_VIOLATION;
- }
-
//
// We are successful.
//
if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "OCSB: Verified IMG4 without issues\n"));
+ FreePool (ManifestBuffer);
return Status;
}
}
@@ -1074,5 +1080,7 @@ OcAppleSecureBootVerify (
//
// No suitable signature.
//
+ DEBUG ((DEBUG_INFO, "OCSB: No suitable signature - %r\n", Status));
+ FreePool (ManifestBuffer);
return EFI_UNSUPPORTED;
}
diff --git a/Library/OcBootManagementLib/BootEntryManagement.c b/Library/OcBootManagementLib/BootEntryManagement.c
index a5e82a3d..0869f85c 100644
--- a/Library/OcBootManagementLib/BootEntryManagement.c
+++ b/Library/OcBootManagementLib/BootEntryManagement.c
@@ -1841,7 +1841,7 @@ OcLoadBootEntry (
if (!EFI_ERROR (Status)) {
Status = Context->StartImage (BootEntry, EntryHandle, NULL, NULL);
if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "OCB: StartImage failed - %r\n", Status));
+ DEBUG ((DEBUG_WARN, "OCB: StartImage failed - %r\n", Status));
//
// Unload dmg if any.
//
diff --git a/Library/OcBootManagementLib/BootManagementInternal.h b/Library/OcBootManagementLib/BootManagementInternal.h
index 1a8164d5..0811f1cf 100644
--- a/Library/OcBootManagementLib/BootManagementInternal.h
+++ b/Library/OcBootManagementLib/BootManagementInternal.h
@@ -176,14 +176,4 @@ InternalSystemActionResetNvram (
VOID
);
-/**
- Initialises custom gBS->LoadImage override.
-
- @retval EFI_SUCCESS on success.
-**/
-EFI_STATUS
-InternalInitImageLoader (
- VOID
- );
-
#endif // BOOT_MANAGEMENET_INTERNAL_H
diff --git a/Library/OcBootManagementLib/ImageLoader.c b/Library/OcBootManagementLib/ImageLoader.c
index d78ffe9c..9c5a0335 100644
--- a/Library/OcBootManagementLib/ImageLoader.c
+++ b/Library/OcBootManagementLib/ImageLoader.c
@@ -14,7 +14,10 @@
#include "BootManagementInternal.h"
+#include
+
#include
+#include
#include
#include
@@ -33,12 +36,44 @@
#include
#include
#include
+#include
#include
#include
#include
#include
-STATIC EFI_IMAGE_LOAD mOriginalEfiLoadImage;
+#if defined(MDE_CPU_IA32)
+ #define OC_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_I386
+#elif defined(MDE_CPU_X64)
+ #define OC_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_X64
+#else
+ #error Unsupported architecture.
+#endif
+
+STATIC EFI_GUID mOcLoadedImageProtocolGuid = {
+ 0x1f3c963d, 0xf9dc, 0x4537, { 0xbb, 0x06, 0xd8, 0x08, 0x46, 0x4a, 0x85, 0x2e }
+};
+
+typedef struct {
+ EFI_IMAGE_ENTRY_POINT EntryPoint;
+ EFI_PHYSICAL_ADDRESS ImageArea;
+ UINTN PageCount;
+ EFI_STATUS Status;
+ VOID *JumpBuffer;
+ BASE_LIBRARY_JUMP_BUFFER *JumpContext;
+ CHAR16 *ExitData;
+ UINTN ExitDataSize;
+ UINT16 Subsystem;
+ BOOLEAN Started;
+ EFI_LOADED_IMAGE_PROTOCOL LoadedImage;
+} OC_LOADED_IMAGE_PROTOCOL;
+
+STATIC EFI_IMAGE_LOAD mOriginalEfiLoadImage;
+STATIC EFI_IMAGE_START mOriginalEfiStartImage;
+STATIC EFI_IMAGE_UNLOAD mOriginalEfiUnloadImage;
+STATIC EFI_EXIT mOriginalEfiExit;
+STATIC EFI_HANDLE mCurrentImageHandle;
+STATIC BOOLEAN mDirectImageLoaderEnabled;
STATIC
EFI_STATUS
@@ -148,6 +183,409 @@ InternalUpdateLoadedImage (
return EFI_SUCCESS;
}
+EFI_STATUS
+EFIAPI
+OcDirectLoadImage (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ IMAGE_STATUS ImageStatus;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_PHYSICAL_ADDRESS DestinationArea;
+ VOID *DestinationBuffer;
+ OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+
+ ASSERT (SourceBuffer != NULL);
+
+ //
+ // Initialize the image context.
+ //
+ ImageStatus = OcPeCoffLoaderInitializeContext (
+ &ImageContext,
+ SourceBuffer,
+ SourceSize
+ );
+ if (ImageStatus != IMAGE_ERROR_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff init failure - %d\n", ImageStatus));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Reject images that are not meant for the platform's architecture.
+ //
+ if (ImageContext.Machine != OC_IMAGE_FILE_MACHINE) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff wrong machine - %x\n", ImageContext.Machine));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Reject RT drivers for the moment.
+ //
+ if (ImageContext.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff no support for RT drivers\n"));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Allocate the image destination memory.
+ // FIXME: RT drivers require EfiRuntimeServicesCode.
+ //
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ ImageContext.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
+ ? EfiLoaderCode : EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage),
+ &DestinationArea
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DestinationBuffer = (VOID *)(UINTN) DestinationArea;
+
+ //
+ // Load SourceBuffer into DestinationBuffer.
+ //
+ ImageStatus = OcPeCoffLoaderLoadImage (
+ &ImageContext,
+ DestinationBuffer,
+ ImageContext.SizeOfImage
+ );
+ if (ImageStatus != IMAGE_ERROR_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff load image error - %d\n", ImageStatus));
+ FreePages (DestinationBuffer, EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Relocate the loaded image to the destination address.
+ //
+ ImageStatus = OcPeCoffLoaderRelocateImage (
+ &ImageContext,
+ (UINTN) DestinationBuffer
+ );
+ if (ImageStatus != IMAGE_ERROR_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff relocate image error - %d\n", ImageStatus));
+ FreePages (DestinationBuffer, EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Construct a LoadedImage protocol for the image.
+ //
+ OcLoadedImage = AllocateZeroPool (sizeof (*OcLoadedImage));
+ if (OcLoadedImage == NULL) {
+ FreePages (DestinationBuffer, EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OcLoadedImage->EntryPoint = (EFI_IMAGE_ENTRY_POINT) ((UINTN) DestinationBuffer + ImageContext.AddressOfEntryPoint);
+ OcLoadedImage->ImageArea = DestinationArea;
+ OcLoadedImage->PageCount = EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage);
+ OcLoadedImage->Subsystem = ImageContext.Subsystem;
+
+ LoadedImage = &OcLoadedImage->LoadedImage;
+
+ LoadedImage->Revision = EFI_LOADED_IMAGE_INFORMATION_REVISION;
+ LoadedImage->ParentHandle = ParentImageHandle;
+ LoadedImage->SystemTable = gST;
+ LoadedImage->ImageBase = DestinationBuffer;
+ LoadedImage->ImageSize = ImageContext.SizeOfImage;
+ //
+ // FIXME: Support RT drivers.
+ //
+ if (ImageContext.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ LoadedImage->ImageCodeType = EfiLoaderCode;
+ LoadedImage->ImageDataType = EfiLoaderData;
+ } else {
+ LoadedImage->ImageCodeType = EfiBootServicesCode;
+ LoadedImage->ImageDataType = EfiBootServicesData;
+ }
+ //
+ // Install LoadedImage and the image's entry point.
+ //
+ *ImageHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ LoadedImage,
+ &mOcLoadedImageProtocolGuid,
+ OcLoadedImage,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff proto install error - %r\n", Status));
+ FreePool (OcLoadedImage);
+ FreePages (DestinationBuffer, EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage));
+ return Status;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "OCB: Loaded image at %p\n", *ImageHandle));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unload image routine for OcDirectLoadImage.
+
+ @param[in] OcLoadedImage Our loaded image instance.
+ @param[in] ImageHandle Handle that identifies the image to be unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+**/
+STATIC
+EFI_STATUS
+InternalDirectUnloadImage (
+ IN OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage,
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+
+ LoadedImage = &OcLoadedImage->LoadedImage;
+ if (LoadedImage->Unload != NULL) {
+ Status = LoadedImage->Unload (ImageHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Do not allow to execute Unload multiple times.
+ //
+ LoadedImage->Unload = NULL;
+ } else if (OcLoadedImage->Started) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ LoadedImage,
+ &mOcLoadedImageProtocolGuid,
+ OcLoadedImage,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->FreePages (OcLoadedImage->ImageArea, OcLoadedImage->PageCount);
+ FreePool (OcLoadedImage);
+ //
+ // NOTE: Avoid EFI 1.10 extension of closing opened protocols.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Unload image routine for OcDirectLoadImage.
+
+ @param[in] OcLoadedImage Our loaded image instance.
+ @param[in] ImageHandle Handle that identifies the image to be unloaded.
+ @param[in] ExitStatus The image's exit code.
+ @param[in] ExitDataSize The size, in bytes, of ExitData. Ignored if ExitStatus is EFI_SUCCESS.
+ @param[in] ExitData The pointer to a data buffer that includes a Null-terminated string,
+ optionally followed by additional binary data. The string is a
+ description that the caller may use to further indicate the reason
+ for the image's exit. ExitData is only valid if ExitStatus
+ is something other than EFI_SUCCESS. The ExitData buffer
+ must be allocated by calling AllocatePool().
+
+ @retval EFI_SUCCESS The image has been unloaded.
+**/
+STATIC
+EFI_STATUS
+InternalDirectExit (
+ IN OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS ExitStatus,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ )
+{
+ EFI_TPL OldTpl;
+
+ DEBUG ((
+ DEBUG_VERBOSE, "OCB: Exit %p %p (%d) - %r\n",
+ ImageHandle,
+ mCurrentImageHandle,
+ OcLoadedImage->Started,
+ ExitStatus
+ ));
+
+ //
+ // Prevent possible reentrance to this function for the same ImageHandle.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // If the image has not been started just free its resources.
+ // Should not happen normally.
+ //
+ if (!OcLoadedImage->Started) {
+ InternalDirectUnloadImage (OcLoadedImage, ImageHandle);
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If the image has been started, verify this image can exit.
+ //
+ if (ImageHandle != mCurrentImageHandle) {
+ DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n"));
+ gBS->RestoreTPL (OldTpl);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Set the return status.
+ //
+ OcLoadedImage->Status = ExitStatus;
+
+ //
+ // If there's ExitData info provide it.
+ //
+ if (ExitData != NULL) {
+ OcLoadedImage->ExitDataSize = ExitDataSize;
+ OcLoadedImage->ExitData = AllocatePool (OcLoadedImage->ExitDataSize);
+ if (OcLoadedImage->ExitData != NULL) {
+ CopyMem (OcLoadedImage->ExitData, ExitData, OcLoadedImage->ExitDataSize);
+ } else {
+ OcLoadedImage->ExitDataSize = 0;
+ }
+ }
+
+ //
+ // return to StartImage
+ //
+ gBS->RestoreTPL (OldTpl);
+ LongJump (OcLoadedImage->JumpContext, (UINTN)-1);
+
+ //
+ // If we return from LongJump, then it is an error
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+ return EFI_ACCESS_DENIED;
+}
+
+
+/**
+ Simplified start image routine for OcDirectLoadImage.
+
+ @param[in] OcLoadedImage Our loaded image instance.
+ @param[in] ImageHandle Handle of image to be started.
+ @param[out] ExitDataSize The pointer to the size, in bytes, of ExitData.
+ @param[out] ExitData The pointer to a pointer to a data buffer that includes a Null-terminated
+ string, optionally followed by additional binary data.
+
+ @retval EFI_SUCCESS on success.
+**/
+STATIC
+EFI_STATUS
+InternalDirectStartImage (
+ IN OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage,
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE LastImage;
+ UINTN SetJumpFlag;
+
+ //
+ // Push the current image.
+ //
+ LastImage = mCurrentImageHandle;
+ mCurrentImageHandle = ImageHandle;
+
+ //
+ // Set long jump for Exit() support
+ // JumpContext must be aligned on a CPU specific boundary.
+ // Overallocate the buffer and force the required alignment
+ //
+ OcLoadedImage->JumpBuffer = AllocatePool (
+ sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
+ );
+ if (OcLoadedImage->JumpBuffer == NULL) {
+ //
+ // Pop the current start image context
+ //
+ mCurrentImageHandle = LastImage;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OcLoadedImage->JumpContext = ALIGN_POINTER (
+ OcLoadedImage->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
+ );
+
+ SetJumpFlag = SetJump (OcLoadedImage->JumpContext);
+ //
+ // The initial call to SetJump() must always return 0.
+ // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
+ //
+ if (SetJumpFlag == 0) {
+ //
+ // Invoke the manually loaded image entry point.
+ //
+ DEBUG ((DEBUG_VERBOSE, "OCB: Starting image %p\n", ImageHandle));
+ OcLoadedImage->Started = TRUE;
+ OcLoadedImage->Status = OcLoadedImage->EntryPoint (
+ ImageHandle,
+ OcLoadedImage->LoadedImage.SystemTable
+ );
+ //
+ // If the image returns, exit it through Exit()
+ //
+ InternalDirectExit (OcLoadedImage, ImageHandle, OcLoadedImage->Status, 0, NULL);
+ }
+
+ FreePool (OcLoadedImage->JumpBuffer);
+
+ //
+ // Pop the current image.
+ //
+ mCurrentImageHandle = LastImage;
+
+ //
+ // NOTE: EFI 1.10 is not supported, refer to
+ // https://github.com/tianocore/edk2/blob/d8dd54f071cfd60a2dcf5426764a89cd91213420/MdeModulePkg/Core/Dxe/Image/Image.c#L1686-L1697
+ //
+
+ //
+ // Return the exit data to the caller
+ //
+ if (ExitData != NULL && ExitDataSize != NULL) {
+ *ExitDataSize = OcLoadedImage->ExitDataSize;
+ *ExitData = OcLoadedImage->ExitData;
+ } else if (OcLoadedImage->ExitData != NULL) {
+ //
+ // Caller doesn't want the exit data, free it
+ //
+ FreePool (OcLoadedImage->ExitData);
+ OcLoadedImage->ExitData = NULL;
+ }
+
+ //
+ // Save the Status because Image will get destroyed if it is unloaded.
+ //
+ Status = OcLoadedImage->Status;
+
+ //
+ // If the image returned an error, or if the image is an application
+ // unload it
+ //
+ if (EFI_ERROR (OcLoadedImage->Status)
+ || OcLoadedImage->Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ InternalDirectUnloadImage (OcLoadedImage, ImageHandle);
+ }
+
+ return Status;
+}
+
STATIC
EFI_STATUS
EFIAPI
@@ -198,7 +636,7 @@ InternalEfiLoadImage (
}
}
- if (DevicePath != NULL && SourceBuffer != NULL) {
+ if (DevicePath != NULL && SourceBuffer != NULL && mDirectImageLoaderEnabled) {
SecureBootStatus = OcAppleSecureBootVerify (
DevicePath,
SourceBuffer,
@@ -226,6 +664,17 @@ InternalEfiLoadImage (
#else
Status = FatFilterArchitecture64 ((UINT8 **) &SourceBuffer, &RealSize);
#endif
+
+ DEBUG ((
+ DEBUG_INFO,
+ "OCB: Arch filtering %p(%u)->%p(%u) - %r\n",
+ AllocatedBuffer,
+ (UINT32) SourceSize,
+ SourceBuffer,
+ RealSize,
+ Status
+ ));
+
if (!EFI_ERROR (Status)) {
SourceSize = RealSize;
} else if (AllocatedBuffer != NULL) {
@@ -234,21 +683,37 @@ InternalEfiLoadImage (
}
}
+ //
+ // Load the image ourselves in secure boot mode.
+ //
if (SecureBootStatus == EFI_SUCCESS) {
- //
- // TODO: Here we should use a custom COFF loader!
- //
+ if (SourceBuffer != NULL) {
+ Status = OcDirectLoadImage (
+ FALSE,
+ ParentImageHandle,
+ DevicePath,
+ SourceBuffer,
+ SourceSize,
+ ImageHandle
+ );
+ } else {
+ //
+ // We verified the image, but contained garbage.
+ // This should not happen, just abort.
+ //
+ Status = EFI_UNSUPPORTED;
+ }
+ } else {
+ Status = mOriginalEfiLoadImage (
+ BootPolicy,
+ ParentImageHandle,
+ DevicePath,
+ SourceBuffer,
+ SourceSize,
+ ImageHandle
+ );
}
- Status = mOriginalEfiLoadImage (
- BootPolicy,
- ParentImageHandle,
- DevicePath,
- SourceBuffer,
- SourceSize,
- ImageHandle
- );
-
if (AllocatedBuffer != NULL) {
FreePool (AllocatedBuffer);
}
@@ -264,15 +729,126 @@ InternalEfiLoadImage (
return Status;
}
+STATIC
EFI_STATUS
-InternalInitImageLoader (
+EFIAPI
+InternalEfiStartImage (
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage;
+
+ //
+ // If we loaded the image, invoke the entry point manually.
+ //
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &mOcLoadedImageProtocolGuid,
+ (VOID **) &OcLoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ return InternalDirectStartImage (
+ OcLoadedImage,
+ ImageHandle,
+ ExitDataSize,
+ ExitData
+ );
+ }
+
+ return mOriginalEfiStartImage (ImageHandle, ExitDataSize, ExitData);
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+InternalEfiUnloadImage (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage;
+
+ //
+ // If we loaded the image, do the unloading manually.
+ //
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &mOcLoadedImageProtocolGuid,
+ (VOID **) &OcLoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ return InternalDirectUnloadImage (
+ OcLoadedImage,
+ ImageHandle
+ );
+ }
+
+ return mOriginalEfiUnloadImage (ImageHandle);
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+InternalEfiExit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS ExitStatus,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage;
+
+ //
+ // If we loaded the image, do the exit manually.
+ //
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &mOcLoadedImageProtocolGuid,
+ (VOID **) &OcLoadedImage
+ );
+
+ DEBUG ((DEBUG_VERBOSE, "OCB: InternalEfiExit %p - %r / %r\n", ImageHandle, ExitStatus, Status));
+
+ if (!EFI_ERROR (Status)) {
+ return InternalDirectExit (
+ OcLoadedImage,
+ ImageHandle,
+ ExitStatus,
+ ExitDataSize,
+ ExitData
+ );
+ }
+
+ return mOriginalEfiExit (ImageHandle, ExitStatus, ExitDataSize, ExitData);
+}
+
+VOID
+OcInitDirectImageLoader (
VOID
)
{
- mOriginalEfiLoadImage = gBS->LoadImage;
- gBS->LoadImage = InternalEfiLoadImage;
+ mOriginalEfiLoadImage = gBS->LoadImage;
+ mOriginalEfiStartImage = gBS->StartImage;
+ mOriginalEfiUnloadImage = gBS->UnloadImage;
+ mOriginalEfiExit = gBS->Exit;
+
+ gBS->LoadImage = InternalEfiLoadImage;
+ gBS->StartImage = InternalEfiStartImage;
+ gBS->UnloadImage = InternalEfiUnloadImage;
+ gBS->Exit = InternalEfiExit;
gBS->Hdr.CRC32 = 0;
gBS->CalculateCrc32 (gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
- return EFI_SUCCESS;
+}
+
+VOID
+OcActivateDirectImageLoader (
+ VOID
+ )
+{
+ mDirectImageLoaderEnabled = TRUE;
}
diff --git a/Library/OcBootManagementLib/OcBootManagementLib.c b/Library/OcBootManagementLib/OcBootManagementLib.c
index 366116b4..f59e2cee 100644
--- a/Library/OcBootManagementLib/OcBootManagementLib.c
+++ b/Library/OcBootManagementLib/OcBootManagementLib.c
@@ -505,10 +505,7 @@ OcRunBootPicker (
SaidWelcome = FALSE;
- Status = InternalInitImageLoader ();
- if (EFI_ERROR (Status)) {
- return Status;
- }
+ OcActivateDirectImageLoader ();
//
// Reset NVRAM right away if requested by a key combination.
diff --git a/Library/OcBootManagementLib/OcBootManagementLib.inf b/Library/OcBootManagementLib/OcBootManagementLib.inf
index 696756fd..9a4498ca 100644
--- a/Library/OcBootManagementLib/OcBootManagementLib.inf
+++ b/Library/OcBootManagementLib/OcBootManagementLib.inf
@@ -110,6 +110,7 @@
OcGuardLib
OcFileLib
OcMachoLib
+ OcPeCoffLib
OcRtcLib
OcXmlLib
TimerLib
diff --git a/Library/OcGuardLib/Alignment.c b/Library/OcGuardLib/Alignment.c
new file mode 100644
index 00000000..66ef79c5
--- /dev/null
+++ b/Library/OcGuardLib/Alignment.c
@@ -0,0 +1,36 @@
+/** @file
+
+OcGuardLib
+
+Copyright (c) 2020, Download-Fritz
+
+All rights reserved.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include
+
+#include
+#include
+
+BOOLEAN
+OcOverflowAlignUpU32 (
+ UINT32 Value,
+ UINT32 Alignment,
+ UINT32 *Result
+ )
+{
+ BOOLEAN Status;
+
+ Status = OcOverflowAddU32 (Value, Alignment - 1U, Result);
+ *Result &= ~(Alignment - 1U);
+
+ return Status;
+}
diff --git a/Library/OcGuardLib/OcGuardLib.inf b/Library/OcGuardLib/OcGuardLib.inf
index 86a60f14..b360b152 100644
--- a/Library/OcGuardLib/OcGuardLib.inf
+++ b/Library/OcGuardLib/OcGuardLib.inf
@@ -29,6 +29,7 @@
#
[Sources]
+ Alignment.c
BitOverflow.c
Canary.c
NativeOverflow.c
diff --git a/Library/OcPeCoffLib/OcPeCoffLib.c b/Library/OcPeCoffLib/OcPeCoffLib.c
new file mode 100644
index 00000000..c012952b
--- /dev/null
+++ b/Library/OcPeCoffLib/OcPeCoffLib.c
@@ -0,0 +1,1178 @@
+/** @file
+ Base PE/COFF loader supports loading any PE32/PE32+ or TE image.
+
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define IS_POW2(v) ((v) != 0U && ((v) & ((v) - 1U)) == 0U)
+#define IS_ALIGNED(v, a) (((v) & ((a) - 1U)) == 0U)
+
+#define IMAGE_RELOC_TYPE(Relocation) ((Relocation) >> 12U)
+#define IMAGE_RELOC_OFFSET(Relocation) ((Relocation) & 0x0FFFU)
+
+#define IMAGE_IS_EFI_SUBYSYSTEM(Subsystem) \
+ ((Subsystem) >= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \
+ (Subsystem) <= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER)
+
+#define IMAGE_RELOC_TYPE_SUPPORTED(Type) \
+ ((Type) == EFI_IMAGE_REL_BASED_ABSOLUTE) || \
+ ((Type) == EFI_IMAGE_REL_BASED_HIGHLOW) || \
+ ((Type) == EFI_IMAGE_REL_BASED_DIR64))
+
+#define IMAGE_RELOC_SUPPORTED(Reloc) \
+ IMAGE_RELOC_TYPE_SUPPORTED (IMAGE_RELOC_TYPE (Reloc))
+
+STATIC
+IMAGE_STATUS
+InternalVerifySections (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINTN FileSize,
+ IN UINT32 SectionsOffset,
+ IN UINT16 NumberOfSections,
+ OUT UINT32 *BottomAddress,
+ OUT UINT32 *TopAddress
+ )
+{
+ BOOLEAN Result;
+ UINT32 NextSectRva;
+ UINT32 SectRvaPrevEnd;
+ UINT32 SectRvaEnd;
+ UINT32 SectRawEnd;
+ UINT16 SectIndex;
+ CONST EFI_IMAGE_SECTION_HEADER *Sections;
+
+ ASSERT (Context != NULL);
+ ASSERT (Context->SizeOfHeaders >= Context->TeStrippedOffset);
+ ASSERT (IS_POW2 (Context->SectionAlignment));
+ ASSERT (NumberOfSections > 0);
+ ASSERT (BottomAddress != NULL);
+ ASSERT (TopAddress != NULL);
+
+ Sections = (CONST EFI_IMAGE_SECTION_HEADER *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + SectionsOffset
+ );
+
+ if (Sections[0].VirtualAddress == 0) {
+ if (Context->ImageType == ImageTypeTe) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ NextSectRva = 0;
+ } else {
+ // TODO: Disallow PCD
+
+ Result = OcOverflowAlignUpU32 (
+ Context->SizeOfHeaders,
+ Context->SectionAlignment,
+ &NextSectRva
+ );
+ if (Result) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ }
+
+ SectRvaPrevEnd = NextSectRva;
+
+ *BottomAddress = NextSectRva;
+
+ for (SectIndex = 0; SectIndex < NumberOfSections; ++SectIndex) {
+ if (Sections[SectIndex].SizeOfRawData > 0) {
+ if (Context->TeStrippedOffset > Sections[SectIndex].PointerToRawData) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ Result = OcOverflowAddU32 (
+ Sections[SectIndex].PointerToRawData,
+ Sections[SectIndex].SizeOfRawData,
+ &SectRawEnd
+ );
+ if (Result) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ if ((SectRawEnd - Context->TeStrippedOffset) > FileSize) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ }
+
+ Result = OcOverflowAddU32 (
+ Sections[SectIndex].VirtualAddress,
+ Sections[SectIndex].VirtualSize,
+ &SectRvaEnd
+ );
+ if (Result) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ //
+ // FIXME: Misaligned images should be handled with a PCD.
+ //
+ if (Sections[SectIndex].VirtualAddress < SectRvaPrevEnd
+ || Sections[SectIndex].VirtualAddress > NextSectRva) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ SectRvaPrevEnd = SectRvaEnd;
+
+ //
+ // Sections must have virtual addresses adjacent in ascending order.
+ // SectionSize does not need to be aligned, so align the result.
+ //
+ Result = OcOverflowAlignUpU32 (
+ SectRvaEnd,
+ Context->SectionAlignment,
+ &NextSectRva
+ );
+
+ if (Result) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ }
+
+ *TopAddress = NextSectRva;
+
+ return IMAGE_ERROR_SUCCESS;
+}
+
+STATIC
+IMAGE_STATUS
+InternalValidateRelocInfo (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINT32 BottomAddress
+ )
+{
+ BOOLEAN Result;
+ UINT32 SectRvaEnd;
+
+ ASSERT (Context != NULL);
+ ASSERT (BottomAddress == 0 || BottomAddress == ALIGN_VALUE (Context->SizeOfHeaders, Context->SectionAlignment));
+ //
+ // If the relocations have not been stripped, sanitize their directory.
+ //
+ if (!Context->RelocsStripped) {
+ if (sizeof (EFI_IMAGE_BASE_RELOCATION) > Context->RelocDirSize) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ Result = OcOverflowAddU32 (
+ Context->RelocDirRva,
+ Context->RelocDirSize,
+ &SectRvaEnd
+ );
+ //
+ // Ensure no overflow has occured.
+ //
+ if (Result) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // Ensure the directory does not overlap with the image header.
+ //
+ if (BottomAddress > Context->RelocDirRva) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // Ensure the directory is within the bounds of the image's virtual space.
+ //
+ if (SectRvaEnd > Context->SizeOfImage) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // Ensure the directory's start is propery aligned.
+ //
+ if (!OC_TYPE_ALIGNED (EFI_IMAGE_BASE_RELOCATION, Context->RelocDirRva)) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ } else {
+ if (!IS_ALIGNED (Context->ImageBase, Context->SectionAlignment)) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // Ensure DXE Runtime Driver can be relocated.
+ //
+ if (Context->Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ }
+
+ return IMAGE_ERROR_SUCCESS;
+}
+
+STATIC
+IMAGE_STATUS
+InternalInitializeTe (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINTN FileSize
+ )
+{
+ IMAGE_STATUS Status;
+ BOOLEAN Result;
+ CONST EFI_TE_IMAGE_HEADER *TeHdr;
+ UINT32 BottomAddress;
+ UINT32 SizeOfImage;
+ UINT32 SectionsOffset;
+
+ ASSERT (Context != NULL);
+ ASSERT (Context->ExeHdrOffset <= FileSize);
+ ASSERT (FileSize - Context->ExeHdrOffset >= sizeof (EFI_TE_IMAGE_HEADER));
+ ASSERT (OC_TYPE_ALIGNED (EFI_TE_IMAGE_HEADER, Context->ExeHdrOffset));
+
+ Context->ImageType = ImageTypeTe;
+
+
+ TeHdr = (CONST EFI_TE_IMAGE_HEADER *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset
+ );
+
+ STATIC_ASSERT (
+ OC_TYPE_ALIGNED (EFI_IMAGE_SECTION_HEADER, sizeof (*TeHdr)),
+ "The section alignment requirements are violated."
+ );
+
+ Result = OcOverflowSubU32 (
+ TeHdr->StrippedSize,
+ sizeof (*TeHdr),
+ &Context->TeStrippedOffset
+ );
+ if (Result) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ if (TeHdr->NumberOfSections == 0) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ STATIC_ASSERT (
+ sizeof (EFI_IMAGE_SECTION_HEADER) <= (MAX_UINT32 - sizeof (*TeHdr)) / MAX_UINT8,
+ "These arithmetics may overflow."
+ );
+ //
+ // Assign SizeOfHeaders in a way that is equivalent to what the size would
+ // be if this was the original (unstripped) PE32 binary. As the TE image
+ // creation fixes no fields up, tests work the same way as for PE32.
+ // when referencing raw data however, the offset must be subracted.
+ //
+ Result = OcOverflowAddU32 (
+ TeHdr->StrippedSize,
+ (UINT32) TeHdr->NumberOfSections * sizeof (EFI_IMAGE_SECTION_HEADER),
+ &Context->SizeOfHeaders
+ );
+ if (Result) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // Ensure that all headers are in bounds of the file buffer.
+ //
+ if ((Context->SizeOfHeaders - Context->TeStrippedOffset) > FileSize) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ Context->SectionAlignment = BASE_4KB;
+ SectionsOffset = Context->ExeHdrOffset + sizeof (EFI_TE_IMAGE_HEADER);
+ //
+ // Validate the sections.
+ // TE images do not have a field to explicitly describe the image size.
+ // Set it to the top of the image's virtual space.
+ //
+ Status = InternalVerifySections (
+ Context,
+ FileSize,
+ SectionsOffset,
+ TeHdr->NumberOfSections,
+ &BottomAddress,
+ &SizeOfImage
+ );
+
+ if (Status != IMAGE_ERROR_SUCCESS) {
+ return Status;
+ }
+
+ Context->SizeOfImage = SizeOfImage;
+ Context->Machine = TeHdr->Machine;
+ Context->Subsystem = TeHdr->Subsystem;
+ Context->ImageBase = TeHdr->ImageBase;
+ Context->RelocsStripped = TeHdr->DataDirectory[0].Size > 0;
+ Context->AddressOfEntryPoint = TeHdr->AddressOfEntryPoint;
+ Context->RelocDirRva = TeHdr->DataDirectory[0].VirtualAddress;
+ Context->RelocDirSize = TeHdr->DataDirectory[0].Size;
+
+ return InternalValidateRelocInfo (Context, BottomAddress);
+}
+
+STATIC
+IMAGE_STATUS
+InternalInitializePe (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINTN FileSize
+ )
+{
+ BOOLEAN Result;
+ CONST EFI_IMAGE_NT_HEADERS_COMMON_HDR *PeCommon;
+ CONST EFI_IMAGE_NT_HEADERS32 *Pe32;
+ CONST EFI_IMAGE_NT_HEADERS64 *Pe32Plus;
+ CONST VOID *OptHdrPtr;
+ UINT32 HdrSizeWithoutDataDir;
+ UINT32 SizeOfOptionalHdr;
+ UINT32 SizeOfHeaders;
+ CONST EFI_IMAGE_DATA_DIRECTORY *RelocDir;
+ UINT32 NumberOfRvaAndSizes;
+ UINT32 SectHdrOffset;
+ IMAGE_STATUS Status;
+ UINT32 BottomAddress;
+ UINT32 SizeOfImage;
+
+ ASSERT (Context != NULL);
+
+ OptHdrPtr = (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset + sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR);
+ ASSERT (OC_TYPE_ALIGNED (EFI_IMAGE_NT_HEADERS_COMMON_HDR, Context->ExeHdrOffset));
+
+ STATIC_ASSERT (
+ OC_TYPE_ALIGNED (UINT16, OC_ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR))
+ && OC_TYPE_ALIGNED (UINT16, sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR)),
+ "The following operation might be an unaligned access."
+ );
+
+ //
+ // Determine the type of and retrieve data from the PE Optional Header.
+ //
+ //
+ // FIXME: OptHdrPtr could point to unaligned memory.
+ //
+ switch (*(CONST UINT16 *) OptHdrPtr) {
+ case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
+ if (sizeof (*Pe32) > FileSize - Context->ExeHdrOffset) {
+ DEBUG ((DEBUG_INFO, "OCPE: Invalid 32-bit OPT header\n"));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ Context->ImageType = ImageTypePe32;
+
+ Pe32 = (CONST EFI_IMAGE_NT_HEADERS32 *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset
+ );
+
+ HdrSizeWithoutDataDir = OFFSET_OF (EFI_IMAGE_NT_HEADERS32, DataDirectory) - sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR);
+ Context->Subsystem = Pe32->Subsystem;
+ NumberOfRvaAndSizes = Pe32->NumberOfRvaAndSizes;
+
+ RelocDir = Pe32->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
+
+ Context->SizeOfImage = Pe32->SizeOfImage;
+ Context->SizeOfHeaders = Pe32->SizeOfHeaders;
+ Context->ImageBase = Pe32->ImageBase;
+ Context->AddressOfEntryPoint = Pe32->AddressOfEntryPoint;
+ Context->SectionAlignment = Pe32->SectionAlignment;
+
+ PeCommon = &Pe32->CommonHeader;
+ break;
+
+ case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+ if (sizeof (*Pe32Plus) > FileSize - Context->ExeHdrOffset) {
+ DEBUG ((DEBUG_INFO, "OCPE: Invalid 64-bit OPT header\n"));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ Context->ImageType = ImageTypePe32Plus;
+
+
+ Pe32Plus = (CONST EFI_IMAGE_NT_HEADERS64 *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset
+ );
+
+ HdrSizeWithoutDataDir = OFFSET_OF (EFI_IMAGE_NT_HEADERS64, DataDirectory) - sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR);
+ Context->Subsystem = Pe32Plus->Subsystem;
+ NumberOfRvaAndSizes = Pe32Plus->NumberOfRvaAndSizes;
+
+ RelocDir = Pe32Plus->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
+
+ Context->SizeOfImage = Pe32Plus->SizeOfImage;
+ Context->SizeOfHeaders = Pe32Plus->SizeOfHeaders;
+ Context->ImageBase = Pe32Plus->ImageBase;
+ Context->AddressOfEntryPoint = Pe32Plus->AddressOfEntryPoint;
+ Context->SectionAlignment = Pe32Plus->SectionAlignment;
+
+ PeCommon = &Pe32Plus->CommonHeader;
+ break;
+
+ default:
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ if (PeCommon->FileHeader.NumberOfSections == 0) {
+ DEBUG ((DEBUG_INFO, "OCPE: No sections in the image\n"));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // Do not load images with unknown directories.
+ //
+ if (NumberOfRvaAndSizes > EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES) {
+ DEBUG ((DEBUG_INFO, "OCPE: NumberOfRvaAndSizes is too high %u\n", NumberOfRvaAndSizes));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ if (!IS_POW2 (Context->SectionAlignment)) {
+ DEBUG ((DEBUG_INFO, "OCPE: Invalid section alignment %u\n", Context->SectionAlignment));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // SizeOfOptionalHdr cannot overflow because NumberOfRvaAndSizes has
+ // been sanitized and the other two components are validated constants.
+ //
+ STATIC_ASSERT (
+ sizeof (EFI_IMAGE_DATA_DIRECTORY) <= MAX_UINT32 / EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
+ "These arithmetics may overflow."
+ );
+
+ SizeOfOptionalHdr = HdrSizeWithoutDataDir +
+ NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY);
+
+ ASSERT (SizeOfOptionalHdr >= HdrSizeWithoutDataDir);
+ //
+ // Context->ExeHdrOffset + sizeof (*PeCommon) cannot overflow because
+ // * ExeFileSize > sizeof (*PeCommon) and
+ // * Context->ExeHdrOffset + ExeFileSize = FileSize
+ //
+ Result = OcOverflowAddU32 (
+ Context->ExeHdrOffset + sizeof (*PeCommon),
+ SizeOfOptionalHdr,
+ &SectHdrOffset
+ );
+
+ if (Result) {
+ DEBUG ((
+ DEBUG_INFO,
+ "OCPE: Sections offset overflow %u + %u + %u\n",
+ Context->ExeHdrOffset,
+ (UINT32) sizeof (*PeCommon),
+ SizeOfOptionalHdr
+ ));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // Ensure the section headers offset is properly aligned.
+ //
+ if (!OC_TYPE_ALIGNED (EFI_IMAGE_SECTION_HEADER, SectHdrOffset)) {
+ DEBUG ((DEBUG_INFO, "OCPE: Sections are unaligned %u\n", SectHdrOffset));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ STATIC_ASSERT (
+ sizeof (EFI_IMAGE_SECTION_HEADER) <= (MAX_UINT32 + 1ULL) / (MAX_UINT16 + 1ULL),
+ "These arithmetics may overflow."
+ );
+
+ Result = OcOverflowAddU32 (
+ SectHdrOffset,
+ (UINT32) PeCommon->FileHeader.NumberOfSections * sizeof (EFI_IMAGE_SECTION_HEADER),
+ &SizeOfHeaders
+ );
+
+ if (Result) {
+ DEBUG ((DEBUG_INFO, "OCPE: Sections overflow %u %u\n", SectHdrOffset, PeCommon->FileHeader.NumberOfSections));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // Ensure the header sizes are sane. SizeOfHeaders contains all header
+ // components (DOS, PE Common and Optional Header).
+ //
+ if (PeCommon->FileHeader.SizeOfOptionalHeader < SizeOfOptionalHdr
+ || Context->SizeOfHeaders < SizeOfHeaders) {
+ DEBUG ((DEBUG_INFO, "OCPE: SizeOfOptionalHeader %u %u\n", PeCommon->FileHeader.SizeOfOptionalHeader, SizeOfOptionalHdr));
+ DEBUG ((DEBUG_INFO, "OCPE: ImageSizeOfHeaders %u %u\n", Context->SizeOfHeaders, SizeOfHeaders));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // Ensure that all headers are in bounds of the file buffer.
+ //
+ if (Context->SizeOfHeaders > FileSize) {
+ DEBUG ((DEBUG_INFO, "OCPE: Context->SizeOfHeaders > FileSize %u %u\n", Context->SizeOfHeaders, FileSize));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ Status = InternalVerifySections (
+ Context,
+ FileSize,
+ SectHdrOffset,
+ PeCommon->FileHeader.NumberOfSections,
+ &BottomAddress,
+ &SizeOfImage
+ );
+ if (Status != IMAGE_ERROR_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "OCPE: InternalVerifySections %d\n", Status));
+ return Status;
+ }
+ //
+ // Ensure SizeOfImage is equal to the top of the image's virtual space.
+ // FIXME: Misaligned images should load with a PCD
+ //
+ if (Context->SizeOfImage < SizeOfImage) {
+ DEBUG ((DEBUG_INFO, "OCPE: Context->SizeOfImage < SizeOfImage %u %u\n", Context->SizeOfImage, SizeOfImage));
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+ //
+ // If there's no relocations, then make sure it's not a runtime driver.
+ //
+ Context->RelocsStripped =
+ (
+ PeCommon->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED
+ ) != 0;
+
+ Context->Machine = PeCommon->FileHeader.Machine;
+
+ if (EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC < NumberOfRvaAndSizes) {
+ Context->RelocDirRva = RelocDir->VirtualAddress;
+ Context->RelocDirSize = RelocDir->Size;
+ } else {
+ Context->RelocDirRva = 0;
+ Context->RelocDirSize = 0;
+ }
+
+ return InternalValidateRelocInfo (Context, BottomAddress);
+}
+
+IMAGE_STATUS
+OcPeCoffLoaderInitializeContext (
+ OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN CONST VOID *FileBuffer,
+ IN UINTN FileSize
+ )
+{
+ CONST VOID *ImageSig;
+ CONST EFI_IMAGE_DOS_HEADER *DosHdr;
+
+ ASSERT (Context != NULL);
+ ASSERT (FileBuffer != NULL);
+ ASSERT (FileSize > 0);
+
+ ZeroMem (Context, sizeof (*Context));
+
+ Context->FileBuffer = (VOID *) FileBuffer;
+
+ ASSERT (Context != NULL);
+ //
+ // Check whether the DOS image header is present.
+ //
+ if (FileSize > sizeof (*DosHdr)
+ && *(CONST UINT16 *) Context->FileBuffer == EFI_IMAGE_DOS_SIGNATURE) {
+ DosHdr = (CONST EFI_IMAGE_DOS_HEADER *) Context->FileBuffer;
+ //
+ // When the DOS image header is present, sanitize the offset and
+ // retrieve the size of the executable image.
+ //
+ if (sizeof (EFI_IMAGE_DOS_HEADER) > DosHdr->e_lfanew
+ || DosHdr->e_lfanew >= FileSize) {
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ Context->ExeHdrOffset = DosHdr->e_lfanew;
+ } else {
+ //
+ // When the DOS image header is not present, assume the image starts with
+ // the executable header.
+ //
+ Context->ExeHdrOffset = 0;
+ }
+ //
+ // Use Signature to determine and handle the image format (PE32(+) / TE).
+ //
+ ImageSig = (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset;
+
+ if (FileSize - Context->ExeHdrOffset >= sizeof (EFI_TE_IMAGE_HEADER)
+ && OC_TYPE_ALIGNED (EFI_TE_IMAGE_HEADER, Context->ExeHdrOffset)
+ && *(CONST UINT16 *) ImageSig == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ return InternalInitializeTe (Context, FileSize);
+ }
+
+ if (FileSize - Context->ExeHdrOffset >= sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) + sizeof (UINT16)
+ && OC_TYPE_ALIGNED (EFI_IMAGE_NT_HEADERS_COMMON_HDR, Context->ExeHdrOffset)
+ && *(CONST UINT32 *) ImageSig == EFI_IMAGE_NT_SIGNATURE) {
+ return InternalInitializePe (Context, FileSize);
+ }
+
+ return IMAGE_ERROR_INVALID_MACHINE_TYPE;
+}
+
+STATIC
+BOOLEAN
+InternalHashSections (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINT32 SectionsOffset,
+ IN UINT16 NumberOfSections,
+ IN HASH_UPDATE HashUpdate,
+ IN OUT VOID *HashContext
+ )
+{
+ BOOLEAN Result;
+
+ CONST EFI_IMAGE_SECTION_HEADER *Sections;
+ CONST EFI_IMAGE_SECTION_HEADER **SortedSections;
+ UINT16 SectIndex;
+ UINT16 SectionPos;
+ UINT32 SectionTop;
+ //
+ // Build a temporary table of pointers to all section headers of the image
+ // to sort them appropiately.
+ //
+ SortedSections = AllocatePool (
+ (UINT32) NumberOfSections * sizeof (*SortedSections)
+ );
+
+ if (SortedSections == NULL) {
+ return FALSE;
+ }
+
+ Sections = (CONST EFI_IMAGE_SECTION_HEADER *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + SectionsOffset
+ );
+ //
+ // Sort SortedSections by PointerToRawData in ascending order.
+ //
+ SortedSections[0] = &Sections[0];
+ //
+ // Insertion Sort.
+ //
+ for (SectIndex = 1; SectIndex < NumberOfSections; ++SectIndex) {
+ for (SectionPos = SectIndex;
+ 0 < SectionPos
+ && SortedSections[SectionPos - 1]->PointerToRawData > Sections[SectIndex].PointerToRawData;
+ --SectionPos) {
+ SortedSections[SectionPos] = SortedSections[SectionPos - 1];
+ }
+
+ SortedSections[SectionPos] = &Sections[SectIndex];
+ }
+
+ Result = TRUE;
+
+ SectionTop = 0;
+ //
+ // Hash the image's sections' data in the ascending order of their offset.
+ //
+ for (SectIndex = 0; SectIndex < NumberOfSections; ++SectIndex) {
+ if (PcdGetBool (PcdImageLoaderHashProhibitOverlap)) {
+ if (SectionTop > SortedSections[SectIndex]->PointerToRawData) {
+ Result = FALSE;
+ break;
+ }
+
+ SectionTop = SortedSections[SectIndex]->PointerToRawData + SortedSections[SectIndex]->SizeOfRawData;
+ }
+
+ if (SortedSections[SectIndex]->SizeOfRawData > 0) {
+ Result = HashUpdate (
+ HashContext,
+ (CONST CHAR8 *) Context->FileBuffer + SortedSections[SectIndex]->PointerToRawData,
+ SortedSections[SectIndex]->SizeOfRawData
+ );
+ if (!Result) {
+ break;
+ }
+ }
+ }
+
+ FreePool ((VOID *)SortedSections);
+ return Result;
+}
+
+BOOLEAN
+OcPeCoffLoaderHashImage (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN HASH_UPDATE HashUpdate,
+ IN OUT VOID *HashContext
+ )
+{
+ BOOLEAN Result;
+ UINT32 NumberOfRvaAndSizes;
+ UINT32 ChecksumOffset;
+ UINT32 SecurityDirOffset;
+ UINT32 CurrentOffset;
+ UINT32 HashSize;
+ CONST EFI_IMAGE_NT_HEADERS32 *Pe32;
+ CONST EFI_IMAGE_NT_HEADERS64 *Pe32Plus;
+ UINT32 SectionsOffset;
+ UINT16 NumberOfSections;
+ //
+ // Hash the entire image excluding:
+ // * its checksum
+ // * its security directory
+ // * its signature
+ //
+ switch (Context->ImageType) {
+ case ImageTypeTe:
+ //
+ // TE images are not to be signed, as they are supposed to only be part of
+ // Firmware Volumes, which may be signed as a whole.
+ //
+ return FALSE;
+
+ case ImageTypePe32:
+ Pe32 = (CONST EFI_IMAGE_NT_HEADERS32 *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset
+ );
+
+ ChecksumOffset = Context->ExeHdrOffset + OFFSET_OF (EFI_IMAGE_NT_HEADERS32, CheckSum);
+ SecurityDirOffset = Context->ExeHdrOffset + (UINT32) OFFSET_OF (EFI_IMAGE_NT_HEADERS32, DataDirectory) +(UINT32) (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY * sizeof (EFI_IMAGE_DATA_DIRECTORY));
+ NumberOfRvaAndSizes = Pe32->NumberOfRvaAndSizes;
+ SectionsOffset = Context->ExeHdrOffset + sizeof (Pe32->CommonHeader) + Pe32->CommonHeader.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = Pe32->CommonHeader.FileHeader.NumberOfSections;
+
+ break;
+
+ case ImageTypePe32Plus:
+ Pe32Plus = (CONST EFI_IMAGE_NT_HEADERS64 *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset
+ );
+
+ ChecksumOffset = Context->ExeHdrOffset + OFFSET_OF (EFI_IMAGE_NT_HEADERS64, CheckSum);
+ SecurityDirOffset = Context->ExeHdrOffset + (UINT32) OFFSET_OF (EFI_IMAGE_NT_HEADERS64, DataDirectory) +(UINT32) (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY * sizeof (EFI_IMAGE_DATA_DIRECTORY));
+ NumberOfRvaAndSizes = Pe32Plus->NumberOfRvaAndSizes;
+ SectionsOffset = Context->ExeHdrOffset + sizeof (Pe32Plus->CommonHeader) + Pe32Plus->CommonHeader.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = Pe32Plus->CommonHeader.FileHeader.NumberOfSections;
+
+ break;
+
+ default:
+ ASSERT (FALSE);
+ return FALSE;
+ }
+ //
+ // Hash the image header till the image's checksum.
+ //
+ Result = HashUpdate (HashContext, Context->FileBuffer, ChecksumOffset);
+ if (!Result) {
+ return FALSE;
+ }
+ //
+ // Skip over the image's checksum.
+ //
+ CurrentOffset = ChecksumOffset + sizeof (UINT32);
+
+ if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < NumberOfRvaAndSizes) {
+ //
+ // Hash everything after the checksum till the security directory.
+ //
+ HashSize = SecurityDirOffset - CurrentOffset;
+ Result = HashUpdate (
+ HashContext,
+ (CONST CHAR8 *) Context->FileBuffer + CurrentOffset,
+ HashSize
+ );
+ if (!Result) {
+ return FALSE;
+ }
+ //
+ // Skip over the security directory. If no further directory exists, this
+ // will point to the top of the directory.
+ //
+ CurrentOffset = SecurityDirOffset + sizeof (EFI_IMAGE_DATA_DIRECTORY);
+ }
+ //
+ // Hash the remainders of the image header.
+ //
+ HashSize = Context->SizeOfHeaders - CurrentOffset;
+ Result = HashUpdate (
+ HashContext,
+ (CONST CHAR8 *) Context->FileBuffer + CurrentOffset,
+ HashSize
+ );
+
+ if (!Result) {
+ return FALSE;
+ }
+
+ return InternalHashSections (
+ Context,
+ SectionsOffset,
+ NumberOfSections,
+ HashUpdate,
+ HashContext
+ );
+}
+
+STATIC
+IMAGE_STATUS
+InternalApplyRelocation (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINT32 RelocOffset,
+ IN UINT32 RelocIndex,
+ IN UINT64 Adjust
+ )
+{
+ CONST EFI_IMAGE_BASE_RELOCATION *RelocWalker;
+ UINT16 RelocType;
+ UINT16 RelocOff;
+ BOOLEAN Result;
+ UINT32 RelocTarget;
+ UINT32 RemRelocTargetSize;
+ UINT32 Fixup32;
+ UINT64 Fixup64;
+ CHAR8 *Fixup;
+
+ RelocWalker = (CONST EFI_IMAGE_BASE_RELOCATION *) (
+ (CONST VOID *) ((CONST CHAR8 *) Context->FileBuffer + RelocOffset)
+ );
+
+ RelocType = IMAGE_RELOC_TYPE (RelocWalker->Relocations[RelocIndex]);
+ RelocOff = IMAGE_RELOC_OFFSET (RelocWalker->Relocations[RelocIndex]);
+
+ if (RelocType == EFI_IMAGE_REL_BASED_ABSOLUTE) {
+ return IMAGE_ERROR_SUCCESS;
+ }
+ //
+ // Determine the relocation's target address.
+ //
+ Result = OcOverflowAddU32 (
+ RelocWalker->VirtualAddress,
+ RelocOff,
+ &RelocTarget
+ );
+
+ if (Result) {
+ return IMAGE_ERROR_FAILED_RELOCATION;
+ }
+
+ Result = OcOverflowSubU32 (
+ Context->SizeOfImage,
+ RelocTarget,
+ &RemRelocTargetSize
+ );
+
+ if (Result) {
+ return IMAGE_ERROR_FAILED_RELOCATION;
+ }
+
+ Fixup = (CHAR8 *) Context->FileBuffer + RelocTarget;
+ //
+ // Apply the relocation fixup per type.
+ // If RelocationData is not NULL, store the current value of the fixup
+ // target to determine whether it has been changed during runtime
+ // execution.
+ //
+ // It is not clear how EFI_IMAGE_REL_BASED_HIGH and
+ // EFI_IMAGE_REL_BASED_LOW are supposed to be handled. While PE reference
+ // suggests to just add the high or low part of the displacement, there
+ // are concerns about how it's supposed to deal with wraparounds.
+ // As neither LLD,
+ //
+
+ switch (RelocType) {
+ case EFI_IMAGE_REL_BASED_HIGHLOW:
+ if (sizeof (UINT32) > RemRelocTargetSize) {
+ return IMAGE_ERROR_FAILED_RELOCATION;
+ }
+
+ if (RelocTarget + sizeof (UINT32) > Context->RelocDirRva
+ && Context->RelocDirRva + Context->RelocDirSize > RelocTarget) {
+ return IMAGE_ERROR_FAILED_RELOCATION;
+ }
+
+ Fixup32 = ReadUnaligned32 ((UINT32 *) (VOID *) Fixup) +(UINT32)Adjust;
+ WriteUnaligned32 ((UINT32 *) (VOID *) Fixup, Fixup32);
+
+ break;
+
+ case EFI_IMAGE_REL_BASED_DIR64:
+ if (sizeof (UINT64) > RemRelocTargetSize) {
+ return IMAGE_ERROR_FAILED_RELOCATION;
+ }
+
+ if (RelocTarget + sizeof (UINT64) > Context->RelocDirRva
+ && Context->RelocDirRva + Context->RelocDirSize > RelocTarget) {
+ return IMAGE_ERROR_FAILED_RELOCATION;
+ }
+
+ Fixup64 = ReadUnaligned64 ((UINT64 *) (VOID *) Fixup) + Adjust;
+ WriteUnaligned64 ((UINT64 *) (VOID *) Fixup, Fixup64);
+
+ break;
+
+ default:
+ return IMAGE_ERROR_FAILED_RELOCATION;
+ }
+
+ return IMAGE_ERROR_SUCCESS;
+}
+
+IMAGE_STATUS
+OcPeCoffLoaderRelocateImage (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINTN BaseAddress
+ )
+{
+ BOOLEAN Result;
+ IMAGE_STATUS Status;
+
+ UINT64 Adjust;
+ CONST EFI_IMAGE_BASE_RELOCATION *RelocWalker;
+
+ UINT32 SizeOfRelocs;
+ UINT32 NumRelocs;
+
+ UINT32 RelocDataIndex;
+
+ UINT32 RelocOffset;
+ UINT32 RelocMax;
+
+ UINT32 RelocIndex;
+
+ ASSERT (Context != NULL);
+ ASSERT (Context->RelocDirRva + Context->RelocDirSize >= Context->RelocDirRva);
+ ASSERT (Context->RelocDirRva + Context->RelocDirSize <= Context->SizeOfImage);
+ //
+ // Calculate the image's displacement from its prefered location.
+ //
+ Adjust = (UINT64) BaseAddress -Context->ImageBase;
+ //
+ // Runtime drivers should unconditionally go through the full relocation
+ // procedure early to eliminate the possibility of errors later at runtime.
+ // Runtime drivers don't have their relocations stripped, this is verified
+ // during context creation.
+ // Skip explicit relocation when the image is already loaded at its
+ // prefered location.
+ //
+ if (Context->Subsystem != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
+ && Adjust == 0) {
+ return IMAGE_ERROR_SUCCESS;
+ }
+ //
+ // Ensure relocations have not been stripped.
+ //
+ ASSERT (!Context->RelocsStripped);
+ //
+ // Apply relocation fixups to the image.
+ //
+ RelocOffset = Context->RelocDirRva;
+
+ RelocMax = Context->RelocDirRva + Context->RelocDirSize - sizeof (EFI_IMAGE_BASE_RELOCATION);
+
+ RelocDataIndex = 0;
+
+ while (RelocOffset < RelocMax) {
+ RelocWalker = (CONST EFI_IMAGE_BASE_RELOCATION *) (
+ (CONST VOID *) ((CONST CHAR8 *) Context->FileBuffer + RelocOffset)
+ );
+
+ STATIC_ASSERT (
+ (sizeof (UINT32) % OC_ALIGNOF (EFI_IMAGE_BASE_RELOCATION)) == 0,
+ "The following accesses must be performed unaligned."
+ );
+
+ Result = OcOverflowSubU32 (
+ RelocWalker->SizeOfBlock,
+ sizeof (EFI_IMAGE_BASE_RELOCATION),
+ &SizeOfRelocs
+ );
+ //
+ // Ensure no overflow has occured and there is at least one entry.
+ //
+ if (Result || SizeOfRelocs == 0 || SizeOfRelocs > RelocMax - RelocOffset) {
+ return IMAGE_ERROR_FAILED_RELOCATION;
+ }
+ //
+ // Ensure the block's size is padded to ensure proper alignment.
+ //
+ if ((RelocWalker->SizeOfBlock % sizeof (UINT32)) != 0) {
+ return IMAGE_ERROR_FAILED_RELOCATION;
+ }
+ //
+ // This division is safe due to the guarantee made above.
+ //
+ NumRelocs = SizeOfRelocs / sizeof (*RelocWalker->Relocations);
+ //
+ // Apply all relocation fixups of the current block.
+ //
+ for (RelocIndex = 0; RelocIndex < NumRelocs; ++RelocIndex) {
+ //
+ // Apply the relocation fixup per type.
+ // If RelocationData is not NULL, store the current value of the fixup
+ // target to determine whether it has been changed during runtime
+ // execution.
+ //
+ // It is not clear how EFI_IMAGE_REL_BASED_HIGH and
+ // EFI_IMAGE_REL_BASED_LOW are supposed to be handled. While PE reference
+ // suggests to just add the high or low part of the displacement, there
+ // are concerns about how it's supposed to deal with wraparounds.
+ // As neither LLD,
+ //
+ Status = InternalApplyRelocation (
+ Context,
+ RelocOffset,
+ RelocIndex,
+ Adjust
+ );
+ if (Status != IMAGE_ERROR_SUCCESS) {
+ return Status;
+ }
+ }
+
+ RelocDataIndex += NumRelocs;
+ RelocOffset += RelocWalker->SizeOfBlock;
+ }
+ //
+ // Ensure the relocation directory size matches the contained relocations.
+ //
+ if (RelocOffset != RelocMax + sizeof (EFI_IMAGE_BASE_RELOCATION)) {
+ return IMAGE_ERROR_FAILED_RELOCATION;
+ }
+
+ return IMAGE_ERROR_SUCCESS;
+}
+
+STATIC
+VOID
+InternalLoadSections (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINT32 LoadedSizeOfHeaders,
+ IN UINT32 SectionsOffset,
+ IN UINT16 NumberOfSections,
+ OUT VOID *Destination,
+ IN UINT32 DestinationSize
+ )
+{
+ CONST EFI_IMAGE_SECTION_HEADER *Sections;
+ UINT16 Index;
+ UINT32 DataSize;
+ UINT32 PreviousTopRva;
+
+ Sections = (CONST EFI_IMAGE_SECTION_HEADER *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + SectionsOffset
+ );
+
+ PreviousTopRva = LoadedSizeOfHeaders;
+
+ for (Index = 0; Index < NumberOfSections; ++Index) {
+ if (Sections[Index].VirtualSize < Sections[Index].SizeOfRawData) {
+ DataSize = Sections[Index].VirtualSize;
+ } else {
+ DataSize = Sections[Index].SizeOfRawData;
+ }
+
+ ZeroMem ((CHAR8 *) Destination + PreviousTopRva, Sections[Index].VirtualAddress - PreviousTopRva);
+ CopyMem (
+ (CHAR8 *) Destination + Sections[Index].VirtualAddress,
+ (CONST CHAR8 *) Context->FileBuffer + (Sections[Index].PointerToRawData -Context->TeStrippedOffset),
+ DataSize
+ );
+
+ PreviousTopRva = Sections[Index].VirtualAddress + DataSize;
+ }
+
+ ZeroMem (
+ (CHAR8 *) Destination + PreviousTopRva,
+ DestinationSize - PreviousTopRva
+ );
+}
+
+IMAGE_STATUS
+OcPeCoffLoaderLoadImage (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ OUT VOID *Destination,
+ IN UINT32 DestinationSize
+ )
+{
+ CHAR8 *AlignedDest;
+ UINT32 AlignOffset;
+ UINT32 AlignedSize;
+ UINT32 LoadedSizeOfHeaders;
+ CONST EFI_IMAGE_NT_HEADERS32 *SrcPe32;
+ CONST EFI_IMAGE_NT_HEADERS64 *SrcPe32Plus;
+ CONST EFI_TE_IMAGE_HEADER *SrcTe;
+ CONST EFI_IMAGE_SECTION_HEADER *Sections;
+ UINT32 SectionsOffset;
+ UINT16 NumberOfSections;
+ UINTN Address;
+ UINTN AlignedAddress;
+
+ ASSERT (Context != NULL);
+ ASSERT (Destination != NULL);
+ ASSERT (DestinationSize > 0);
+ ASSERT (DestinationSize >= Context->SectionAlignment);
+
+ Address = (UINTN)Destination;
+
+ ASSERT (!Context->RelocsStripped || Context->ImageBase == Address);
+
+ AlignedAddress = ALIGN_VALUE (Address, (UINTN) Context->SectionAlignment);
+ AlignOffset = (UINT32) (AlignedAddress - Address);
+ AlignedSize = DestinationSize - AlignOffset;
+
+ ASSERT (Context->SizeOfImage <= AlignedSize);
+
+ AlignedDest = (CHAR8 *) Destination + AlignOffset;
+
+ ZeroMem (Destination, AlignOffset);
+
+ switch (Context->ImageType) {
+ case ImageTypeTe:
+ SrcTe = (CONST EFI_TE_IMAGE_HEADER *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset
+ );
+
+ NumberOfSections = SrcTe->NumberOfSections;
+ SectionsOffset = Context->ExeHdrOffset + sizeof (*SrcTe);
+ break;
+
+ case ImageTypePe32:
+ SrcPe32 = (CONST EFI_IMAGE_NT_HEADERS32 *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset
+ );
+
+ NumberOfSections = SrcPe32->CommonHeader.FileHeader.NumberOfSections;
+ SectionsOffset = Context->ExeHdrOffset + sizeof (SrcPe32->CommonHeader) + SrcPe32->CommonHeader.FileHeader.SizeOfOptionalHeader;
+ break;
+
+ case ImageTypePe32Plus:
+ SrcPe32Plus = (CONST EFI_IMAGE_NT_HEADERS64 *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset
+ );
+
+ NumberOfSections = SrcPe32Plus->CommonHeader.FileHeader.NumberOfSections;
+ SectionsOffset = Context->ExeHdrOffset + sizeof (SrcPe32Plus->CommonHeader) + SrcPe32Plus->CommonHeader.FileHeader.SizeOfOptionalHeader;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ return IMAGE_ERROR_UNSUPPORTED;
+ }
+
+ Sections = (CONST EFI_IMAGE_SECTION_HEADER *) (CONST VOID *) (
+ (CONST CHAR8 *) Context->FileBuffer + SectionsOffset
+ );
+
+ if (Sections[0].VirtualAddress != 0 && PcdGetBool (PcdImageLoaderLoadHeader)) {
+ LoadedSizeOfHeaders = (Context->SizeOfHeaders - Context->TeStrippedOffset);
+
+ CopyMem (AlignedDest, Context->FileBuffer, LoadedSizeOfHeaders);
+ } else {
+ LoadedSizeOfHeaders = 0;
+ }
+
+ InternalLoadSections (
+ Context,
+ LoadedSizeOfHeaders,
+ SectionsOffset,
+ NumberOfSections,
+ AlignedDest,
+ AlignedSize
+ );
+ //
+ // Update the location-dependent fields to the loaded destination.
+ //
+ Context->FileBuffer = AlignedDest;
+
+ return IMAGE_ERROR_SUCCESS;
+}
diff --git a/Library/OcPeCoffLib/OcPeCoffLib.inf b/Library/OcPeCoffLib/OcPeCoffLib.inf
new file mode 100644
index 00000000..604b6bd2
--- /dev/null
+++ b/Library/OcPeCoffLib/OcPeCoffLib.inf
@@ -0,0 +1,36 @@
+## @file
+# PE/COFF Loader Library implementation.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = OcPeCoffLib
+ FILE_GUID = 556f5d10-7309-4af4-b80a-8196bd60946e
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = OcPeCoffLib
+
+[Sources]
+ OcPeCoffLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OpenCorePkg/OpenCorePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ OcGuardLib
+
+[FixedPcd]
+ gOpenCorePkgTokenSpaceGuid.PcdImageLoaderLoadHeader
+ gOpenCorePkgTokenSpaceGuid.PcdImageLoaderHashProhibitOverlap
diff --git a/OpenCorePkg.dec b/OpenCorePkg.dec
index 0eef4f14..8bd662ac 100755
--- a/OpenCorePkg.dec
+++ b/OpenCorePkg.dec
@@ -702,6 +702,9 @@
## @Prompt Allow these signature hashing algorithms for cryptographic usage.
gOpenCorePkgTokenSpaceGuid.PcdOcCryptoAllowedSigHashTypes|0x07|UINT16|0x00000501
+ gOpenCorePkgTokenSpaceGuid.PcdImageLoaderLoadHeader|TRUE|BOOLEAN|0x00000600
+ gOpenCorePkgTokenSpaceGuid.PcdImageLoaderHashProhibitOverlap|TRUE|BOOLEAN|0x00000601
+
[LibraryClasses]
## @libraryclass
OcAcpiLib|Include/Acidanthera/Library/OcAcpiLib.h
diff --git a/OpenCorePkg.dsc b/OpenCorePkg.dsc
index 20d8cbb3..6a901d98 100755
--- a/OpenCorePkg.dsc
+++ b/OpenCorePkg.dsc
@@ -108,6 +108,7 @@
OcUnicodeCollationEngLocalLib|OpenCorePkg/Library/OcUnicodeCollationEngLib/OcUnicodeCollationEngLocalLib.inf
OcVirtualFsLib|OpenCorePkg/Library/OcVirtualFsLib/OcVirtualFsLib.inf
OcXmlLib|OpenCorePkg/Library/OcXmlLib/OcXmlLib.inf
+ OcPeCoffLib|OpenCorePkg/Library/OcPeCoffLib/OcPeCoffLib.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
@@ -225,6 +226,7 @@
OpenCorePkg/Library/OcUnicodeCollationEngLib/OcUnicodeCollationEngLocalLib.inf
OpenCorePkg/Library/OcVirtualFsLib/OcVirtualFsLib.inf
OpenCorePkg/Library/OcXmlLib/OcXmlLib.inf
+ OpenCorePkg/Library/OcPeCoffLib/OcPeCoffLib.inf
OpenCorePkg/Platform/CrScreenshotDxe/CrScreenshotDxe.inf
OpenCorePkg/Platform/OpenCanopy/OpenCanopy.inf
OpenCorePkg/Platform/OpenCore/OpenCore.inf
diff --git a/Platform/OpenCore/OpenCoreUefi.c b/Platform/OpenCore/OpenCoreUefi.c
index e64e4d49..c501eaf7 100644
--- a/Platform/OpenCore/OpenCoreUefi.c
+++ b/Platform/OpenCore/OpenCoreUefi.c
@@ -516,6 +516,8 @@ OcLoadUefiSupport (
OcReinstallProtocols (Config);
+ OcInitDirectImageLoader ();
+
OcLoadAppleSecureBoot (Config);
OcLoadUefiInputSupport (Config);
diff --git a/User/Include/Pcd.h b/User/Include/Pcd.h
index 361a1f70..20fc9d64 100644
--- a/User/Include/Pcd.h
+++ b/User/Include/Pcd.h
@@ -24,6 +24,8 @@ extern UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength;
extern BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList;
extern UINT32 _gPcd_FixedAtBuild_PcdCpuNumberOfReservedVariableMtrrs;
extern UINT32 _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount;
+extern BOOLEAN _gPcd_FixedAtBuild_PcdImageLoaderHashProhibitOverlap;
+extern BOOLEAN _gPcd_FixedAtBuild_PcdImageLoaderLoadHeader;
#define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize
#define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport _gPcd_FixedAtBuild_PcdUgaConsumeSupport
@@ -42,5 +44,7 @@ extern UINT32 _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount;
// this will not be of any effect at userspace
#define _PCD_GET_MODE_64_PcdPciExpressBaseAddress 0
#define _PCD_GET_MODE_32_PcdMaximumDevicePathNodeCount _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount
+#define _PCD_GET_MODE_BOOL_PcdImageLoaderHashProhibitOverlap _gPcd_FixedAtBuild_PcdImageLoaderHashProhibitOverlap
+#define _PCD_GET_MODE_BOOL_PcdImageLoaderLoadHeader _gPcd_FixedAtBuild_PcdImageLoaderLoadHeader
#endif // OC_USER_PCD_H
diff --git a/User/Library/Pcd.c b/User/Library/Pcd.c
index 0e623870..8817e601 100644
--- a/User/Library/Pcd.c
+++ b/User/Library/Pcd.c
@@ -17,6 +17,8 @@
#define _PCD_VALUE_PcdVerifyNodeInList ((BOOLEAN)0U)
#define _PCD_VALUE_PcdCpuNumberOfReservedVariableMtrrs 0x2U
#define _PCD_VALUE_PcdMaximumDevicePathNodeCount 0U
+#define _PCD_VALUE_PcdImageLoaderHashProhibitOverlap 1U
+#define _PCD_VALUE_PcdImageLoaderLoadHeader 0U
UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize;
BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport;
@@ -30,3 +32,5 @@ UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLink
BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList;
UINT32 _gPcd_FixedAtBuild_PcdCpuNumberOfReservedVariableMtrrs = _PCD_VALUE_PcdCpuNumberOfReservedVariableMtrrs;
UINT32 _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount = _PCD_VALUE_PcdMaximumDevicePathNodeCount;
+BOOLEAN _gPcd_FixedAtBuild_PcdImageLoaderHashProhibitOverlap = _PCD_VALUE_PcdImageLoaderHashProhibitOverlap;
+BOOLEAN _gPcd_FixedAtBuild_PcdImageLoaderLoadHeader = _PCD_VALUE_PcdImageLoaderLoadHeader;
diff --git a/User/Makefile b/User/Makefile
index 1e78fffd..b4271f42 100644
--- a/User/Makefile
+++ b/User/Makefile
@@ -112,7 +112,7 @@ ifneq ($(STANDALONE),1)
#
# OcGuardLib targets.
#
- OBJS += BitOverflow.o NativeOverflow.o TripleOverflow.o
+ OBJS += BitOverflow.o NativeOverflow.o TripleOverflow.o Alignment.o
#
# OcSerializeLib targets.
#
diff --git a/Utilities/TestPeCoff/Makefile b/Utilities/TestPeCoff/Makefile
new file mode 100644
index 00000000..1bf5a058
--- /dev/null
+++ b/Utilities/TestPeCoff/Makefile
@@ -0,0 +1,11 @@
+## @file
+# Copyright (c) 2020, vit9696. All rights reserved.
+# SPDX-License-Identifier: BSD-3-Clause
+##
+
+PROJECT = PeCoff
+PRODUCT = $(PROJECT)$(SUFFIX)
+OBJS = $(PROJECT).o \
+ OcPeCoffLib.o
+VPATH = ../../Library/OcPeCoffLib
+include ../../User/Makefile
diff --git a/Utilities/TestPeCoff/PeCoff.c b/Utilities/TestPeCoff/PeCoff.c
new file mode 100644
index 00000000..1b615aaf
--- /dev/null
+++ b/Utilities/TestPeCoff/PeCoff.c
@@ -0,0 +1,149 @@
+/** @file
+ Copyright (c) 2018, vit9696. All rights reserved.
+ SPDX-License-Identifier: BSD-3-Clause
+**/
+
+#include "../Include/Uefi.h"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+/**
+
+clang -g -fsanitize=undefined,address -Wno-incompatible-pointer-types-discards-qualifiers -fshort-wchar -I../Include -I../../Include -I../../../MdePkg/Include/ -I../../../EfiPkg/Include/ -include ../Include/Base.h DiskImage.c ../../Library/OcXmlLib/OcXmlLib.c ../../Library/OcTemplateLib/OcTemplateLib.c ../../Library/OcSerializeLib/OcSerializeLib.c ../../Library/OcMiscLib/Base64Decode.c ../../Library/OcStringLib/OcAsciiLib.c ../../Library/OcAppleDiskImageLib/OcAppleDiskImageLib.c ../../Library/OcAppleDiskImageLib/OcAppleDiskImageLibInternal.c ../../Library/OcMiscLib/DataPatcher.c ../../Library/OcCompressionLib/zlib/zlib_uefi.c ../../Library/OcCompressionLib/zlib/adler32.c ../../Library/OcCompressionLib/zlib/deflate.c ../../Library/OcCompressionLib/zlib/crc32.c ../../Library/OcCompressionLib/zlib/compress.c ../../Library/OcCompressionLib/zlib/infback.c ../../Library/OcCompressionLib/zlib/inffast.c ../../Library/OcCompressionLib/zlib/inflate.c ../../Library/OcCompressionLib/zlib/inftrees.c ../../Library/OcCompressionLib/zlib/trees.c ../../Library/OcCompressionLib/zlib/uncompr.c ../../Library/OcCryptoLib/Sha256.c ../../Library/OcCryptoLib/Rsa2048Sha256.c ../../Library/OcAppleKeysLib/OcAppleKeysLib.c ../../Library/OcAppleChunklistLib/OcAppleChunklistLib.c ../../Library/OcAppleRamDiskLib/OcAppleRamDiskLib.c ../../Library/OcFileLib/ReadFile.c ../../Library/OcFileLib/FileProtocol.c -o DiskImage
+
+clang-mp-7.0 -DFUZZING_TEST=1 -g -fsanitize=undefined,address,fuzzer -Wno-incompatible-pointer-types-discards-qualifiers -fshort-wchar -I../Include -I../../Include -I../../../MdePkg/Include/ -I../../../EfiPkg/Include/ -include ../Include/Base.h DiskImage.c ../../Library/OcXmlLib/OcXmlLib.c ../../Library/OcTemplateLib/OcTemplateLib.c ../../Library/OcSerializeLib/OcSerializeLib.c ../../Library/OcMiscLib/Base64Decode.c ../../Library/OcStringLib/OcAsciiLib.c ../../Library/OcAppleDiskImageLib/OcAppleDiskImageLib.c ../../Library/OcAppleDiskImageLib/OcAppleDiskImageLibInternal.c ../../Library/OcMiscLib/DataPatcher.c ../../Library/OcCompressionLib/zlib/zlib_uefi.c ../../Library/OcCompressionLib/zlib/adler32.c ../../Library/OcCompressionLib/zlib/deflate.c ../../Library/OcCompressionLib/zlib/crc32.c ../../Library/OcCompressionLib/zlib/compress.c ../../Library/OcCompressionLib/zlib/infback.c ../../Library/OcCompressionLib/zlib/inffast.c ../../Library/OcCompressionLib/zlib/inflate.c ../../Library/OcCompressionLib/zlib/inftrees.c ../../Library/OcCompressionLib/zlib/trees.c ../../Library/OcCompressionLib/zlib/uncompr.c ../../Library/OcCryptoLib/Sha256.c ../../Library/OcCryptoLib/Rsa2048Sha256.c ../../Library/OcAppleKeysLib/OcAppleKeysLib.c ../../Library/OcAppleChunklistLib/OcAppleChunklistLib.c ../../Library/OcAppleRamDiskLib/OcAppleRamDiskLib.c../../Library/OcFileLib/ReadFile.c ../../Library/OcFileLib/FileProtocol.c -o DiskImage
+rm -rf DICT fuzz*.log ; mkdir DICT ; UBSAN_OPTIONS='halt_on_error=1' ./DiskImage -jobs=4 DICT -rss_limit_mb=4096
+
+**/
+
+#ifdef FUZZING_TEST
+#define main no_main
+#include
+#else
+#define ASAN_POISON_MEMORY_REGION(addr, size)
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size)
+#endif
+
+#if 0
+#include
+#endif
+
+EFI_STATUS
+TestImageLoad (
+ IN VOID *SourceBuffer,
+ IN UINTN SourceSize
+ )
+{
+ EFI_STATUS Status;
+ IMAGE_STATUS ImageStatus;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_PHYSICAL_ADDRESS DestinationArea;
+ VOID *DestinationBuffer;
+
+
+ //
+ // Initialize the image context.
+ //
+ ImageStatus = OcPeCoffLoaderInitializeContext (
+ &ImageContext,
+ SourceBuffer,
+ SourceSize
+ );
+ if (ImageStatus != IMAGE_ERROR_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff init failure - %d\n", ImageStatus));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Reject images that are not meant for the platform's architecture.
+ //
+ if (ImageContext.Machine != IMAGE_FILE_MACHINE_X64) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff wrong machine - %x\n", ImageContext.Machine));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Reject RT drivers for the moment.
+ //
+ if (ImageContext.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff no support for RT drivers\n"));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Allocate the image destination memory.
+ // FIXME: RT drivers require EfiRuntimeServicesCode.
+ //
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage),
+ &DestinationArea
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DestinationBuffer = (VOID *)(UINTN) DestinationArea;
+
+ //
+ // Load SourceBuffer into DestinationBuffer.
+ //
+ ImageStatus = OcPeCoffLoaderLoadImage (
+ &ImageContext,
+ DestinationBuffer,
+ ImageContext.SizeOfImage
+ );
+ if (ImageStatus != IMAGE_ERROR_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff load image error - %d\n", ImageStatus));
+ FreePages (DestinationBuffer, EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Relocate the loaded image to the destination address.
+ //
+ ImageStatus = OcPeCoffLoaderRelocateImage (
+ &ImageContext,
+ (UINTN) DestinationBuffer
+ );
+
+ FreePages (DestinationBuffer, EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage));
+
+ if (ImageStatus != IMAGE_ERROR_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "OCB: PeCoff relocate image error - %d\n", ImageStatus));
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+int main (int argc, char *argv[]) {
+ if (argc < 2) {
+ printf ("Please provide a valid PE image path\n");
+ return -1;
+ }
+
+ PcdGet32 (PcdFixedDebugPrintErrorLevel) |= DEBUG_INFO;
+ PcdGet32 (PcdDebugPrintErrorLevel) |= DEBUG_INFO;
+
+ uint8_t *Image;
+ uint32_t ImageSize;
+
+ if ((Image = readFile (argv[1], &ImageSize)) == NULL) {
+ printf ("Read fail\n");
+ return 1;
+ }
+
+ EFI_STATUS Status = TestImageLoad (Image, ImageSize);
+ free(Image);
+ if (EFI_ERROR (Status)) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/build_oc.tool b/build_oc.tool
index 46e79813..be1fa972 100755
--- a/build_oc.tool
+++ b/build_oc.tool
@@ -14,6 +14,7 @@ buildutil() {
"TestImg4"
"TestKextInject"
"TestMacho"
+ "TestPeCoff"
"TestRsaPreprocess"
"TestSmbios"
)