← ALL ADVISORIES

MEDIUM BYTERAY-2026-0277Disclosed

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 at Ip6Input.c:335 and Ip6Input.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

  1. Send IPv6 fragments of one datagram, one of them with offset=0 and More flag set, to establish an assemble entry.
  2. Send an overlapping fragment with a different offset that triggers either overlap condition (line 246 or line 293).
  3. The TAIL branch in Ip6TrimPacket computes a negative Len; the fragment (headers included) is over-trimmed to 0 bytes while Info->Length grows by the overlap via the (UINT32)Len subtraction.
  4. If the offset-0 fragment is the one emptied at line 299 (send it after a fragment that starts inside it), Ip6NtohHead dereferences the NULL header at line 335.
  5. 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 NetbufGetFragment returns NULL at line 401 and the NULL-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.

References