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
PeCoffLoaderRelocateImagePeCoffLoaderLoadImageCoreLoadPeImage(DXE)LoadAndRelocatePeCoffImage(PEI)LoadAndRelocatePeCoffImageInPlaceReadyToLockEventNotify
Sanitization / Security Controls
StrippedSizelower-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.
DxeImageVerificationLibrejects any non-PE image, including TE (DxeImageVerificationLib.c:1820), and under the default DENY policy (0x04, SecurityPkg.dec:305/318/378) returnsEFI_ACCESS_DENIEDso the image is never loaded. Under the DEFER_EXECUTE_ON_SECURITY_VIOLATION policy (0x03) it returnsEFI_SECURITY_VIOLATION(DxeImageVerificationLib.c:2070-2071), whichCoreLoadImageCommonlets 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. CoreIsImageTypeSupportedat 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
- 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.
- Craft an unsigned TE image with
StrippedSize=0xFFFF(soTeStrippedOffset=0xFFD7),BaseOfCode=0x10000, a relocation directory placed inside the image, and a relocation block withVirtualAddress=0x0and an entry offset of0x100. - Deliver it via USB or PXE and boot it.
DxeImageVerificationLibrejects the TE image and returnsEFI_SECURITY_VIOLATION;CoreLoadImageCommoncontinues toCoreLoadPeImage. - 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.