Unauthenticated remote heap overflow in xe RX: missing upper-bound check on frame length before copying into 2KB mbuf cluster
Summary
xe_intr at if_xe.c:752: len=XE_INW(XE_RBC)-ETHER_CRC_LEN. No mask vs XE_RBC_BYTE_COUNT(0x1FFF). No check vs MCLBYTES(2048). len==0 guard misses unsigned wrap (RBC<4 -> len=0xFFFC..0xFFFF). Silicon accepts long packets up to 8184B. bus_space_read_multi_2 copies up to 8187 (or ~64KB wrap) bytes into 2046-byte mbuf cluster window. Remote on same L2 segment. Sibling pattern: every other DFly NIC driver checks MCLBYTES. Fix: mask RBC, check len<=MCLBYTES-2-1, check pktlen>=ETHER_CRC_LEN.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1410 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| harness.c | trigger-source | reproduces the buggy len arithmetic + (len+1)>>1 word count | 4.1 KB | view raw |
| build.sh | build-script | cc -O2 -Wall -o harness harness.c | 65 B | view raw |
| run.sh | run-script | ./harness | 41 B | view raw |
| build.log | build-log | in-guest build, BUILD_EXIT=0 | 13 B | view raw |
| run.log | run-log | decisive run; 4/7 cases overflow 6KiB..63KiB | 999 B | view raw |
| env.txt | environment | uname + guest PCI inventory (no Xircom) | 543 B | view raw |
| fix.diff | suggested-fix | mask XE_RBC, range-check vs MCLBYTES before cluster attach | 866 B | view raw |
| fix_build.log | fix-build-log | patched nativekernel, rc=0 | 5.6 MB | β download |
| VERDICT.md | verdict | full narrative | 3.6 KB | β raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1410 β xe(4) RX length missing upper bound (heap overflow)
Verdict
REPRODUCED (source-level harness). The bug is real; impact ceiling is
remote (unauthenticated, same-L2-segment) heap overflow of a 2 KiB mbuf
cluster, with overflow sizes from ~6 KiB (long packet) up to ~63 KiB (RBC<4
unsigned wrap). The kernel code path cannot be exercised on this guest
because QEMU does not emulate any PCMCIA bridge or the Xircom CE hardware β
xe0 does not exist in pciconf -lv. The fix.diff applies cleanly and
nativekernel succeeds (rc=0); no run-time exercise is possible because the
device is absent.
Mechanism (sys/dev/netif/xe/if_xe.c)
- Line 750:
u_int16_t len; - Line 752:
len = XE_INW(XE_RBC) - ETHER_CRC_LEN;β no mask againstXE_RBC_BYTE_COUNT(if_xereg.h:269, 0x1FFF) so the 3 flag bits in the high half contaminate the count; no upper-bound check vsMCLBYTES(2048); no lower-bound check thatRBC >= ETHER_CRC_LEN, so an RBC value of 0..3 wraps tolen = 0xFFFC..0xFFFF. - Lines 775-782:
MCLGETattaches a 2 KiB cluster; line 784m_data += 2reduces the usable window toMCLBYTES - 2. - Lines 822/826:
bus_space_read_multi_2(bst, bsh, XE_EDP, ehp, (len+1)>>1)copies2*ceil(len/2)bytes from the card into that cluster window β for any oversized or wrappedlen, this writes thousands of bytes past the cluster into the adjacent kernel heap.
Sibling drivers (dc, fxp, rl, etc.) all mask their RX-length register
and bound against MCLBYTES; xe is the outlier.
Harness proof (harness.c)
Uses the genuine register layout (XE_RBC_BYTE_COUNT = 0x1fff), the genuine
len = RBC - ETHER_CRC_LEN arithmetic, and the genuine
(len+1)>>1 word count. 4 of 7 representative inputs (silicon-long 8184 B
packet, plus RBC=0/1/3 wraps) produce overflows of 6 KiB..63 KiB. The fixed
variant (mask + range-check) accepts the legitimate packets and rejects the
oversized/wrapped ones:
case RBC bug_len oob_B fix_len oob_B silicon long 8184B packet 8184 8180 6134 -1 0 RBC=0 (wrap to 0xFFFC) 0 65532 63486 0 0 RBC=1 (wrap to 0xFFFD) 1 65533 63488 0 0 RBC=3 (wrap to 0xFFFF) 3 65535 63490 0 0 Buggy driver: 4/7 cases overflow the 2KiB mbuf cluster
Exploit-chain note
This is a remote unauthenticated heap-overflow primitive on real hardware. QEMU has no Xircom PCMCIA device, so the kernel-side chain cannot be exercised here. On a deployed Xircom CE2 system, every received long packet (8 KiB) or underflowed RBC corrupts adjacent heap deterministically; this is a credible remote heap-grooming β kernel-code-exec primitive in a real deployment. Documented as primitive characterization; impact ceiling is remote heap corruption.
PoC changes
- Original PoC folder had no source (
build.sh/run.shwere placeholders). - Added
harness.cplus repro scripts, env, build/run logs, fix.diff, VERDICT.md, manifest.json.
Fix
fix.diff masks XE_RBC against XE_RBC_BYTE_COUNT, requires
len >= ETHER_CRC_LEN, and rejects len - ETHER_CRC_LEN > MCLBYTES - 2 - 1
before attaching the cluster. This matches the pattern every sibling NIC
driver uses. Matches the finding markdown proposal.
Fix-validation
patch -p1 --forward succeeds (hunk #1 at line 749). nativekernel
completes with rc=0 (saved as fix_build.log). The kernel-side before/after
cannot be exercised because the device is absent β fix_status:
"not_testable". The diff is verified to apply and compile, and the changed
logic is traced to close the cited overflow.
Fix verification
not_testablenot_testable because the Xircom CE PCMCIA NIC is absent from the audit guest; validated that fix.diff applies cleanly (hunk #1 at line 749) and the single-fix nativekernel compiles rc=0 (fix_build.log). Traced the changed logic to mask + range-check before the cluster attach.
baseline (harness): Buggy driver: 4/7 cases overflow the 2KiB mbuf cluster patched kernel build: === NK_DONE rc=0 ===
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- n
- e
- t
- i
- f
- /
- x
- e
- /
- i
- f
- _
- x
- e
- .
- c
- :
- 7
- 5
- 0
- s
- y
- s
- /
- d
- e
- v
- /
- n
- e
- t
- i
- f
- /
- x
- e
- /
- i
- f
- _
- x
- e
- .
- c
- :
- 7
- 5
- 2
- s
- y
- s
- /
- d
- e
- v
- /
- n
- e
- t
- i
- f
- /
- x
- e
- /
- i
- f
- _
- x
- e
- .
- c
- :
- 8
- 2
- 2
- s
- y
- s
- /
- d
- e
- v
- /
- n
- e
- t
- i
- f
- /
- x
- e
- /
- i
- f
- _
- x
- e
- .
- c
- :
- 8
- 2
- 6
- s
- y
- s
- /
- d
- e
- v
- /
- n
- e
- t
- i
- f
- /
- x
- e
- /
- i
- f
- _
- x
- e
- r
- e
- g
- .
- h
- :
- 2
- 6
- 9
Detail
Exploit chain
none (HW-gated): Xircom CE2 is PCMCIA and QEMU has no PCMCIA bridge, so the in-kernel path cannot be exercised. Primitive characterized via harness: remote unauthenticated same-L2 heap overflow of a 2 KiB mbuf cluster with overflow sizes 6 KiB..63 KiB. Realistic ceiling on a deployed Xircom NIC: remote heap-grooming -> kernel-code-exec.
Evidence (decisive lines)
case RBC bug_len oob_B fix_len oob_B silicon long 8184B packet 8184 8180 6134 -1 0 RBC=0 (wrap to 0xFFFC) 0 65532 63486 0 0 RBC=1 (wrap to 0xFFFD) 1 65533 63488 0 0 RBC=3 (wrap to 0xFFFF) 3 65535 63490 0 0 Buggy driver: 4/7 cases overflow the 2KiB mbuf cluster
PoC changes
Original folder had no source (placeholder build.sh/run.sh). Added harness.c reproducing the genuine len arithmetic and word-count computation, plus repro scripts, env, full logs, fix.diff, VERDICT.md, manifest.json.
Verified recommended fix
fix.diff masks XE_RBC against XE_RBC_BYTE_COUNT and rejects len < ETHER_CRC_LEN or len-ETHER_CRC_LEN > MCLBYTES-2-1 before attaching the cluster, matching the pattern every sibling NIC driver uses. Matches finding markdown proposal.
Verdict
REPRODUCED at the source-logic level. if_xe.c:752 len = XE_INW(XE_RBC) - ETHER_CRC_LEN has no mask against XE_RBC_BYTE_COUNT (0x1fff, if_xereg.h:269) and no upper-bound vs MCLBYTES; line 826 bus_space_read_multi_2 copies (len+1)>>1 16-bit words into a 2048-byte mbuf cluster window. For RBC<4 the unsigned wrap yields len=0xFFFC..0xFFFF (63486..63490 byte overflow), and silicon-accepted 8 KiB packets yield len=8180 (6134 byte overflow). Harness confirms 4/7 representative inputs overflow; fixed variant rejects them all. No Xircom CE PCMCIA hardware on the guest so the kernel path cannot be triggered here; harness proof only.
No comments yet.