EDK II - Numeric Range Comparison Without Minimum Check in Ip6TrimPacket
Identical bug to Ip4TrimPacket.
- Advisory
- BYTERAY-2026-0277
- CWE
- CWE-839
- 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/Ip6Dxe/Ip6Input.c.
- Credit
- Argus-Systems
Executive Summary
Identical bug to Ip4TrimPacket. The TAIL branch at lines 133–139 computes Len = End - Info->End (INTN) at line 134, which is always negative when the branch guard if (End < Info->End) is true. The correct computation should be Len = Info->End - End. The negative INTN value is cast to (UINT32) at line 136 for NetbufTrim (wrapping to a huge value, clamped to TotalSize), so the whole NET_BUF is emptied. Info->Length is INT32, so Info->Length -= (UINT32)Len at line 138 increases it by the overlap size instead of decreasing it, inflating the reassembly accounting. Unlike IPv4, queued IPv6 fragments still hold the IPv6 header, unfragmentable extension headers and fragment header at offset 0 (they are only stripped after reassembly, lines 401-409), so the emptied fragment loses its headers too. If that fragment is the first one (offset 0), this leads to NULL pointer use: when it is emptied at line 299, NetbufGetByte on its empty duplicate returns NULL (NetBuffer.c:371) and Ip6NtohHead(NULL) at line 335 writes near address 0 (Ip6Common.c:663-664; the ASSERT at 334 is compiled out in RELEASE); when it is emptied at line 254, on completion NetbufGetFragment(Fragment, 0, This->HeadLen, 0) returns NULL (NetBuffer.c:533) and InsertHeadList(ListHead, &TmpPacket->List) at line 412 links a near-NULL address that NetbufFromBufList then walks. Two distinct call sites trigger the bug: line 254 (Ip6TrimPacket(Fragment, Node->Start, This->Start) — trims the previous fragment's tail when This->Start < Node->End at line 246) and line 299 (Ip6TrimPacket(Packet, This->Start, Node->Start) — trims the incoming fragment's tail when Node->Start < This->End at line 293). The ASSERT precondition at line 123 is satisfied for both triggering paths. This is reachable from a pre-auth remote network attacker sending overlapping IPv6 fragments during IPv6 PXE/HTTP boot.
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/Ip6Dxe/Ip6Input.c:134; consequences atIp6Input.c:335andIp6Input.c:401-412 - Function:
Ip6TrimPacket - Category: Numeric Range Comparison Without Minimum Check (CWE-839)
Technical Details
Controllability: EXTERNAL_UNTRUSTED — Confidence: High
Data Flow
The vulnerability is reachable from unauthenticated remote network input via IPv6. A raw IPv6 packet arrives from the network wire and enters Ip6AcceptFrame() (line 976), the registered IPv6 receive callback during IPv6 PXE/HTTP boot with no authentication. The packet is forwarded to Ip6PreProcessPacket() (line 1009), where the attacker-controlled IPv6 Fragment Header offset field is extracted into IP6_CLIP_INFO. When a fragment extension header is present, the packet enters Ip6Reassemble() (line 914). Two distinct overlap detection paths can trigger the bug. Path 1 (line 246): when This->Start < Node->End, the call Ip6TrimPacket(Fragment, Node->Start, This->Start) at line 254 trims the previous fragment's tail — the TAIL branch is taken because This->Start < Node->End, producing negative Len = This->Start - Node->End. Path 2 (line 293): when Node->Start < This->End, the call Ip6TrimPacket(Packet, This->Start, Node->Start) at line 299 trims the incoming fragment's tail — the TAIL branch is taken because Node->Start < This->End, producing negative Len = Node->Start - This->End. In both cases, (UINT32)Len at line 136 wraps to approximately 4.29 billion, NetbufTrim clamps to TotalSize and empties the fragment including its headers, and Info->Length -= (UINT32)Len at line 138 inflates the INT32 length by the overlap. The inflated This->Length propagates to Assemble->CurLen at line 310, and premature reassembly can be triggered at line 379. If the emptied fragment is the first one, Ip6NtohHead is called on a NULL header at line 335 (Path 2), or NetbufGetFragment returns NULL at line 401 and the NULL-based TmpPacket->List is inserted into the fragment list at line 412 (Path 1).
Affected Callers
Ip6Reassemble
Sanitization / Security Controls
- ASSERT guard at
Ip6Input.c:122-123:ASSERT ((Info->Start + Info->Length == Info->End) && (Info->Start < End) && (Start < Info->End)). This is ineffective — the precondition is satisfied by fragment list ordering invariants for both triggering call sites (line 254 and line 299). For line 254:(Node->Start < This->Start) && (Node->Start < Node->End)holds when offsets differ. For line 299: same as the IPv4 line-340 case. ASSERT is a no-op in release firmware builds.
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: High
Realism: Medium
Reproduction
- Send IPv6 fragments of one datagram, one of them with offset=0 and More flag set, to establish an assemble entry.
- Send an overlapping fragment with a different offset that triggers either overlap condition (line 246 or line 293).
- The TAIL branch in
Ip6TrimPacketcomputes a negativeLen; the fragment (headers included) is over-trimmed to 0 bytes whileInfo->Lengthgrows by the overlap via the(UINT32)Lensubtraction. - If the offset-0 fragment is the one emptied at line 299 (send it after a fragment that starts inside it),
Ip6NtohHeaddereferences theNULLheader at line 335. - If the offset-0 fragment is the one emptied at line 254 (send it first, then an overlapping fragment), send the remaining fragments including the last one; at reassembly
NetbufGetFragmentreturnsNULLat line 401 and theNULL-based list entry is inserted at line 412, crashing the firmware.
Impact
Remote, unauthenticated denial of service in UEFI firmware during IPv6 network boot. Emptying the first fragment leads to writes through a NULL-based pointer (Ip6NtohHead at line 335, or the list insertion at line 412 followed by NetbufFromBufList walking a fake NET_BUF), which crashes the firmware, or writes to low memory where page 0 is mapped. The written addresses are fixed small offsets from 0, not attacker-chosen, so code execution is not shown. The inflated reassembly accounting can also deliver a malformed IPv6 packet with missing data ranges to upper layers.
Remediation and Mitigation
As of commit 70741a15d9a714323a5598eac47727e60507e22f this issue is unfixed upstream and no CVE has been assigned. Add the missing minimum-value check before the range comparison so a crafted value cannot take the wrong branch. 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.