msk_txeof() consumes the device-supplied TX done index (0..4095) with no MSK_TX_RING_CNT (256) range check: bogus index force-completes the entire in-flight TX window (premature dmamap_unload/m_freem on HW_OWNER descriptors)
Summary
msk_txeof walks 'for (; cons != idx; MSK_INC(cons, MSK_TX_RING_CNT))' where idx is device-supplied: the status LE's 11-bit fields (0..4095) from DMA and the watchdog's raw 16-bit CSR read - while the ring holds 256 entries. No range check exists. For an idx that can never equal cons (>=256, or behind cons), the only terminator is the msk_tx_cnt<=0 break, so one bogus index drains ALL in-flight descriptors: bus_dmamap_unload + m_freem on mbufs whose TX LEs still carry HW_OWNER - the NIC may still be DMA-reading those clusters (stale/freed kernel memory transmitted on the wire) - and leaves msk_tx_cons advanced to msk_tx_prod while the NIC prefetch unit still walks the old LEs. Memory-safe by construction (bounded by msk_tx_cnt, MSK_INC modulo keeps accesses in-bounds) - Low, device-trust hardening. Hardware-gated (no Marvell device on the guest); one-line range-check fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3808 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | β | 3.4 KB | β raw | |
| README.md | β | 974 B | β raw | |
| env.txt | β | 376 B | view raw | |
| fix.diff | β | 640 B | view raw | |
| verdict.json | β | 3.6 KB | view raw |
DF-3808 β analysis-only pack (no runnable PoC)
Structural source finding: msk_txeof() consumes the device-supplied TX
done index (11-bit status-LE fields / 16-bit STAT_TXAx_RIDX register,
0..4095 possible) with no MSK_TX_RING_CNT (256) range check. A bogus
index force-drains the in-flight TX window: unloads dmamaps and frees
mbufs the NIC may still own (HW_OWNER), desyncs cons/prod against the
NIC's prefetch unit. Walk stays in-bounds (bounded by msk_tx_cnt), so
impact is premature completion / stale-data-on-wire potential, not OOB.
No PoC was run: the trigger requires a faulty/hostile Yukon II NIC (the
index is written by the NIC's DMA, not by packet contents) and the audit
guest has no Marvell hardware (vtnet0/lo0 only, no 11ab: PCI devices).
fix.diff adds the range check at the top of msk_txeof(), covering both
call sites (status LE at if_msk.c:3206-3217, watchdog register read at
:2671-2674).
See VERDICT.md for the full path:line trace.
DF-3808 β msk_txeof() trusts the device-supplied TX done index without ring bounds
Verdict
Source-certain structural finding; not PoC-verified (status: untested). Severity Low, confidence likely. The missing validation is provable from the source; exploitation requires the NIC (or errant DMA) to misreport the index, so the guest (no Marvell hardware) cannot exercise the path. The same device-trust class as DF-3604 (bce(4)), filed Low here because the walk stays memory-safe and the impact is premature completion rather than out-of-bounds access.
Root cause (path:line)
msk_txeof() (sys/dev/netif/msk/if_msk.c:2884-2927):
2898: cons = sc_if->msk_cdata.msk_tx_cons;
2900: for (; cons != idx; MSK_INC(cons, MSK_TX_RING_CNT)) {
2901: if (sc_if->msk_cdata.msk_tx_cnt <= 0)
2902: break;
...
2906: sc_if->msk_cdata.msk_tx_cnt--;
...
2910: bus_dmamap_unload(...);
2915: m_freem(txd->tx_m);
2916: txd->tx_m = NULL;
2917: }
idx is device-supplied at both call sites:
mskc_handle_events()OP_TXINDEXLE:status & STLE_TXA1_MSKL(if_msk.c:3208-3209) βSTLE_TXA1_MSKL = 0x00000fff(if_mskreg.h:2198) β 0..4095, and for port B((status & 0xff000000) >> 24) | ((len & 0xf) << 8)β 0..4095 (if_msk.c:3211-3216), while the ring holdsMSK_TX_RING_CNT = 256entries (if_mskreg.h:2309).msk_watchdog():idx = CSR_READ_2(sc_if->msk_softc, STAT_TXA1_RIDX)(if_msk.c:2671-2674) β a 16-bit hardware register.
There is no range check against MSK_TX_RING_CNT. For an idx >= 256
(or an idx behind cons), cons (wrapped mod 256) can never equal
idx; the only terminator is the msk_tx_cnt <= 0 break. Consequences:
- The walk drains all in-flight descriptors (β€
msk_tx_cntβ€ 256 iterations β bounded, in-bounds array access viaMSK_INC's modulo, so no OOB), callingbus_dmamap_unload()andm_freem()on mbufs whose TX LEs still carryHW_OWNERβ the NIC may still be DMA-reading those clusters for transmission β transmission of stale/freed kernel memory onto the wire and dmamap state desync. - After the forced drain,
msk_tx_consis advanced tomsk_tx_prodwhile the NIC's prefetch unit still walks the old LEs; subsequentmsk_encap()calls overwrite hardware-owned descriptors.
The walk itself stays memory-safe (every visited descriptor is a live,
in-flight one, and every EOP descriptor in that window has a non-NULL
tx_m set by msk_encap at :2575-2579; m_freem(NULL) is also guarded,
sys/kern/uipc_mbuf.c). Hence Low, not Medium.
Threat model
Requires a faulty or compromised Yukon II (or PCIe-level DMA corruption) to write a bogus TX-index into the status LE / STAT_TXAx_RIDX register β not reachable from packet contents alone. Same trust boundary as DF-3604/DF-3807; defense-in-depth hardening.
Fix
fix.diff: range-check idx at the top of msk_txeof() (covers both
call sites) and ignore out-of-range values.
Kernel references
sys/dev/netif/msk/if_msk.c:2884-2927 (:2900-2902, :2906, :2910-2916), :2671-2674, :3206-3217; sys/dev/netif/msk/if_mskreg.h:2198-2210, :2309.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablefix.diff adds the one-line range check at the top of msk_txeof(), covering both call sites (status LE and watchdog register). Not validated at runtime: requires Yukon hardware to exercise msk_txeof; the change is trivially local and cannot affect the valid-index path.
fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (full path:line trace incl. the 0..4095 vs 256 arithmetic and the bounded-drain proof); fix.diff (range check, git apply --check clean); env.txt (no Marvell hardware on guest; untested rationale)
PoC changes
No PoC authored: hardware-gated device-trust finding (Low severity). Analysis-only pack.
Verified recommended fix
Range-check the device-supplied done index at the top of msk_txeof(): reject idx < 0 || idx >= MSK_TX_RING_CNT (see fix.diff).
Verdict
Source-certain structural finding, not PoC-verified (untested): the trigger input is written by the NIC (status-LE TX-index fields / STAT_TXAx_RIDX register), not by packet contents, so it cannot be exercised on the audit guest (no Marvell hardware; NO_MARVELL_PCI, vtnet0 lo0 only; src md5 == audited tree). msk_txeof (sys/dev/netif/msk/if_msk.c:2884-2927) consumes the device-supplied done index with NO range validation: mskc_handle_events feeds it 'status & STLE_TXA1_MSKL' and the port-B composite (if_msk.c:3206-3217) - 11-bit values, 0..4095 - and msk_watchdog feeds a raw 16-bit CSR read (if_msk.c:2671-2674), while the ring holds MSK_TX_RING_CNT = 256 entries (if_mskreg.h:2309). For an idx that can never equal cons (>= 256, or behind cons), the walk terminates only via the msk_tx_cnt <= 0 break (:2901-2902) and therefore force-completes the ENTIRE in-flight window: bus_dmamap_unload + m_freem on mbufs whose TX LEs still carry HW_OWNER (:2910-2916) - the NIC may still be DMA-reading those clusters (stale/freed kernel memory transmitted on the wire, dmamap desync) - and leaves msk_tx_cons advanced to msk_tx_prod while the NIC prefetch unit still walks the old LEs (subsequent msk_encap overwrites hardware-owned descriptors). Memory-safe by construction: the walk is bounded by msk_tx_cnt (<= 256) and MSK_INC's modulo keeps all array access in-bounds; every visited EOP descriptor has a non-NULL tx_m (set at :2575-2579) and m_freem(NULL) is guarded (sys/kern/uipc_mbuf.c) - hence Low severity, device-trust/defense-in-depth class (same trust boundary as DF-3604/DF-3807). fix.diff adds a one-line range check at the top of msk_txeof(), covering both call sites.
No comments yet.