← ALL ADVISORIES

MEDIUM BYTERAY-2026-0272Disclosed

EDK II - Out-of-bounds Write in PeCoffLoaderLoadImage

In the PE/COFF section loading loop at line 1404, the End bounds check computes Section->VirtualAddress + Section->Misc.VirtualSize - 1 where both operands are UINT32.

Advisory
BYTERAY-2026-0272
CWE
CWE-787
Vendor
TianoCore
Product
EDK II
Reported
2026-06-25
Disclosure
2026-10-29
Affected
EDK II at commit 70741a15d9a714323a5598eac47727e60507e22f (master, 2026-06-21); affected code in MdePkg/Library/BasePeCoffLib/BasePeCoff.c.
Credit
Argus-Systems

Executive Summary

In the PE/COFF section loading loop at line 1404, the End bounds check computes Section->VirtualAddress + Section->Misc.VirtualSize - 1 where both operands are UINT32. This addition is performed in 32-bit arithmetic and wraps modulo 2^32 before being widened to UINTN for the PeCoffLoaderImageAddress parameter. An attacker crafts a PE32 image with a section that has a small VirtualAddress (passes the Base bounds check) but a huge VirtualSize such that VirtualAddress + VirtualSize overflows 2^32. The wrapped End value is then small enough to pass the Address >= ImageSize check in PeCoffLoaderImageAddress (line 917), defeating the only validation guarding the section's memory range. Since PeCoffLoaderGetPeHeader validates file-level bounds but never validates VirtualAddress + VirtualSize <= SizeOfImage, the subsequent ZeroMem at line 1432 writes VirtualSize - Size bytes (up to ~4 GB) of zeros starting past the ImageSize-sized buffer.

This advisory is one of a set reported to VulnCheck on 2026-06-25 for coordinated disclosure to the EDK II maintainers. After several follow-ups over the following months no response was received. 126 days after the initial report, ByteRay is publishing the findings in good faith so that affected integrators can assess and remediate them. All findings were identified against EDK II commit 70741a15d9a714323a5598eac47727e60507e22f (master, 2026-06-21).

Affected Products and Versions

  • Vendor: TianoCore
  • Product: EDK II (MdePkg)
  • Affected commit: 70741a15d9a714323a5598eac47727e60507e22f (master, 2026-06-21). The code is present on that commit and later revisions that have not changed it.
  • Location: MdePkg/Library/BasePeCoffLib/BasePeCoff.c:1404
  • Function: PeCoffLoaderLoadImage
  • Category: Out-of-bounds Write (CWE-787)

Technical Details

Controllability: EXTERNAL_UNTRUSTED — Confidence: high

Data Flow

The PE/COFF image originates from external untrusted boot media reachable through UEFI boot protocols. CoreLocateDevicePath resolves the boot source — PXE/HTTP network boot (gEfiLoadFileProtocolGuid), removable media (gEfiSimpleFileSystemProtocolGuid), gEfiLoadFile2ProtocolGuid, or a firmware volume (gEfiFirmwareVolume2ProtocolGuid) — at Image.c:1220–1238; PCI option ROM images are passed in as a buffer by PciBusDxe (PciOptionRomSupport.c:739). CoreLoadImage (Image.c:1544) reads the raw PE/COFF bytes, which CoreLoadImageCommon receives as SourceBuffer (Image.c:1138–1200). Before loading, CoreLoadImageCommon runs gSecurity2->FileAuthentication (Image.c:1279) and stops on any error other than EFI_SECURITY_VIOLATION (Image.c:1316-1328). PeCoffLoaderGetPeHeader sets ImageSize = SizeOfImage from the attacker-controlled optional header (BasePeCoff.c:313). The header validator checks only file-level bounds (PointerToRawData + SizeOfRawData, lines 497–536) and omits any memory-level check. CoreLoadPeImage then allocates an ImageSize-byte buffer (Image.c:653–655). In the section loop, Base = PeCoffLoaderImageAddress(VA) passes the bounds check at line 917, and End = PeCoffLoaderImageAddress(VA + VirtualSize - 1) passes due to the 32-bit overflow at line 1404. The ZeroMem at line 1432 then writes up to ~4 GB past the buffer. The ImageRead at line 1415 is a secondary write sink.

Affected Callers

  • CoreLoadPeImage (Image.c:751)
  • LoadAndRelocatePeCoffImage (Pei/Image.c:440)
  • LoadAndRelocatePeCoffImageInPlace (Pei/Image.c:505)
  • ReadyToLockEventNotify (ScriptExecute.c:353)

Sanitization / Security Controls

  • File-level bounds validation (BasePeCoff.c:497–536): Checks PointerToRawData + SizeOfRawData does not overflow UINT32 and last byte is readable from file. Insufficient — validates file-level data only; does not validate VirtualAddress + VirtualSize <= SizeOfImage.
  • PeCoffLoaderImageAddress bounds check (BasePeCoff.c:917): if (Address >= ImageSize + TeStrippedOffset) return NULL. Bypassed — defeated by the 32-bit integer overflow at the call site.
  • Secure Boot signature verification (gSecurity2->FileAuthentication, Image.c:1279): runs before CoreLoadPeImage. With Secure Boot enabled and the default policy (PcdOptionRomImageVerificationPolicy, PcdRemovableMediaImageVerificationPolicy, PcdFixedMediaImageVerificationPolicy all 0x04, deny execute, SecurityPkg.dec:305/318/378), an unsigned or untrusted image gets EFI_ACCESS_DENIED (DxeImageVerificationLib.c:2070-2074) and is rejected at Image.c:1316-1328 before PeCoffLoaderLoadImage runs. Only the non-default defer policy (DEFER_EXECUTE_ON_SECURITY_VIOLATION, 0x03) returns EFI_SECURITY_VIOLATION, which lets the load continue. A validly signed image cannot carry crafted section headers, because the headers are covered by the Authenticode hash. With Secure Boot disabled the image is allowed to run anyway.
  • PEI (LoadAndRelocatePeCoffImage, LoadAndRelocatePeCoffImageInPlace) and S3 boot script (ReadyToLockEventNotify) callers load images from firmware volumes, which are already trusted.

Reachability and Preconditions

Attacker position and trust level for this issue are stated in the Controllability line and Data Flow above, and the concrete trigger is in Reproduction below.

Exploitability: Low
Realism: Low

Reproduction

  1. Craft a PE32 image with SizeOfImage=0x10000, a section with VirtualAddress=0x1000, VirtualSize=0xFFFFF100, SizeOfRawData=0x100.
  2. Use a target with Secure Boot disabled, or with the image verification policy for the chosen source set to defer execute (0x03).
  3. Place the image on a bootable USB drive, PXE server, or malicious PCI option ROM.
  4. Boot the target from the malicious source; DXE core loads the image via CoreLoadImage → CoreLoadPeImage → PeCoffLoaderLoadImage.
  5. The 32-bit overflow defeats the bounds check; ZeroMem at line 1432 writes ~4 GB of zeros past the 64 KB buffer, corrupting memory and crashing the firmware.

Impact

Out-of-bounds zero write (up to about 4 GB) past the image buffer during PE/COFF section loading, which corrupts memory and crashes the firmware. Under the default Secure Boot policy an unsigned crafted image is rejected before the loader runs, and with Secure Boot disabled the attacker's image would be executed anyway, so in default configurations the bug does not cross a privilege boundary and does not bypass Secure Boot. It is reachable as a boundary crossing only on platforms that set the defer-execute image verification policy.

Remediation and Mitigation

As of commit 70741a15d9a714323a5598eac47727e60507e22f this issue is unfixed upstream and no CVE has been assigned. Validate the computed destination offset and length against the real buffer size before writing, using width-safe arithmetic so the check cannot be bypassed by overflow. The specific control that is absent or ineffective is identified in the Sanitization / Security Controls list under Technical Details.

Timeline

  • 2026-06-25 - Reported to VulnCheck for coordinated disclosure to the TianoCore / EDK II security team.
  • 2026-07 to 2026-10 - Several follow-ups sent; no response received.
  • 2026-10-29 - Public disclosure in good faith, 126 days after the initial report.

Credits

Discovered and reported by Argus-Systems.

References