← ALL ADVISORIES

LOW BYTERAY-2026-0228Disclosed

EDK II - Out-of-Bounds Read in Dhcp6SeekIaOption

Both Dhcp6SeekOption and Dhcp6SeekIaOption iterate over DHCP6 options using a loop guarded only by Cursor < Buf + SeekLen.

Advisory
BYTERAY-2026-0228
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

Both Dhcp6SeekOption and Dhcp6SeekIaOption iterate over DHCP6 options using a loop guarded only by Cursor < Buf + SeekLen. The loop bodies read fixed-offset fields without verifying enough bytes remain. Dhcp6SeekOption reads Cursor+0..1 (OpCode) and Cursor+2..3 (DataLen); Dhcp6SeekIaOption additionally reads Cursor+4..7 (IaId). Loop advancement uses Cursor += (DataLen + 4). A trailing option whose header starts within SeekLen but whose fixed-offset reads extend past SeekLen reads beyond the received data. The receive buffer is AllocateZeroPool(sizeof (EFI_DHCP6_PACKET) + TotalSize) (Dhcp6Io.c:3060-3061); EFI_DHCP6_PACKET is 13 bytes under #pragma pack(1) while the packet data starts at offset 8, so 5 zeroed bytes follow the received data. Dhcp6SeekOption therefore stays inside the allocation, and Dhcp6SeekIaOption reads at most 2 bytes past it on callers that pass the option length. Dhcp6HandleReplyMsg passes Packet->Length (which includes the 4-byte header) as SeekLen instead of the option length (Dhcp6Io.c:2347-2351), so the walk can start an option up to 3 bytes past the end of the received data and Dhcp6SeekIaOption then reads up to 6 bytes past the allocation. These functions are the first parsers called on every received DHCP6 packet.

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:1179 (read at line 1181); worst caller NetworkPkg/Dhcp6Dxe/Dhcp6Io.c:2347-2351
  • Function: Dhcp6SeekIaOption (and Dhcp6SeekOption at line 1135)
  • Category: CWE-130 — Out-of-bounds read (insufficient bounds check before fixed-offset read)

Technical Details

Controllability: EXTERNAL_UNTRUSTED — high confidence. First parsers on every received DHCP6 packet. No authentication in DHCP6. Pattern and LLM agreement.

Data Flow

A remote UDP DHCP6 packet is received (Dhcp6Io.c:3060-3069), allocated with AllocateZeroPool and filled with exactly TotalSize bytes, leaving 5 zeroed bytes after the data. Dispatched to Dhcp6HandleStateless or Dhcp6HandleStateful (Dhcp6Io.c:3113-3116). Dhcp6SeekStsOption computes OptionLen = Packet->Length - sizeof(Packet->Dhcp6.Header) (line 824) and calls Dhcp6SeekOption(Packet->Dhcp6.Option, OptionLen, ...) at line 830 and Dhcp6SeekIaOption(...) at line 846 — both as first parsers. Dhcp6SeekOption (line 1135) reads Cursor and Cursor+2 without verifying Cursor+4 <= SeekLen (up to 3 bytes past SeekLen, which land in the 5 zeroed slack bytes of the allocation). Dhcp6SeekIaOption (line 1179) reads Cursor+4 via ReadUnaligned32 at line 1181 without verifying Cursor+8 <= SeekLen (up to 7 bytes past SeekLen, at most 2 bytes past the allocation). Dhcp6HandleReplyMsg calls Dhcp6SeekIaOption(Packet->Dhcp6.Option, Packet->Length, ...) at Dhcp6Io.c:2347-2351, overstating SeekLen by 4, which raises this to up to 6 bytes past the allocation. Loop advancement in both uses Cursor += (DataLen + 4) with attacker-controlled DataLen.

Affected Callers

Dhcp6SeekStsOption, Dhcp6UpdateIaInfo, Dhcp6SelectAdvertiseMsg, Dhcp6HandleReplyMsg, Dhcp6HandleStateful, Dhcp6HandleStateless, Dhcp6ReceivePacket

Sanitization / Security Controls

  • No sanitization points on these functions — they are the first parsers called.
  • Transaction ID matching (Dhcp6Io.c:3084) — trivially satisfied.
  • Minimum header size check (Dhcp6Io.c:3053) — header only.

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. Attacker controls/MITMs a DHCP6 server; target firmware processes DHCP6 packets; attacker can observe/guess the 24-bit transaction ID.
  2. Wait for DHCP6 exchange.
  3. Craft a packet with a trailing option header starting within SeekLen but truncated (1–3 bytes for SeekOption, 1–7 for SeekIaOption). For the largest over-read, send a Reply while the client is Requesting, Renewing or Rebinding so Dhcp6HandleReplyMsg walks it with SeekLen = Packet->Length.
  4. Send with matching XID.

Impact

OOB heap read of up to 2 bytes past the packet allocation (up to 6 bytes through Dhcp6HandleReplyMsg), triggered by an unauthenticated on-link DHCPv6 server or spoofer. The bytes fall in pool padding or the pool tail, are only compared against the IA type and IAID, and are never returned or sent, so nothing is disclosed. A fault is possible only if the allocation ends at a guard page (heap guard enabled).

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