← ALL ADVISORIES

MEDIUM BYTERAY-2026-0227Disclosed

EDK II - Out-of-Bounds Read in Dhcp6ParseAddrOption

Dhcp6ParseAddrOption iterates over IA_ADDR sub-options within an IA option's inner data using a loop guarded only by Cursor < IaInnerOpt + IaInnerLen (line 1283).

Advisory
BYTERAY-2026-0227
CWE
CWE-130
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 NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c.
Credit
Argus-Systems

Executive Summary

Dhcp6ParseAddrOption iterates over IA_ADDR sub-options within an IA option's inner data using a loop guarded only by Cursor < IaInnerOpt + IaInnerLen (line 1283). The loop body reads fixed-offset fields from Cursor without verifying that Cursor + 28 fits within IaInnerLen. Reads at Cursor+20 (PreferredLifetime, line 1289), Cursor+24 (ValidLifetime, line 1290), and a 24+ byte CopyMem from Cursor+4 (line 1296) can extend up to 27 bytes past the inner-data boundary. When the IA option ends the packet, this runs past the packet buffer: the buffer is sizeof(EFI_DHCP6_PACKET) + TotalSize bytes (13 + TotalSize with #pragma pack(1)) and the packet data starts at offset 8, so only 5 zeroed slack bytes follow the data and the read reaches up to 22 bytes past the allocation into the pool tail and the next pool header. The upstream Dhcp6SeekInnerOptionSafe validation only checks the outer IA option envelope, not individual sub-option sizes.

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 (NetworkPkg)
  • Affected commit: 70741a15d9a714323a5598eac47727e60507e22f (master, 2026-06-21). The code is present on that commit and later revisions that have not changed it.
  • Location: NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c:1283
  • Function: Dhcp6ParseAddrOption
  • Category: CWE-130 — Out-of-bounds read (insufficient buffer validation)

Technical Details

Controllability: EXTERNAL_UNTRUSTED — high confidence. The packet buffer is filled directly from a remote UDP DHCP6 server response with no authentication. Pattern and LLM agreement.

Data Flow

A remote UDP DHCP6 packet is received (Dhcp6Io.c:3019). The buffer is allocated as AllocateZeroPool(sizeof(EFI_DHCP6_PACKET) + Udp6Wrap->TotalSize) with NetbufCopy filling exactly TotalSize bytes starting at Packet->Dhcp6.Header (offset 8), leaving 5 zeroed bytes after the data (Dhcp6Io.c:3060-3069). The packet is dispatched to Dhcp6HandleStateful (Dhcp6Io.c:3116) on matching transaction ID. Dhcp6HandleReplyMsg calls Dhcp6SeekStsOption (Dhcp6Io.c:2408), which calls Dhcp6SeekIaOption at line 846 to locate the IA option (first parser, no prior sub-option validation). On status success, Dhcp6UpdateIaInfo (Dhcp6Io.c:2418; also reached from Dhcp6SelectAdvertiseMsg at Dhcp6Io.c:2626) is called, which bounds the IA option to the packet via Dhcp6SeekInnerOptionSafe and invokes Dhcp6GenerateIaCb (Dhcp6Io.c:680), which calls Dhcp6ParseAddrOption(IaInnerOpt, IaInnerLen) twice, once to count addresses (Dhcp6Utility.c:1346) and once to fill them (Dhcp6Utility.c:1368). The vulnerable loop at Dhcp6Utility.c:1283 reads Cursor+20, Cursor+24, and CopyMem(Cursor+4, 24+ bytes) without verifying Cursor+28 <= IaInnerLen, with attacker-controlled DataLen driving loop advancement — OOB heap read up to 27 bytes past the inner-data boundary, up to 22 bytes past the packet allocation.

Affected Callers

Dhcp6GenerateIaCb, Dhcp6UpdateIaInfo, Dhcp6HandleReplyMsg, Dhcp6SelectAdvertiseMsg, Dhcp6HandleStateful, Dhcp6ReceivePacket

Sanitization / Security Controls

  • Dhcp6SeekInnerOptionSafe (Dhcp6Io.c:705) — ineffective: only validates the outer IA option envelope length; does not validate individual sub-option sizes within the inner data.
  • Minimum header size check (Dhcp6Io.c:3053) — effective for header only.
  • Transaction ID matching (Dhcp6Io.c:3084) — trivially satisfied by attacker server; DHCP6 transaction IDs are 24-bit and observable on the network.

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. Attacker controls or MITMs a DHCP6 server on the client's network segment; target firmware performs stateful DHCPv6; attacker can observe the client's Solicit/Request to obtain the transaction ID.
  2. Wait for a DHCP6 Solicit/Request.
  3. Craft a Reply/Advertise with a valid outer IA_NA envelope placed last in the packet, ending in a truncated IA_ADDR sub-option of a few bytes.
  4. Send with matching XID.
  5. Dhcp6ParseAddrOption reads up to 27 bytes past the inner-data boundary, up to 22 bytes past the packet allocation.

Impact

Out-of-bounds heap read of up to 22 bytes past the packet allocation, which is mostly pool tail and pool header metadata. If the out-of-bounds bytes pass the lifetime checks at line 1292, they are copied into the IA address list as an address entry; PXE and HTTP boot adopt IaAddress[0] as the station IPv6 address (PxeBcDhcp6.c:2481, HttpBootDhcp6.c:1113), so some of those bytes can show up on the wire. The disclosure is small and conditional.

Remediation and Mitigation

As of commit 70741a15d9a714323a5598eac47727e60507e22f this issue is unfixed upstream and no CVE has been assigned. Before reading each option header or field, verify that the full field fits within the remaining buffer length, not just that the cursor currently sits in bounds. 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