diff --git a/Changelog.md b/Changelog.md
index abf32a20cf8b..f306b158ff95 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -5,6 +5,7 @@ OpenCore Changelog
- Fixed hang while generating boot entries on some systems
- Added `efidebug.tool` support for 32-bit on 32-bit using GDB or LLDB
- Fixed potential incorrect values in kernel image capabilities calculation
+- Added `FixupAppleEfiImages` quirk to allow booting Mac OS X 10.4 and 10.5 boot.efi images on modern secure image loaders
#### v0.9.5
- Fixed GUID formatting for legacy NVRAM saving
diff --git a/Docs/Configuration.tex b/Docs/Configuration.tex
index c4ff79ab6a2e..721f4a5bdf0c 100755
--- a/Docs/Configuration.tex
+++ b/Docs/Configuration.tex
@@ -1610,6 +1610,34 @@ \subsection{Quirks Properties}\label{booterpropsquirks}
\texttt{RebuildAppleMemoryMap} if the firmware supports memory attributes table (MAT).
Refer to the \texttt{OCABC: MAT support is 1/0} log entry to determine whether MAT is supported.
+\item
+ \texttt{FixupAppleEfiImages}\\
+ \textbf{Type}: \texttt{plist\ boolean}\\
+ \textbf{Failsafe}: \texttt{false}\\
+ \textbf{Description}: Fix errors in early Mac OS X boot.efi images.
+
+ Modern secure PE loaders will refuse to load \texttt{boot.efi} images from
+ Mac OS X 10.4 and 10.5 due to these files containing \texttt{W\^{}X} errors
+ and illegal overlapping sections.
+
+ This quirk detects these issues and pre-processes such images in memory,
+ so that a modern loader can accept them.
+
+ Pre-processing in memory is incompatible with secure boot, as the image loaded
+ is not the image on disk, so you cannot sign files which are loaded in this way
+ based on their original disk image contents.
+ Certain firmware will offer to register the hash of new, unknown images - this would
+ still work. On the other hand, it is not particularly realistic to want to
+ start such early, insecure images with secure boot anyway.
+
+ \emph{Note 1}: The quirk is only applied to Apple-specific `fat' (both 32-bit and 64-bit
+ versions in one image) \texttt{.efi} files, and is never applied during the Apple secure
+ boot path for newer macOS.
+
+ \emph{Note 2}: The quirk is only needed for loading Mac OS X 10.4 and 10.5, and even then
+ only if the firmware itself includes a modern, more secure PE COFF image loader. This includes
+ current builds of OpenDuet.
+
\item
\texttt{ForceBooterSignature}\\
\textbf{Type}: \texttt{plist\ boolean}\\
diff --git a/Docs/Sample.plist b/Docs/Sample.plist
index 607384342e7a..1c60f841a61c 100644
--- a/Docs/Sample.plist
+++ b/Docs/Sample.plist
@@ -319,6 +319,8 @@
EnableWriteUnprotector
+ FixupAppleEfiImages
+
ForceBooterSignature
ForceExitBootServices
diff --git a/Docs/SampleCustom.plist b/Docs/SampleCustom.plist
index 3b8ee41942b8..61843ed69d5c 100644
--- a/Docs/SampleCustom.plist
+++ b/Docs/SampleCustom.plist
@@ -319,6 +319,8 @@
EnableWriteUnprotector
+ FixupAppleEfiImages
+
ForceBooterSignature
ForceExitBootServices
diff --git a/Include/Acidanthera/Library/OcBootManagementLib.h b/Include/Acidanthera/Library/OcBootManagementLib.h
index b443863a85b5..e0599da3d61c 100644
--- a/Include/Acidanthera/Library/OcBootManagementLib.h
+++ b/Include/Acidanthera/Library/OcBootManagementLib.h
@@ -1814,7 +1814,8 @@ OcRegisterBootstrapBootOption (
**/
VOID
OcImageLoaderInit (
- IN CONST BOOLEAN ProtectUefiServices
+ IN CONST BOOLEAN ProtectUefiServices,
+ IN CONST BOOLEAN FixupAppleEfiImages
);
/**
diff --git a/Include/Acidanthera/Library/OcConfigurationLib.h b/Include/Acidanthera/Library/OcConfigurationLib.h
index bb2a04a11ecc..470f54e8ccb9 100644
--- a/Include/Acidanthera/Library/OcConfigurationLib.h
+++ b/Include/Acidanthera/Library/OcConfigurationLib.h
@@ -142,6 +142,7 @@ OC_DECLARE (OC_BOOTER_PATCH_ARRAY)
_(BOOLEAN , DiscardHibernateMap , , FALSE , ()) \
_(BOOLEAN , EnableSafeModeSlide , , FALSE , ()) \
_(BOOLEAN , EnableWriteUnprotector , , FALSE , ()) \
+ _(BOOLEAN , FixupAppleEfiImages , , FALSE , ()) \
_(BOOLEAN , ForceBooterSignature , , FALSE , ()) \
_(BOOLEAN , ForceExitBootServices , , FALSE , ()) \
_(BOOLEAN , ProtectMemoryRegions , , FALSE , ()) \
diff --git a/Include/Acidanthera/Library/OcPeCoffExtLib.h b/Include/Acidanthera/Library/OcPeCoffExtLib.h
index 404ddf5564ab..09bd5263336f 100644
--- a/Include/Acidanthera/Library/OcPeCoffExtLib.h
+++ b/Include/Acidanthera/Library/OcPeCoffExtLib.h
@@ -43,4 +43,19 @@ PeCoffGetApfsDriverVersion (
OUT APFS_DRIVER_VERSION **DriverVersionPtr
);
+/**
+ Detect and patch W^X and section overlap errors in legacy boot.efi.
+ Expected to make changes in 10.4 and 10.5 only.
+
+ @param[in] DriverBuffer Image buffer.
+ @param[in] DriverSize Size of the image.
+
+ @retval EFI_SUCCESS on success.
+**/
+EFI_STATUS
+OcPatchLegacyEfi (
+ IN VOID *DriverBuffer,
+ IN UINT32 DriverSize
+ );
+
#endif // OC_PE_COFF_EXT_LIB_H
diff --git a/Library/OcBootManagementLib/ImageLoader.c b/Library/OcBootManagementLib/ImageLoader.c
index 5971b140a867..baca32aa44b4 100644
--- a/Library/OcBootManagementLib/ImageLoader.c
+++ b/Library/OcBootManagementLib/ImageLoader.c
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -82,6 +83,7 @@ STATIC EFI_HANDLE mImageLoaderCapsHandle;
STATIC BOOLEAN mImageLoaderEnabled;
STATIC BOOLEAN mProtectUefiServices;
+STATIC BOOLEAN mFixupAppleEfiImages;
STATIC EFI_IMAGE_LOAD mPreservedLoadImage;
STATIC EFI_IMAGE_START mPreservedStartImage;
@@ -867,6 +869,26 @@ InternalEfiLoadImage (
// Determine its capabilities.
//
if (!EFI_ERROR (Status) && (RealSize != SourceSize) && (RealSize >= EFI_PAGE_SIZE)) {
+ if (mFixupAppleEfiImages) {
+ if (SecureBootStatus == EFI_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "OCB: Secure boot, fixup legacy efi ignored\n"));
+ } else {
+ Status = OcPatchLegacyEfi (SourceBuffer, RealSize);
+ //
+ // Error can mean incompletely patched image, so we should fail.
+ // Any error not the result of incomplete patching would in general not load anyway.
+ //
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "OCB: PatchLegacyEfi - %r\n", Status));
+ if (AllocatedBuffer != NULL) {
+ FreePool (AllocatedBuffer);
+ }
+
+ return Status;
+ }
+ }
+ }
+
mImageLoaderCaps = DetectCapabilities (SourceBuffer, RealSize);
}
@@ -1089,10 +1111,12 @@ InternalEfiExit (
VOID
OcImageLoaderInit (
- IN CONST BOOLEAN ProtectUefiServices
+ IN CONST BOOLEAN ProtectUefiServices,
+ IN CONST BOOLEAN FixupAppleEfiImages
)
{
mProtectUefiServices = ProtectUefiServices;
+ mFixupAppleEfiImages = FixupAppleEfiImages;
mOriginalEfiLoadImage = gBS->LoadImage;
mOriginalEfiStartImage = gBS->StartImage;
diff --git a/Library/OcBootManagementLib/OcBootManagementLib.inf b/Library/OcBootManagementLib/OcBootManagementLib.inf
index efb5743b9a32..f782dd757eef 100644
--- a/Library/OcBootManagementLib/OcBootManagementLib.inf
+++ b/Library/OcBootManagementLib/OcBootManagementLib.inf
@@ -110,6 +110,7 @@
OcFlexArrayLib
OcMachoLib
OcMiscLib
+ OcPeCoffExtLib
OcRtcLib
OcTypingLib
OcVariableLib
diff --git a/Library/OcConfigurationLib/OcConfigurationLib.c b/Library/OcConfigurationLib/OcConfigurationLib.c
index 3d0df633100c..09749e8769a3 100644
--- a/Library/OcConfigurationLib/OcConfigurationLib.c
+++ b/Library/OcConfigurationLib/OcConfigurationLib.c
@@ -189,6 +189,7 @@ OC_SCHEMA
OC_SCHEMA_BOOLEAN_IN ("DiscardHibernateMap", OC_GLOBAL_CONFIG, Booter.Quirks.DiscardHibernateMap),
OC_SCHEMA_BOOLEAN_IN ("EnableSafeModeSlide", OC_GLOBAL_CONFIG, Booter.Quirks.EnableSafeModeSlide),
OC_SCHEMA_BOOLEAN_IN ("EnableWriteUnprotector", OC_GLOBAL_CONFIG, Booter.Quirks.EnableWriteUnprotector),
+ OC_SCHEMA_BOOLEAN_IN ("FixupAppleEfiImages", OC_GLOBAL_CONFIG, Booter.Quirks.FixupAppleEfiImages),
OC_SCHEMA_BOOLEAN_IN ("ForceBooterSignature", OC_GLOBAL_CONFIG, Booter.Quirks.ForceBooterSignature),
OC_SCHEMA_BOOLEAN_IN ("ForceExitBootServices", OC_GLOBAL_CONFIG, Booter.Quirks.ForceExitBootServices),
OC_SCHEMA_BOOLEAN_IN ("ProtectMemoryRegions", OC_GLOBAL_CONFIG, Booter.Quirks.ProtectMemoryRegions),
diff --git a/Library/OcMainLib/OpenCoreUefi.c b/Library/OcMainLib/OpenCoreUefi.c
index a85b39768838..35e26c736808 100644
--- a/Library/OcMainLib/OpenCoreUefi.c
+++ b/Library/OcMainLib/OpenCoreUefi.c
@@ -899,7 +899,7 @@ OcLoadUefiSupport (
OcReinstallProtocols (Config);
- OcImageLoaderInit (Config->Booter.Quirks.ProtectUefiServices);
+ OcImageLoaderInit (Config->Booter.Quirks.ProtectUefiServices, Config->Booter.Quirks.FixupAppleEfiImages);
OcLoadAppleSecureBoot (Config, CpuInfo);
diff --git a/Library/OcPeCoffExtLib/BasePeCoffLib2Internals.h b/Library/OcPeCoffExtLib/BasePeCoffLib2Internals.h
new file mode 100644
index 000000000000..3d7f00952863
--- /dev/null
+++ b/Library/OcPeCoffExtLib/BasePeCoffLib2Internals.h
@@ -0,0 +1,55 @@
+/** @file
+ Provides shared private definitions across this library.
+
+ Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+**/
+
+#ifndef BASE_PE_COFF_LIB2_INTERNALS_H_
+#define BASE_PE_COFF_LIB2_INTERNALS_H_
+
+//
+// PcdImageLoaderRelocTypePolicy bits.
+//
+
+///
+/// If set, ARM Thumb Image relocations are supported.
+///
+#define PCD_RELOC_TYPE_POLICY_ARM BIT0
+
+///
+/// Denotes the alignment requirement for Image certificate sizes.
+///
+#define IMAGE_CERTIFICATE_ALIGN 8U
+
+//
+// The PE/COFF specification guarantees an 8 Byte alignment for certificate
+// sizes. This is larger than the alignment requirement for WIN_CERTIFICATE
+// implied by the UEFI ABI. ASSERT this holds.
+//
+STATIC_ASSERT (
+ ALIGNOF (WIN_CERTIFICATE) <= IMAGE_CERTIFICATE_ALIGN,
+ "The PE/COFF specification guarantee does not suffice."
+ );
+
+//
+// The 4 Byte alignment guaranteed by the PE/COFF specification has been
+// replaced with ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK) for proof simplicity.
+// This obviously was the original intention of the specification. ASSERT in
+// case the equality is not given.
+//
+STATIC_ASSERT (
+ sizeof (UINT32) == ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK),
+ "The current model violates the PE/COFF specification"
+ );
+
+// FIXME:
+RETURN_STATUS
+PeCoffLoadImageInplaceNoBase (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
+ );
+
+#endif // BASE_PE_COFF_LIB_INTERNALS_H_
diff --git a/Library/OcPeCoffExtLib/OcPeCoffExtInternal.h b/Library/OcPeCoffExtLib/OcPeCoffExtInternal.h
index e31d7eb0257f..647e6031b27b 100644
--- a/Library/OcPeCoffExtLib/OcPeCoffExtInternal.h
+++ b/Library/OcPeCoffExtLib/OcPeCoffExtInternal.h
@@ -29,4 +29,31 @@ typedef struct APPLE_SIGNATURE_CONTEXT_ {
UINT8 Signature[256];
} APPLE_SIGNATURE_CONTEXT;
+/**
+ Fix W^X and section overlap issues in loaded TE, PE32, or PE32+ Image in
+ memory while initialising Context.
+
+ Closely based on PeCoffInitializeContext from PeCoffLib2.
+
+ The approach of modifying the image in memory is basically incompatible
+ with secure boot, athough:
+ a) Certain firmware may allow optionally registering the hash of any
+ image which does not load, which would still work.
+ b) It is fairly crazy anyway to want to apply secure boot to the old,
+ insecure .efi files which need these fixups.
+
+ @param[out] Context The context describing the Image.
+ @param[in] FileBuffer The file data to parse as PE Image.
+ @param[in] FileSize The size, in Bytes, of FileBuffer.
+
+ @retval RETURN_SUCCESS The Image context has been initialised successfully.
+ @retval other The file data is malformed.
+**/
+RETURN_STATUS
+InternalPeCoffFixup (
+ OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN CONST VOID *FileBuffer,
+ IN UINT32 FileSize
+ );
+
#endif // OC_PE_COFF_EXT_INTERNAL_H
diff --git a/Library/OcPeCoffExtLib/OcPeCoffExtLib.c b/Library/OcPeCoffExtLib/OcPeCoffExtLib.c
index 8192e7fda99a..044cec857bf0 100644
--- a/Library/OcPeCoffExtLib/OcPeCoffExtLib.c
+++ b/Library/OcPeCoffExtLib/OcPeCoffExtLib.c
@@ -33,6 +33,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include
#include
#include
+#include
#include
#include "OcPeCoffExtInternal.h"
@@ -495,7 +496,7 @@ PeCoffGetApfsDriverVersion (
|| (ImageContext.ImageType != PeCoffLoaderTypePe32Plus)
|| (ImageContext.Subsystem != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER))
{
- DEBUG ((DEBUG_INFO, "OCPE: PeCoff unsupported image\n"));
+ DEBUG ((DEBUG_INFO, "OCPE: PeCoff apfs unsupported image\n"));
return EFI_UNSUPPORTED;
}
@@ -543,3 +544,25 @@ PeCoffGetApfsDriverVersion (
*DriverVersionPtr = DriverVersion;
return EFI_SUCCESS;
}
+
+EFI_STATUS
+OcPatchLegacyEfi (
+ IN VOID *DriverBuffer,
+ IN UINT32 DriverSize
+ )
+{
+ EFI_STATUS ImageStatus;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ ImageStatus = InternalPeCoffFixup (
+ &ImageContext,
+ DriverBuffer,
+ DriverSize
+ );
+ if (EFI_ERROR (ImageStatus)) {
+ DEBUG ((DEBUG_WARN, "OCPE: PeCoff legacy patch failure - %r\n", ImageStatus));
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Library/OcPeCoffExtLib/OcPeCoffExtLib.inf b/Library/OcPeCoffExtLib/OcPeCoffExtLib.inf
index e5e14faddda1..5bb07f849329 100644
--- a/Library/OcPeCoffExtLib/OcPeCoffExtLib.inf
+++ b/Library/OcPeCoffExtLib/OcPeCoffExtLib.inf
@@ -25,12 +25,13 @@
#
-# VALID_ARCHITECTURES = X64
+# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
OcPeCoffExtInternal.h
OcPeCoffExtLib.c
+ OcPeCoffFixup.c
[Packages]
MdePkg/MdePkg.dec
@@ -48,7 +49,13 @@
DebugLib
OcAppleKeysLib
OcCryptoLib
+ OcStringLib
[Guids]
gAppleEfiCertificateGuid
gEfiCertTypeRsa2048Sha256Guid
+
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAlignmentPolicy
+ gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAllowMisalignedOffset
+ gEfiMdePkgTokenSpaceGuid.PcdDebugRaisePropertyMask
diff --git a/Library/OcPeCoffExtLib/OcPeCoffFixup.c b/Library/OcPeCoffExtLib/OcPeCoffFixup.c
new file mode 100644
index 000000000000..72142fd83222
--- /dev/null
+++ b/Library/OcPeCoffExtLib/OcPeCoffFixup.c
@@ -0,0 +1,805 @@
+/** @file
+ Implements APIs to fix certain issues in legacy EFI files in memory before loading.
+
+ Very closely based on MdePkg/Library/BasePeCoffLib2/PeCoffInit.c, and intentionally
+ kept more similar to that file than it would otherwise need to be, to easily allow
+ diffing and importing future changes if required.
+
+ Copyright (c) 2023, Mike Beaton, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ Portions copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Portions copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+**/
+
+#include
+#include
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "BasePeCoffLib2Internals.h"
+
+//
+// FIXME: Provide an API to destruct the context?
+//
+
+/**
+ Verify the Image section Headers and initialise the Image memory space size.
+
+ The first Image section must be the beginning of the memory space, or be
+ contiguous to the aligned Image Headers.
+ Sections must be disjoint and, depending on the policy, contiguous in the
+ memory space space.
+ The section data must be in bounds bounds of the file buffer.
+
+ @param[in,out] Context The context describing the Image. Must have been
+ initialised by PeCoffInitializeContext().
+ @param[in] FileSize The size, in Bytes, of Context->FileBuffer.
+ @param[out] StartAddress On output, the RVA of the first Image section.
+
+ @retval RETURN_SUCCESS The Image section Headers are well-formed.
+ @retval other The Image section Headers are malformed.
+**/
+STATIC
+RETURN_STATUS
+InternalVerifySections (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINT32 FileSize,
+ OUT UINT32 *StartAddress
+ )
+{
+ BOOLEAN Overflow;
+ UINT32 NextSectRva;
+ UINT32 FixupOffset;
+ UINT32 FixupVirtualSize;
+ CHAR8 SectionName[EFI_IMAGE_SIZEOF_SHORT_NAME + 1];
+ UINT32 SectRawEnd;
+ UINT16 SectionIndex;
+ EFI_IMAGE_SECTION_HEADER *Sections;
+
+ ASSERT (Context != NULL);
+ ASSERT (IS_POW2 (Context->SectionAlignment));
+ ASSERT (StartAddress != NULL);
+ //
+ // Images without Sections have no usable data, disallow them.
+ //
+ if (Context->NumberOfSections == 0) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ Sections = (EFI_IMAGE_SECTION_HEADER *)(VOID *)(
+ (CHAR8 *)Context->FileBuffer + Context->SectionsOffset
+ );
+ //
+ // The first Image section must begin the Image memory space, or it must be
+ // adjacent to the Image Headers.
+ //
+ if (Sections[0].VirtualAddress == 0) {
+ // FIXME: Add PCD to disallow.
+ NextSectRva = 0;
+ } else {
+ //
+ // Choose the raw or aligned Image Headers size depending on whether loading
+ // unaligned Sections is allowed.
+ //
+ if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
+ Overflow = BaseOverflowAlignUpU32 (
+ Context->SizeOfHeaders,
+ Context->SectionAlignment,
+ &NextSectRva
+ );
+ if (Overflow) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+ } else {
+ NextSectRva = Context->SizeOfHeaders;
+ }
+ }
+
+ SectionName[L_STR_LEN (SectionName)] = '\0';
+ *StartAddress = NextSectRva;
+ //
+ // Verify all Image sections are valid.
+ //
+ for (SectionIndex = 0; SectionIndex < Context->NumberOfSections; ++SectionIndex) {
+ AsciiStrnCpyS (SectionName, L_STR_SIZE (SectionName), (CHAR8 *)Sections[SectionIndex].Name, EFI_IMAGE_SIZEOF_SHORT_NAME);
+ //
+ // Fix up W^X errors in memory.
+ //
+ if ((Sections[SectionIndex].Characteristics & (EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_WRITE)) == (EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_WRITE)) {
+ Sections[SectionIndex].Characteristics &= ~EFI_IMAGE_SCN_MEM_EXECUTE;
+ DEBUG ((DEBUG_INFO, "OCPE: Fixup W^X for %a\n", SectionName));
+ }
+
+ //
+ // Verify the Image sections are disjoint (relaxed) or adjacent (strict)
+ // depending on whether unaligned Image sections may be loaded or not.
+ // Unaligned Image sections have been observed with iPXE Option ROMs and old
+ // Apple Mac OS X bootloaders.
+ //
+ if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
+ if (Sections[SectionIndex].VirtualAddress != NextSectRva) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+ } else {
+ if (Sections[SectionIndex].VirtualAddress < NextSectRva) {
+ //
+ // Disallow overlap fixup unless we're ovelapping into an empty section.
+ //
+ if (Sections[SectionIndex].SizeOfRawData > 0) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Fix up section overlap errors in memory.
+ //
+ FixupOffset = NextSectRva - Sections[SectionIndex].VirtualAddress;
+ FixupVirtualSize = Sections[SectionIndex].VirtualSize;
+ if (FixupOffset > Sections[SectionIndex].VirtualSize) {
+ Sections[SectionIndex].VirtualSize = 0;
+ } else {
+ Sections[SectionIndex].VirtualSize -= FixupOffset;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "OCPE: Fixup section overlap for %a 0x%X(0x%X)->0x%X(0x%X)\n",
+ SectionName,
+ Sections[SectionIndex].VirtualAddress,
+ FixupVirtualSize,
+ NextSectRva,
+ Sections[SectionIndex].VirtualSize
+ ));
+ Sections[SectionIndex].VirtualAddress = NextSectRva;
+ }
+
+ //
+ // If the Image section address is not aligned by the Image section
+ // alignment, fall back to important architecture-specific page sizes if
+ // possible, to ensure the Image can have memory protection applied.
+ // Otherwise, report no alignment for the Image.
+ //
+ if (!IS_ALIGNED (Sections[SectionIndex].VirtualAddress, Context->SectionAlignment)) {
+ STATIC_ASSERT (
+ DEFAULT_PAGE_ALLOCATION_GRANULARITY <= RUNTIME_PAGE_ALLOCATION_GRANULARITY,
+ "This code must be adapted to consider the reversed order."
+ );
+
+ if (IS_ALIGNED (Sections[SectionIndex].VirtualAddress, RUNTIME_PAGE_ALLOCATION_GRANULARITY)) {
+ Context->SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ } else if ( (DEFAULT_PAGE_ALLOCATION_GRANULARITY < RUNTIME_PAGE_ALLOCATION_GRANULARITY)
+ && IS_ALIGNED (Sections[SectionIndex].VirtualAddress, DEFAULT_PAGE_ALLOCATION_GRANULARITY))
+ {
+ Context->SectionAlignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+ } else {
+ Context->SectionAlignment = 1;
+ }
+ }
+ }
+
+ //
+ // Verify the Image sections with data are in bounds of the file buffer.
+ //
+ if (Sections[SectionIndex].SizeOfRawData > 0) {
+ Overflow = BaseOverflowAddU32 (
+ Sections[SectionIndex].PointerToRawData,
+ Sections[SectionIndex].SizeOfRawData,
+ &SectRawEnd
+ );
+ if (Overflow) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ if (SectRawEnd > FileSize) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+ }
+
+ //
+ // Determine the end of the current Image section.
+ //
+ Overflow = BaseOverflowAddU32 (
+ Sections[SectionIndex].VirtualAddress,
+ Sections[SectionIndex].VirtualSize,
+ &NextSectRva
+ );
+ if (Overflow) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // VirtualSize does not need to be aligned, so align the result if needed.
+ //
+ if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
+ Overflow = BaseOverflowAlignUpU32 (
+ NextSectRva,
+ Context->SectionAlignment,
+ &NextSectRva
+ );
+ if (Overflow) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+ }
+ }
+
+ //
+ // Set SizeOfImage to the aligned end address of the last ImageSection.
+ //
+ if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
+ Context->SizeOfImage = NextSectRva;
+ } else {
+ //
+ // Because VirtualAddress is aligned by SectionAlignment for all Image
+ // sections, and they are disjoint and ordered by VirtualAddress,
+ // VirtualAddress + VirtualSize must be safe to align by SectionAlignment for
+ // all but the last Image section.
+ // Determine the strictest common alignment that the last section's end is
+ // safe to align to.
+ //
+ Overflow = BaseOverflowAlignUpU32 (
+ NextSectRva,
+ Context->SectionAlignment,
+ &Context->SizeOfImage
+ );
+ if (Overflow) {
+ Context->SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ Overflow = BaseOverflowAlignUpU32 (
+ NextSectRva,
+ Context->SectionAlignment,
+ &Context->SizeOfImage
+ );
+ if ( (DEFAULT_PAGE_ALLOCATION_GRANULARITY < RUNTIME_PAGE_ALLOCATION_GRANULARITY)
+ && Overflow)
+ {
+ Context->SectionAlignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+ Overflow = BaseOverflowAlignUpU32 (
+ NextSectRva,
+ Context->SectionAlignment,
+ &Context->SizeOfImage
+ );
+ }
+
+ if (Overflow) {
+ Context->SectionAlignment = 1;
+ }
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Verify the basic Image Relocation information.
+
+ The preferred Image load address must be aligned by the section alignment.
+ The Relocation Directory must be contained within the Image section memory.
+ The Relocation Directory must be sufficiently aligned in memory.
+
+ @param[in] Context The context describing the Image. Must have been
+ initialised by PeCoffInitializeContext().
+ @param[in] StartAddress The RVA of the first Image section.
+
+ @retval RETURN_SUCCESS The basic Image Relocation information is well-formed.
+ @retval other The basic Image Relocation information is malformed.
+**/
+STATIC
+RETURN_STATUS
+InternalValidateRelocInfo (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINT32 StartAddress
+ )
+{
+ BOOLEAN Overflow;
+ UINT32 SectRvaEnd;
+
+ ASSERT (Context != NULL);
+ ASSERT (!Context->RelocsStripped || Context->RelocDirSize == 0);
+ //
+ // If the Base Relocations have not been stripped, verify their Directory.
+ //
+ if (Context->RelocDirSize != 0) {
+ //
+ // Verify the Relocation Directory is not empty.
+ //
+ if (sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK) > Context->RelocDirSize) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the Relocation Directory does not overlap with the Image Headers.
+ //
+ if (StartAddress > Context->RelocDirRva) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the Relocation Directory is contained in the Image memory space.
+ //
+ Overflow = BaseOverflowAddU32 (
+ Context->RelocDirRva,
+ Context->RelocDirSize,
+ &SectRvaEnd
+ );
+ if (Overflow || (SectRvaEnd > Context->SizeOfImage)) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the Relocation Directory start is sufficiently aligned.
+ //
+ if (!IS_ALIGNED (Context->RelocDirRva, ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK))) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+ }
+
+ //
+ // Verify the preferred Image load address is sufficiently aligned.
+ //
+ // FIXME: Only with force-aligned sections? What to do with XIP?
+ if (!IS_ALIGNED (Context->ImageBase, (UINT64)Context->SectionAlignment)) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Verify the PE32 or PE32+ Image and initialise Context.
+
+ Used offsets and ranges must be aligned and in the bounds of the raw file.
+ Image section Headers and basic Relocation information must be Well-formed.
+
+ @param[in,out] Context The context describing the Image. Must have been
+ initialised by PeCoffInitializeContext().
+ @param[in] FileSize The size, in Bytes, of Context->FileBuffer.
+
+ @retval RETURN_SUCCESS The PE Image is Well-formed.
+ @retval other The PE Image is malformed.
+**/
+STATIC
+RETURN_STATUS
+InternalInitializePe (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN UINT32 FileSize
+ )
+{
+ BOOLEAN Overflow;
+ CONST EFI_IMAGE_NT_HEADERS_COMMON_HDR *PeCommon;
+ CONST EFI_IMAGE_NT_HEADERS32 *Pe32;
+ CONST EFI_IMAGE_NT_HEADERS64 *Pe32Plus;
+ CONST CHAR8 *OptHdrPtr;
+ UINT32 HdrSizeWithoutDataDir;
+ UINT32 MinSizeOfOptionalHeader;
+ UINT32 MinSizeOfHeaders;
+ CONST EFI_IMAGE_DATA_DIRECTORY *RelocDir;
+ CONST EFI_IMAGE_DATA_DIRECTORY *SecDir;
+ UINT32 SecDirEnd;
+ UINT32 NumberOfRvaAndSizes;
+ RETURN_STATUS Status;
+ UINT32 StartAddress;
+
+ ASSERT (Context != NULL);
+ ASSERT (sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) + sizeof (UINT16) <= FileSize - Context->ExeHdrOffset);
+ if (!PcdGetBool (PcdImageLoaderAllowMisalignedOffset)) {
+ ASSERT (IS_ALIGNED (Context->ExeHdrOffset, ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR)));
+ }
+
+ //
+ // Locate the PE Optional Header.
+ //
+ OptHdrPtr = (CONST CHAR8 *)Context->FileBuffer + Context->ExeHdrOffset;
+ OptHdrPtr += sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR);
+
+ STATIC_ASSERT (
+ IS_ALIGNED (ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR), ALIGNOF (UINT16))
+ && IS_ALIGNED (sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR), ALIGNOF (UINT16)),
+ "The following operation might be an unaligned access."
+ );
+ //
+ // Determine the type of and retrieve data from the PE Optional Header.
+ // Do not retrieve SizeOfImage as the value usually does not follow the
+ // specification. Even if the value is large enough to hold the last Image
+ // section, it may not be aligned, or it may be too large. No data can
+ // possibly be loaded past the last Image section anyway.
+ //
+ switch (*(CONST UINT16 *)(CONST VOID *)OptHdrPtr) {
+ case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
+ //
+ // Verify the PE32 header is in bounds of the file buffer.
+ //
+ if (sizeof (*Pe32) > FileSize - Context->ExeHdrOffset) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // The PE32 header offset is always sufficiently aligned.
+ //
+ STATIC_ASSERT (
+ ALIGNOF (EFI_IMAGE_NT_HEADERS32) <= ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR),
+ "The following operations may be unaligned."
+ );
+ //
+ // Populate the common data with information from the Optional Header.
+ //
+ Pe32 = (CONST EFI_IMAGE_NT_HEADERS32 *)(CONST VOID *)(
+ (CONST CHAR8 *)Context->FileBuffer + Context->ExeHdrOffset
+ );
+
+ Context->ImageType = PeCoffLoaderTypePe32;
+ Context->Subsystem = Pe32->Subsystem;
+ Context->SizeOfHeaders = Pe32->SizeOfHeaders;
+ Context->ImageBase = Pe32->ImageBase;
+ Context->AddressOfEntryPoint = Pe32->AddressOfEntryPoint;
+ Context->SectionAlignment = Pe32->SectionAlignment;
+
+ RelocDir = Pe32->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
+ SecDir = Pe32->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_SECURITY;
+
+ PeCommon = &Pe32->CommonHeader;
+ NumberOfRvaAndSizes = Pe32->NumberOfRvaAndSizes;
+ HdrSizeWithoutDataDir = sizeof (EFI_IMAGE_NT_HEADERS32) - sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR);
+
+ break;
+
+ case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+ //
+ // Verify the PE32+ header is in bounds of the file buffer.
+ //
+ if (sizeof (*Pe32Plus) > FileSize - Context->ExeHdrOffset) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the PE32+ header offset is sufficiently aligned.
+ //
+ if ( !PcdGetBool (PcdImageLoaderAllowMisalignedOffset)
+ && !IS_ALIGNED (Context->ExeHdrOffset, ALIGNOF (EFI_IMAGE_NT_HEADERS64)))
+ {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Populate the common data with information from the Optional Header.
+ //
+ Pe32Plus = (CONST EFI_IMAGE_NT_HEADERS64 *)(CONST VOID *)(
+ (CONST CHAR8 *)Context->FileBuffer + Context->ExeHdrOffset
+ );
+
+ Context->ImageType = PeCoffLoaderTypePe32Plus;
+ Context->Subsystem = Pe32Plus->Subsystem;
+ Context->SizeOfHeaders = Pe32Plus->SizeOfHeaders;
+ Context->ImageBase = Pe32Plus->ImageBase;
+ Context->AddressOfEntryPoint = Pe32Plus->AddressOfEntryPoint;
+ Context->SectionAlignment = Pe32Plus->SectionAlignment;
+
+ RelocDir = Pe32Plus->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
+ SecDir = Pe32Plus->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_SECURITY;
+
+ PeCommon = &Pe32Plus->CommonHeader;
+ NumberOfRvaAndSizes = Pe32Plus->NumberOfRvaAndSizes;
+ HdrSizeWithoutDataDir = sizeof (EFI_IMAGE_NT_HEADERS64) - sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR);
+
+ break;
+
+ default:
+ //
+ // Disallow Images with unknown PE Optional Header signatures.
+ //
+ DEBUG_RAISE ();
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Disallow Images with unknown directories.
+ //
+ if (NumberOfRvaAndSizes > EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the Image alignment is a power of 2.
+ //
+ if (!IS_POW2 (Context->SectionAlignment)) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ STATIC_ASSERT (
+ sizeof (EFI_IMAGE_DATA_DIRECTORY) <= MAX_UINT32 / EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
+ "The following arithmetic may overflow."
+ );
+ //
+ // Calculate the offset of the Image sections.
+ //
+ // Context->ExeHdrOffset + sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) cannot overflow because
+ // * ExeFileSize > sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) and
+ // * Context->ExeHdrOffset + ExeFileSize = FileSize
+ //
+ Overflow = BaseOverflowAddU32 (
+ Context->ExeHdrOffset + sizeof (*PeCommon),
+ PeCommon->FileHeader.SizeOfOptionalHeader,
+ &Context->SectionsOffset
+ );
+ if (Overflow) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the Section Headers offset is sufficiently aligned.
+ //
+ if ( !PcdGetBool (PcdImageLoaderAllowMisalignedOffset)
+ && !IS_ALIGNED (Context->SectionsOffset, ALIGNOF (EFI_IMAGE_SECTION_HEADER)))
+ {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // This arithmetic cannot overflow because all values are sufficiently
+ // bounded.
+ //
+ MinSizeOfOptionalHeader = HdrSizeWithoutDataDir +
+ NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY);
+
+ ASSERT (MinSizeOfOptionalHeader >= HdrSizeWithoutDataDir);
+
+ STATIC_ASSERT (
+ sizeof (EFI_IMAGE_SECTION_HEADER) <= (MAX_UINT32 + 1ULL) / (MAX_UINT16 + 1ULL),
+ "The following arithmetic may overflow."
+ );
+ //
+ // Calculate the minimum size of the Image Headers.
+ //
+ Overflow = BaseOverflowAddU32 (
+ Context->SectionsOffset,
+ (UINT32)PeCommon->FileHeader.NumberOfSections * sizeof (EFI_IMAGE_SECTION_HEADER),
+ &MinSizeOfHeaders
+ );
+ if (Overflow) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the Image Header sizes are sane. SizeOfHeaders contains all header
+ // components (DOS, PE Common and Optional Header).
+ //
+ if (MinSizeOfOptionalHeader > PeCommon->FileHeader.SizeOfOptionalHeader) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ if (MinSizeOfHeaders > Context->SizeOfHeaders) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the Image Headers are in bounds of the file buffer.
+ //
+ if (Context->SizeOfHeaders > FileSize) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Populate the Image context with information from the Common Header.
+ //
+ Context->NumberOfSections = PeCommon->FileHeader.NumberOfSections;
+ Context->Machine = PeCommon->FileHeader.Machine;
+ Context->RelocsStripped =
+ (
+ PeCommon->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED
+ ) != 0;
+
+ if (EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC < NumberOfRvaAndSizes) {
+ Context->RelocDirRva = RelocDir->VirtualAddress;
+ Context->RelocDirSize = RelocDir->Size;
+
+ if (Context->RelocsStripped && (Context->RelocDirSize != 0)) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+ } else {
+ ASSERT (Context->RelocDirRva == 0);
+ ASSERT (Context->RelocDirSize == 0);
+ }
+
+ if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < NumberOfRvaAndSizes) {
+ Context->SecDirOffset = SecDir->VirtualAddress;
+ Context->SecDirSize = SecDir->Size;
+ //
+ // Verify the Security Directory is in bounds of the Image buffer.
+ //
+ Overflow = BaseOverflowAddU32 (
+ Context->SecDirOffset,
+ Context->SecDirSize,
+ &SecDirEnd
+ );
+ if (Overflow || (SecDirEnd > FileSize)) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the Security Directory is sufficiently aligned.
+ //
+ if (!IS_ALIGNED (Context->SecDirOffset, IMAGE_CERTIFICATE_ALIGN)) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the Security Directory size is sufficiently aligned, and that if
+ // it is not empty, it can fit at least one certificate.
+ //
+ if ( (Context->SecDirSize != 0)
+ && ( !IS_ALIGNED (Context->SecDirSize, IMAGE_CERTIFICATE_ALIGN)
+ || (Context->SecDirSize < sizeof (WIN_CERTIFICATE))))
+ {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+ } else {
+ //
+ // The Image context is zero'd on allocation.
+ //
+ ASSERT (Context->SecDirOffset == 0);
+ ASSERT (Context->SecDirSize == 0);
+ }
+
+ //
+ // Verify the Image sections are Well-formed.
+ //
+ Status = InternalVerifySections (
+ Context,
+ FileSize,
+ &StartAddress
+ );
+ if (Status != RETURN_SUCCESS) {
+ DEBUG_RAISE ();
+ return Status;
+ }
+
+ //
+ // Verify the entry point is in bounds of the Image buffer.
+ //
+ if (Context->AddressOfEntryPoint >= Context->SizeOfImage) {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Verify the basic Relocation information is well-formed.
+ //
+ Status = InternalValidateRelocInfo (Context, StartAddress);
+ if (Status != RETURN_SUCCESS) {
+ DEBUG_RAISE ();
+ }
+
+ return Status;
+}
+
+RETURN_STATUS
+InternalPeCoffFixup (
+ OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
+ IN CONST VOID *FileBuffer,
+ IN UINT32 FileSize
+ )
+{
+ RETURN_STATUS Status;
+ CONST EFI_IMAGE_DOS_HEADER *DosHdr;
+
+ //
+ // Failure of these asserts can be fixed if needed by not using the Pcd
+ // values above, we do not do this initially to make it simpler to compare
+ // this file with BasePeCoffLib2/PeCoffInit.c.
+ // STATIC_ASSERT not suitable here: 'not an integral constant expression'.
+ //
+ if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
+ ASSERT (FALSE);
+ }
+
+ if (PcdGetBool (PcdImageLoaderAllowMisalignedOffset)) {
+ ASSERT (FALSE);
+ }
+
+ ASSERT (Context != NULL);
+ ASSERT (FileBuffer != NULL || FileSize == 0);
+ //
+ // Initialise the Image context with 0-values.
+ //
+ ZeroMem (Context, sizeof (*Context));
+
+ Context->FileBuffer = FileBuffer;
+ Context->FileSize = FileSize;
+ //
+ // Check whether the DOS Image Header is present.
+ //
+ if ( (sizeof (*DosHdr) <= FileSize)
+ && (*(CONST UINT16 *)(CONST VOID *)FileBuffer == EFI_IMAGE_DOS_SIGNATURE))
+ {
+ DosHdr = (CONST EFI_IMAGE_DOS_HEADER *)(CONST VOID *)(
+ (CONST CHAR8 *)FileBuffer
+ );
+ //
+ // Verify the DOS Image Header and the Executable Header are in bounds of
+ // the file buffer, and that they are disjoint.
+ //
+ if ( (sizeof (EFI_IMAGE_DOS_HEADER) > DosHdr->e_lfanew)
+ || (DosHdr->e_lfanew > FileSize))
+ {
+ DEBUG_RAISE ();
+ return RETURN_VOLUME_CORRUPTED;
+ }
+
+ Context->ExeHdrOffset = DosHdr->e_lfanew;
+ //
+ // Verify the Execution Header offset is sufficiently aligned.
+ //
+ if ( !PcdGetBool (PcdImageLoaderAllowMisalignedOffset)
+ && !IS_ALIGNED (Context->ExeHdrOffset, ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR)))
+ {
+ return RETURN_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Verify the file buffer can hold a PE Common Header.
+ //
+ if (FileSize - Context->ExeHdrOffset < sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) + sizeof (UINT16)) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ STATIC_ASSERT (
+ ALIGNOF (UINT32) <= ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR),
+ "The following access may be performed unaligned"
+ );
+ //
+ // Verify the Image Executable Header has a PE signature.
+ //
+ if (*(CONST UINT32 *)(CONST VOID *)((CONST CHAR8 *)FileBuffer + Context->ExeHdrOffset) != EFI_IMAGE_NT_SIGNATURE) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Verify the PE Image Header is well-formed.
+ //
+ Status = InternalInitializePe (Context, FileSize);
+ if (Status != RETURN_SUCCESS) {
+ return Status;
+ }
+
+ return RETURN_SUCCESS;
+}
diff --git a/Utilities/AppleEfiSignTool/Makefile b/Utilities/AppleEfiSignTool/Makefile
index 6c8b89d6c190..eb805411fc02 100644
--- a/Utilities/AppleEfiSignTool/Makefile
+++ b/Utilities/AppleEfiSignTool/Makefile
@@ -13,7 +13,8 @@ OBJS = $(PROJECT).o \
PeCoffInit.o \
PeCoffLoad.o \
PeCoffRelocate.o \
- OcPeCoffExtLib.o
+ OcPeCoffExtLib.o \
+ OcPeCoffFixup.o
VPATH = $(UDK_PATH)/MdePkg/Library/BasePeCoffLib2:$\
../../Library/OcPeCoffExtLib:$\