mxge_tx_done walks the TX ring toward the unvalidated NIC send_done_count: premature TX-buffer free (device DMA-after-free) and permanent interrupt-context spin under tx/main serializers
Summary
mcp_idx is (int)send_done_count from the NIC-DMA'd fw_stats block. mxge_tx_done loops 'while (tx->pkt_done != mcp_idx)' with no relation to tx->req: a counter ahead of pkt_done unloads dmamaps and m_frees still-queued descriptors -> device DMA into freed mbufs; a counter that never matches spins forever once a ring revolution leaves every info[].m NULL - holding tx_serialize (and main_serialize on MSI/legacy) permanently. DF-3680/3714 family shape; idx stays masked so host-side damage is the freed-mapping reuse, not an OOB write. Occupancy-guard fix git-apply-clean.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3718 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.5 KB | β raw | |
| VERDICT.md | β | 1.7 KB | β raw | |
| fix.diff | β | 524 B | view raw | |
| verdict.json | β | 2.0 KB | view raw | |
| manifest.json | β | 820 B | view raw | |
| env.txt | β | 583 B | view raw |
DF-3718 β mxge_tx_done() walks the TX ring toward an unvalidated NIC completion counter
Vulnerability
sys/dev/netif/mxge/if_mxge.c mxge_tx_done() (:2364-2415):
while (tx->pkt_done != mcp_idx) { /* :2369 */
idx = tx->done & tx->mask;
tx->done++;
m = tx->info[idx].m;
if (m != NULL) { /* first-segment slots only */
tx->pkt_done++;
...
bus_dmamap_unload(tx->dmat, tx->info[idx].map);
m_freem(m); /* :2386 */
}
}
mcp_idx is (int)send_done_count β the firmware statistics block's
packet-completion counter, NIC-DMA'd data (mcp_irq_data_t.send_done_count,
mxge_mcp.h) β read at :2695/:2767/:2844 and passed from all three interrupt
paths (mxge_legacy :2699, mxge_msi :2770, mxge_msix_rxtx :2847).
There is no bound relating mcp_idx to tx->pkt_done/tx->req:
- Free of unsent descriptors (DMA-after-free). A counter even a few packets ahead makes the loop walk forward, unloading dmamaps and freeing mbufs for descriptors that are still queued-but-unsent. The NIC keeps owning those DMA mappings β post-free DMA reads of freed mbuf memory (content disclosure to the wire / corruption), the same shape as DF-3714 (em tx_collect) and DF-3680 (igb txeof).
- Infinite interrupt-context spin.
pkt_doneonly advances on non-NULLinfo[idx].m; after one full ring revolution every slot hasm == NULL,pkt_donefreezes, and if the NIC's counter still doesn't match (garbage, desync), thewhilespins forever β holdingtx->tx_serialize(entered at :2769/:2846) and, in the MSI/legacy paths,main_serialize(mxge_msiasserts it at :2737) β wedging the interface and blocking every thread that later tries to take those serializers.tx->done/idxstay masked (no OOB write), so the failure mode is a permanent spin/DoS, not memory corruption on the host side.
Threat model
NIC-DMA'd counter (hostile/compromised device or device fault), identical trust boundary to DF-3680/DF-3714 (both filed Low/certain).
Verification
Hardware-gated (no Myricom NIC on the guest; module never attaches) β
source-certain only, family convention β inconclusive.
Fix
fix.diff bounds the walk by ring occupancy (tx->done >= tx->req β
warn + break), which kills the runaway spin; a mismatched-but-in-range
counter still must be dealt with by the watchdog. git-apply clean.
DF-3718 VERDICT
Status: inconclusive (hardware-gated, family convention β cf. DF-3680 Low/certain, DF-3714 Low/certain), confidence: certain source-level.
Source proof
mcp_idxoriginates from the NIC-DMA'dmcp_irq_data.send_done_count(readbe32toh(stats->send_done_count)at if_mxge.c:2695/2767/2844, cast(int)and passed at :2700/:2770/:2847).mxge_tx_done(:2364-2415) loopswhile (tx->pkt_done != mcp_idx)with no relation totx->reqβ the driver's own knowledge of queued descriptors. Free path per iteration:bus_dmamap_unload+m_freemon any non-NULLinfo[idx].m(:2381-2387).- Forward-walk consequence A: descriptors still owned by the NIC get their maps unloaded and mbufs freed β device DMA into freed memory.
- Consequence B:
pkt_doneadvances only on non-NULL m; after one revolution all slots are NULL β permanent interrupt-context spin undertx_serialize(andmain_serializefor MSI/legacy paths, :2737) β interface and any serializer-acquiring threads wedge.
Not reproduced
Guest has no Myricom device (see env.txt); the stats block is device-written. No software-only trigger.
Fix
fix.diff: occupancy guard if (tx->done >= tx->req) break; + warning.
Mitigates the infinite spin; full validation of the counter against req is
the watchdog's job. fix_status=not_testable (no hardware).
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 git apply --check clean; not buildable without mxge hardware.
findings/poc/DF-3718/fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
findings/poc/DF-3718/VERDICT.md; fix.diff (occupancy guard, git-apply clean); env.txt
PoC changes
No seed PoC; hardware-gated.
Verified recommended fix
Guard the walk with ring occupancy: if (tx->done >= tx->req) break (warn), before consuming the next slot.
Verdict
Source-certain, hardware-gated (DF-3680/DF-3714 family): mxge_tx_done (if_mxge.c:2364-2415) walks the TX completion ring toward mcp_idx = (int)send_done_count, the NIC-DMA'd firmware stats counter (read :2695/:2767/:2844, passed :2700/:2770/:2847), with no bound against tx->req. A counter ahead of pkt_done unloads dmamaps and frees mbufs of still-queued descriptors (device DMA-after-free); a counter that never matches pkt_done (which freezes once a full revolution leaves every info[].m NULL) spins forever in interrupt context holding tx->tx_serialize and, on MSI/legacy, main_serialize - permanent interface/kernel-thread wedge. Guest lacks Myricom hardware; not runtime-testable (inconclusive per family convention).
No comments yet.