EDK II - Out-of-Bounds Read in GetShortAdFromAds
GetShortAdFromAds loops over a file entry's allocation descriptor sequence, advancing a byte cursor (*Offset) and casting it to a UDF_SHORT_ALLOCATION_DESCRIPTOR pointer.
- Advisory
- BYTERAY-2026-0280
- 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
GetShortAdFromAds loops over a file entry's allocation descriptor sequence, advancing a byte cursor (*Offset) and casting it to a UDF_SHORT_ALLOCATION_DESCRIPTOR pointer. It then reads the ExtentLength field (4 bytes at offset 0) via GET_EXTENT_FLAGS without first verifying that *Offset + sizeof(UDF_SHORT_ALLOCATION_DESCRIPTOR) (8 bytes) <= Length. The only bounds check (line 719: *Offset >= Length) guarantees the cursor merely starts in bounds. The cursor advances in steps of 8 from 0 (lines 744, 1207, 1254, 1378), and nothing requires Length to be a multiple of 8, so with Length % 8 != 0 the last descriptor is partial. For *Offset in [Length-7, Length-1], the ExtentPosition field (offsets 4-7) read by GetShortAdLsn (line 834) goes past the AD region bound, and for *Offset in [Length-3, Length-1] the 4-byte ExtentLength read at line 733 is also OOB. Two buffers are affected: the File Entry copy (allocated with Volume->FileEntrySize, line 512), when the AD region ends at its end, and the Allocation Extent Descriptor buffer, which GetAedAdsData allocates with exactly *Length bytes (line 1002) taken from the on-disk AED LengthOfAllocationDescriptors (line 940). This is the same root cause as GetLongAdFromAds but with an 8-byte record stride.
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:719 - Function:
GetShortAdFromAds - 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. UdfRead/UdfOpen (File.c:317/164) are EFI entry points invoked when firmware reads or opens a file on the mounted UDF volume. GetAdsInformation (FileSystemOperations.c:601–626) sets *Length = FileEntry->LengthOfAllocationDescriptors and *AdsData = FileEntry->Data + LengthOfExtendedAttributes — both derived from attacker-controlled File Entry fields. This function is explicitly annotated as a boundary receiving untrusted filesystem input. GetAdsInformation validates that Length <= FileEntrySize (line 628), which caps but does not prevent the OOB. GetAllocationDescriptor (line 768) forwards Data/Offset/Length directly with no additional check. GetShortAdFromAds checks only *Offset >= Length (line 719), then casts to (UDF_SHORT_ALLOCATION_DESCRIPTOR*)((UINT8*)Data + *Offset) and reads ExtentLength (4 bytes at offset 0) via GET_EXTENT_FLAGS, an OOB read for *Offset in [Length-3, Length-1]. Subsequent reads of ExtentPosition@4-7 by GetShortAdLsn (line 834) are OOB for *Offset in [Length-7, Length-1]. When ReadFile follows an indirect AD, GetAedAdsData (line 1231) replaces Data/Length with a pool buffer of exactly Length bytes (line 1002), where Length is the attacker's AED LengthOfAllocationDescriptors (line 940); a Length of 1-7 gives the same over-read directly.
Affected Callers
GetAllocationDescriptorReadFile
Sanitization / Security Controls
Two bounds checks exist: (1) GetAdsInformation validates Length <= FileEntrySize (line 628) — classified as partial (caps but does not prevent); (2) *Offset >= Length (line 719) — classified as ineffective (cursor-start only, no 8-byte remaining-size guard). 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
- Physical or media access; target firmware includes UdfDxe and mounts/reads UDF volumes; no authentication of disk content before parsing.
- Craft a UDF File Entry with Short AD recording flags (
ICBTagflags indicatingShortAdsSequence) andLengthOfAllocationDescriptorsnot a multiple of 8, with the Short AD region ending at the end of the File Entry buffer (or an indirect AD pointing to an AED whoseLengthOfAllocationDescriptorsis 1-7). - Mark the preceding ADs as not recorded so the
GET_EXTENT_FLAGSskip logic advances*Offsetin steps of 8 into[Length-7, Length-1]. - Attach the medium and trigger a file read/open.
GetShortAdFromAdspasses the cursor-start check, casts the partial descriptor, and readsExtentPosition(andExtentLengthwhen fewer than 4 bytes remain) OOB.
Impact
OOB read of up to 7 bytes past the end of a firmware pool buffer (File Entry copy or AED buffer). The bytes are not returned to the caller; they become the extent length and LSN of the following disk read, so the effect is wrong file data or a failed read, and a page fault only if the buffer ends next to an unmapped page.
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.