← ALL ADVISORIES

LOW BYTERAY-2026-0276Disclosed

EDK II - Numeric Range Comparison Without Minimum Check in Ip4TrimPacket

In the TAIL branch of Ip4TrimPacket (lines 162–168), the trim length is computed as Len = End - Info->End (INTN).

Advisory
BYTERAY-2026-0276
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/Ip4Dxe/Ip4Input.c.
Credit
Argus-Systems

Executive Summary

In the TAIL branch of Ip4TrimPacket (lines 162–168), the trim length is computed as Len = End - Info->End (INTN). Because the branch guard is if (End < Info->End), this subtraction always produces a negative value. The correct computation should be Len = Info->End - End (positive bytes to trim from the tail). The HEAD branch at line 155 correctly computes Len = Start - Info->Start, confirming the TAIL branch has reversed operands. The negative Len is cast to (UINT32) at line 165 — wrapping to approximately 4.29 billion — and passed to NetbufTrim, which clamps it internally to TotalSize, trimming the fragment to 0 bytes. At line 167, Info->Length -= Len subtracts a negative value, inflating the length accounting. This corrupted Info->Length propagates to Assemble->CurLen (line 351), which can trigger premature reassembly and delivery of a packet with missing data ranges to upper-layer protocols. The NET_BUF bookkeeping itself stays consistent (the emptied fragment really has 0 bytes), so the delivered packet is simply shorter than the IP total length; delivery uses Packet->TotalSize (line 1230). The only caller that reaches the TAIL branch is line 340; the call at line 295 only uses the HEAD branch.

The ASSERT precondition at line 152 does NOT protect against this: for the triggering call site at line 340, Ip4TrimPacket(Packet, This->Start, Node->Start), the precondition (Info->Start < End) && (Start < Info->End) is satisfied by the fragment list ordering invariant, so the ASSERT passes in debug builds and is compiled out entirely in release firmware builds.

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/Ip4Dxe/Ip4Input.c:163
  • Function: Ip4TrimPacket
  • 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. The full path is: a raw IPv4 packet arrives from the network wire and enters Ip4AccpetFrame() (line 838), the registered MNP receive callback during PXE/HTTP boot with no authentication. The packet is forwarded to Ip4PreProcessPacket() (line 874), where attacker-controlled IP fragment offset fields are extracted into IP4_CLIP_INFO. When the MF flag is set or the fragment offset is non-zero, the packet enters Ip4Reassemble() (line 787). At line 334, an overlap is detected between the incoming fragment (This) and an existing fragment (Node) when Node->Start < This->End. This triggers the call Ip4TrimPacket(Packet, This->Start, Node->Start) at line 340. Inside Ip4TrimPacket, the TAIL branch guard if (End < Info->End) is true, and Len = End - Info->End at line 163 computes a negative INTN value (operands reversed). At line 165, (UINT32)Len wraps to approximately 4.29 billion, which NetbufTrim clamps to TotalSize, trimming the fragment to 0 bytes. At line 167, Info->Length -= Len subtracts a negative value, inflating the length accounting. The corrupted This->Length propagates to Assemble->CurLen at line 351, and premature reassembly is triggered at line 379 when CurLen >= TotalLen (the last fragment must already be queued, and the check at line 389 that the last fragment's End equals TotalLen still applies), delivering a packet with missing data ranges to upper-layer protocols.

Affected Callers

  • Ip4Reassemble

Sanitization / Security Controls

  • ASSERT guard at Ip4Input.c:151-152: 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 the triggering call site at line 340. Furthermore, ASSERT is a no-op in release firmware builds (the default shipping configuration). No other sanitization or runtime validation exists between the network input and the vulnerable sink.

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. Send a first fragment with offset=0, MF=1 (more fragments) to establish an assemble entry.
  2. Send a later fragment (MF=0, ending at the total length) that is already queued, then send a fragment whose range starts before that queued fragment and overlaps its start, so that Node->Start < This->End with This->Start < Node->Start (triggers the overlap condition at line 334 and the call at line 340).
  3. The TAIL branch in Ip4TrimPacket computes a negative Len; the fragment data is over-trimmed to 0 bytes while Info->Length is inflated.
  4. The inflated CurLen reaches TotalLen prematurely, triggering reassembly at line 379 with missing data ranges; the last fragment's End matches TotalLen, so the check at line 389 passes.
  5. The reassembled packet, shorter than the IP total length, is delivered to the upper-layer protocol (TCP/UDP/HTTP) during PXE boot.

Impact

IPv4 reassembly logic error. The inflated length accounting lets a reassembled packet be delivered with a byte range missing, so upper layers receive a shorter payload than the IP header describes. No memory-safety consequence follows: the NET_BUF sizes stay consistent, delivery uses Packet->TotalSize, and upper layers read the data through bounds-checked NET_BUF helpers. An attacker able to inject overlapping fragments can already inject arbitrary IP payloads, so the practical effect is limited to corrupted or dropped traffic during network boot.

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