← ALL ADVISORIES

MEDIUM BYTERAY-2026-0278Disclosed

EDK II - Out-of-Bounds Read in ReadDirectoryEntry

ReadDirectoryEntry loops over a directory's recorded data, advancing a byte cursor (FidOffset) and casting it to a UDF_FILE_IDENTIFIER_DESCRIPTOR pointer via GET_FID_FROM_ADS (a raw (UINT8*)Data + offset cast).

Advisory
BYTERAY-2026-0278
CWE
CWE-125
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 MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c.
Credit
Argus-Systems

Executive Summary

ReadDirectoryEntry loops over a directory's recorded data, advancing a byte cursor (FidOffset) and casting it to a UDF_FILE_IDENTIFIER_DESCRIPTOR pointer via GET_FID_FROM_ADS (a raw (UINT8*)Data + offset cast). It then reads fixed-width metadata fields — FileCharacteristics (offset 18), LengthOfFileIdentifier (offset 19), and LengthOfImplementationUse (offsets 36–37) — without first verifying that FidOffset + 38 <= DirectoryLength. The only bounds check (line 2013: FidOffset >= DirectoryLength) guarantees the cursor merely starts in bounds, not that the full 38-byte fixed header is present. DuplicateFid subsequently calls AllocateCopyPool(GetFidDescriptorLength(...), FileIdentifierDesc), copying an attacker-controlled number of bytes (up to about 64 KB, driven by the 16-bit LengthOfImplementationUse) from the cursor position without checking that the full descriptor length fits in the buffer, amplifying the OOB read. A crafted UDF image can position a FID so FidOffset falls in [DirectoryLength-37, DirectoryLength-1], causing field reads — and potentially the DuplicateFid copy — to read out of bounds of the exact-sized DirectoryData heap allocation.

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 (MdeModulePkg)
  • Affected commit: 70741a15d9a714323a5598eac47727e60507e22f (master, 2026-06-21). The code is present on that commit and later revisions that have not changed it.
  • Location: MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c:2013
  • Function: ReadDirectoryEntry
  • Category: Out-of-bounds read (CWE-125/126)

Technical Details

Controllability: EXTERNAL_UNTRUSTED — Confidence: High

Data Flow

The vulnerability originates from an external UDF disk image on attached storage. When firmware invokes EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume (File.c:92, entry point UdfOpenVolume), FindRootDirectory triggers volume parsing. ReadFile allocates DirectoryData exactly to the read length (AllocatePool at FileSystemOperations.c:1166, or AllocatePool/ReallocatePool growing by each ExtentLength at lines 1042/1047), which equals the sum of attacker-controlled ExtentLength values from the UDF disk image allocation descriptors; ReadDirectoryEntry stores it as DirectoryData/DirectoryLength at lines 2008–2009. The cursor FidOffset is checked only with FidOffset >= DirectoryLength (line 2013), which verifies the cursor start is in bounds but does not verify the full 38-byte FID fixed header fits. The cursor is then cast via GET_FID_FROM_ADS (Udf.h:116 = (UDF_FILE_IDENTIFIER_DESCRIPTOR*)((UINT8*)Data + Offs)) with no size validation. GetFidDescriptorLength (line 2032, definition at 463–472) reads LengthOfFileIdentifier@19 and LengthOfImplementationUse@36–37 — an OOB read when FidOffset is within [DirectoryLength-37, DirectoryLength-1]. DuplicateFid (line 2035, definition at 488–492) then calls AllocateCopyPool(GetFidDescriptorLength(...), FileIdentifierDesc), amplifying the read by copying an attacker-influenced byte count from the OOB cursor position.

Affected Callers

  • UdfRead
  • InternalFindFile

Sanitization / Security Controls

One bounds check exists at FileSystemOperations.c:2013 (FidOffset >= DirectoryLength), classified as ineffective — it only verifies the cursor start is in bounds and does not verify the full 38-byte FID header fits within DirectoryLength. No other security controls are present.

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

Reproduction

  1. Physical or media access (attacker attaches a USB, CD/DVD, or HDD image containing a crafted UDF filesystem); target firmware includes UdfDxe and auto-mounts UDF volumes during boot or via EFI shell/DiskIo; no authentication of disk content is performed before UDF parsing.
  2. Craft a UDF image where a FID is positioned at FidOffset within [DirectoryLength-37, DirectoryLength-1].
  3. Set the directory's extent lengths so DirectoryLength ends just past the partial FID with DirectoryData allocated to match exactly.
  4. Attach the medium and trigger parsing via boot auto-mount, EFI shell DIR, or any OpenVolume/Read call.
  5. ReadDirectoryEntry passes the cursor-start check, casts the partial FID, and reads fields OOB.
  6. DuplicateFid amplifies the read with an attacker-influenced copy length.

Impact

OOB heap read of firmware memory. The AllocateCopyPool copy of up to about 64 KB can fault on unmapped memory and crash the firmware, or copy adjacent heap contents into the duplicated FID, which is later parsed as a filename. Read only, no write; requires the victim to mount crafted UDF media.

Remediation and Mitigation

As of commit 70741a15d9a714323a5598eac47727e60507e22f this issue is unfixed upstream and no CVE has been assigned. Before reading each field, validate that its full width fits within the remaining bytes derived from the packet or record size, and stop parsing or reject the input when it does not. 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