← ALL ADVISORIES

MEDIUM BYTERAY-2026-0224Disclosed

EDK II - Buffer Under-read in PeCoffLoaderImageAddress

PeCoffLoaderImageAddress performs only an upper-bound check (Address >= ImageSize + TeStrippedOffset, line 917) before computing the returned pointer as ImageAddress + Address - TeStrippedOffset (line 922).

Advisory
BYTERAY-2026-0224
CWE
CWE-127
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

PeCoffLoaderImageAddress performs only an upper-bound check (Address >= ImageSize + TeStrippedOffset, line 917) before computing the returned pointer as ImageAddress + Address - TeStrippedOffset (line 922). There is no lower-bound check ensuring Address >= TeStrippedOffset. For TE images, TeStrippedOffset is StrippedSize - sizeof (EFI_TE_IMAGE_HEADER), where StrippedSize is an attacker-controlled UINT16 header field (PeImage.h:783) validated only against a lower bound (line 148). It can therefore be up to 0xFFD7. When an address passed in is smaller than TeStrippedOffset, the returned pointer lies up to 0xFFD7 bytes before the loaded image buffer. In the relocation apply loop this pointer is read and written by every fixup type (HIGH at lines 1131-1132, LOW at 1141-1142, HIGHLOW at 1151-1152, DIR64 at 1162-1163), adding the relocation delta to memory before the image. The same helper also places TE sections in PeCoffLoaderLoadImage (lines 1403-1404): a section whose VirtualAddress is below TeStrippedOffset gets a Base before the image buffer, and ImageRead at line 1414 copies the section's raw data, which the attacker controls, to that location.

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:917
  • Function: PeCoffLoaderImageAddress
  • Category: CWE-127 (Buffer Under-read)

Technical Details

Controllability: EXTERNAL_UNTRUSTED — confidence: HIGH

Data Flow

Untrusted TE image bytes (StrippedSize, relocation directory VirtualAddress, relocation entry offsets) from external boot media enter at PeCoffLoaderGetPeHeader, where StrippedSize is validated only against a lower bound (line 148: sizeof(EFI_TE_IMAGE_HEADER) >= StrippedSize rejects; no upper bound). In PeCoffLoaderRelocateImage, TeStrippedOffset = StrippedSize - sizeof(EFI_TE_IMAGE_HEADER) is computed (line 1047). RelocBase is obtained via PeCoffLoaderImageAddress(RelocDir->VirtualAddress, TeStrippedOffset) (line 1064), which the attacker points to a valid in-image location. At line 1120, Fixup = PeCoffLoaderImageAddress(RelocBase->VirtualAddress + (*Reloc & 0xFFF), TeStrippedOffset). The upper-bound-only check at line 917 passes when Address < ImageSize + TeStrippedOffset. Line 922 returns ImageAddress + Address - TeStrippedOffset, which points before the image when Address < TeStrippedOffset. The out-of-image Fixup pointer is then read and written by the fixup handlers (for example lines 1131-1132, *Fixup16 = *Fixup16 + Adjust). In DXE these steps run in CoreLoadPeImage (Dxe/Image/Image.c:751 PeCoffLoaderLoadImage, 774 PeCoffLoaderRelocateImage), which is reached only after the Security2 FileAuthentication call at Image.c:1279.

Affected Callers

  • PeCoffLoaderRelocateImage
  • PeCoffLoaderLoadImage
  • CoreLoadPeImage (DXE)
  • LoadAndRelocatePeCoffImage (PEI)
  • LoadAndRelocatePeCoffImageInPlace
  • ReadyToLockEventNotify

Sanitization / Security Controls

  • StrippedSize lower-bound check at BasePeCoff.c:148 — ineffective (no upper bound).
  • Upper-bound-only address check at BasePeCoff.c:917 — ineffective (no lower bound to prevent underflow).
  • Secure Boot signature verification at Dxe/Image/Image.c:1279 — effective by default. DxeImageVerificationLib rejects any non-PE image, including TE (DxeImageVerificationLib.c:1820), and under the default DENY policy (0x04, SecurityPkg.dec:305/318/378) returns EFI_ACCESS_DENIED so the image is never loaded. Under the DEFER_EXECUTE_ON_SECURITY_VIOLATION policy (0x03) it returns EFI_SECURITY_VIOLATION (DxeImageVerificationLib.c:2070-2071), which CoreLoadImageCommon lets through (Image.c:1316), so the unverified TE image is loaded and relocated. With Secure Boot disabled the image runs anyway. PEI loads TE images only from firmware volumes.
  • CoreIsImageTypeSupported at Dxe/Image/Image.c:608 — ineffective for this vulnerability (checks machine type only, not TE header values).

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: Medium
Realism: Low

Reproduction

  1. Use a target whose image verification policy for the chosen source (removable media, fixed media or option ROM) is DEFER_EXECUTE_ON_SECURITY_VIOLATION (0x03), with Secure Boot enabled.
  2. Craft an unsigned TE image with StrippedSize=0xFFFF (so TeStrippedOffset=0xFFD7), BaseOfCode=0x10000, a relocation directory placed inside the image, and a relocation block with VirtualAddress=0x0 and an entry offset of 0x100.
  3. Deliver it via USB or PXE and boot it. DxeImageVerificationLib rejects the TE image and returns EFI_SECURITY_VIOLATION; CoreLoadImageCommon continues to CoreLoadPeImage.
  4. During relocation, Fixup = ImageAddress + 0x100 - 0xFFD7 = ImageAddress - 0xFED7, and the fixup handler reads and writes memory at that address, before the image buffer.

Impact

Memory corruption at firmware privilege, up to 0xFFD7 bytes before the image buffer: the relocation delta is added to existing memory, and through the section load path the attacker's own section bytes are copied there. The corruption happens while an image that failed signature verification is being loaded, before it is allowed to run. It is reachable only on platforms that use the DEFER_EXECUTE_ON_SECURITY_VIOLATION image verification policy (0x03). Under the default DENY policy the TE image is rejected before it is loaded, and with Secure Boot disabled the attacker's image would run anyway.

Remediation and Mitigation

As of commit 70741a15d9a714323a5598eac47727e60507e22f this issue is unfixed upstream and no CVE has been assigned. Add the missing lower-bound check so the computed offset cannot fall before the start of the buffer. 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