EDK II - Integer Underflow in PxeBcDhcp4CallBack
The GET_OPTION_BUFFER_LEN macro is defined as (Pkt)->Length - sizeof(EFI_DHCP4_HEADER) - 4, where sizeof(EFI_DHCP4_HEADER) is 236 bytes and the additional 4 bytes account for the DHCP magic cookie (total 240).
- Advisory
- BYTERAY-2026-0236
- CWE
- CWE-191
- 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/UefiPxeBcDxe/PxeBcDhcp4.h.
- Credit
- Argus-Systems
Executive Summary
The GET_OPTION_BUFFER_LEN macro is defined as (Pkt)->Length - sizeof(EFI_DHCP4_HEADER) - 4, where sizeof(EFI_DHCP4_HEADER) is 236 bytes and the additional 4 bytes account for the DHCP magic cookie (total 240). The DHCP4 receive path at Dhcp4Io.c:963 only guards UdpPacket->TotalSize >= sizeof(EFI_DHCP4_HEADER) (236), not the full 240 bytes the macro requires. A crafted DHCP4 OFFER packet with TotalSize in [236, 239] passes the receive guard but causes the macro's unsigned subtraction to wrap to approximately 0xFFFFFFFC. This wrapped value is passed as the Length argument to PxeBcParseDhcp4Options, whose while (Offset < Length) loop iterates far past the allocated packet buffer, reading Option->OpCode and Option->Length out of bounds from heap memory. If the OOB heap scan encounters a byte matching DHCP4_TAG_MAXMSG (0x39), PxeBcParseDhcp4Options returns a pointer to that OOB location and CopyMem(MaxMsgSize->Data, &Value, 2) at line 1215 writes 2 bytes to an OOB heap address, escalating from OOB read to heap corruption. The written value is the constant HTONS(PXEBC_DHCP4_PACKET_MAX_SIZE) (line 1214), not attacker data, and the write location depends on existing heap contents.
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/UefiPxeBcDxe/PxeBcDhcp4.h:136 - Function:
PxeBcDhcp4CallBack (via GET_OPTION_BUFFER_LEN macro) - Category:
Integer Underflow / Out-of-Bounds Read & Write
Technical Details
Controllability: EXTERNAL_UNTRUSTED — confidence: high
Data Flow
A remote DHCP4 OFFER packet with attacker-controlled TotalSize in [236, 239] arrives at DhcpInput (Dhcp4Io.c:963). The receive guard checks only TotalSize >= sizeof(EFI_DHCP4_HEADER) (236), so the crafted packet passes. Packet->Length is set to the attacker-controlled size (236–239) at Dhcp4Io.c:979. Because Packet->Length <= 240, DhcpValidateOptions is skipped (Dhcp4Io.c:999), leaving Para = NULL. DHCP_IS_BOOTP(NULL) returns TRUE due to the NULL short-circuit (Dhcp4Io.h:50), so the guard !DHCP_IS_BOOTP(Para) evaluates to FALSE and is bypassed (Dhcp4Io.c:611). DhcpCallUser dispatches the undersized packet to PxeBcDhcp4CallBack (Dhcp4Io.c:624). The callback evaluates GET_OPTION_BUFFER_LEN(Packet) at PxeBcDhcp4.h:136, computing 236 - 236 - 4 = 0xFFFFFFFC (UINT32 underflow). This wrapped value is passed to PxeBcParseDhcp4Options at PxeBcDhcp4.c:1208, whose while(Offset < 0xFFFFFFFC) loop reads Option->OpCode and Option->Length out of bounds from heap memory (sinks at lines 54 and 68). If the OOB scan encounters a byte equal to 57 (DHCP4_TAG_MAXMSG), CopyMem(MaxMsgSize->Data, &Value, 2) at line 1215 writes 2 bytes to an OOB heap address, escalating the read to heap corruption.
Affected Callers
DhcpHandleSelectDhcpCallUserPxeBcCacheDhcp4OfferPxeBcParseDhcp4Packet
Sanitization / Security Controls
- Receive guard (
Dhcp4Io.c:963,TotalSize >= 236): Ineffective — threshold is lower than the macro's 240-byte requirement, leaving a [236, 239] gap. DhcpValidateOptions(Dhcp4Io.c:999): Bypassed — gated onLength > 240; forLengthin [236, 239] the condition isFALSE, so validation never runs andParastaysNULL.DhcpHandleSelectOFFER validation (Dhcp4Io.c:611): Bypassed —DHCP_IS_BOOTP(NULL)returnsTRUE, so the!DHCP_IS_BOOTP(Para)guard evaluates toFALSEand execution falls through toDhcpCallUser.
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: High
Reproduction
- Attacker monitors for the victim's DHCP4 DISCOVER broadcast (UDP 67/68).
- Attacker crafts a DHCP4 OFFER with
TotalSize= 236–239 bytes (fullEFI_DHCP4_HEADER, no options/magic cookie). - OFFER passes basic checks (
Dhcp4Io.c:988–993:OpCode = BOOTP_REPLY, matching Xid/ClientHwAddr — all spoofable from the sniffed DISCOVER). - Attacker sends the crafted OFFER to the victim.
- Receive guard passes (236 >= 236),
DhcpValidateOptionsskipped,Para = NULL,DHCP_IS_BOOTP(NULL) = TRUE,DhcpCallUserinvokesPxeBcDhcp4CallBack. GET_OPTION_BUFFER_LENunderflows to 0xFFFFFFFC;PxeBcParseDhcp4Optionsscans past the end of the packet allocation (Dhcp4Io.c:970) through OOB heap until it reaches a 0xFF end tag, a byte of 57, or unmapped memory.- If the OOB scan hits a heap byte == 57 at an option-header position,
CopyMemwrites the constant 2-byte valueHTONS(PXEBC_DHCP4_PACKET_MAX_SIZE)to an OOB heap address, corrupting adjacent heap objects; if the scan runs off mapped memory first, the firmware faults.
Impact
Pre-auth adjacent-network OOB heap read that can run off mapped memory and crash the firmware during PXE boot, plus a 2-byte OOB heap write of a fixed value at a location determined by heap contents, corrupting whatever heap object is there. Nothing read is sent back to the attacker, so there is no information disclosure, and the attacker controls neither the written value nor its exact location.
Remediation and Mitigation
As of commit 70741a15d9a714323a5598eac47727e60507e22f this issue is unfixed upstream and no CVE has been assigned. Validate the length against its minimum before the subtraction so it cannot underflow. 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.