β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3967

tx_intr STA_CSR4 completion desync: qid 5-15 garbage mapped to the mgt ring, results matched to the driver's stat cursor rather than a device index, unguarded txq->queued-- underflow defeating the ring-full gate, and m leaked on the ni==NULL path

Summary

tx_intr attributes each device-posted TX result to txq->data[txq->stat] - the driver's sequential cursor - and maps any qid>=4 to the mgt ring. Reordered/duplicated STA_CSR4 entries complete the wrong slot, freeing an in-flight mbuf while the device may still DMA it (UAF window); the unguarded queued-- underflows on spurious entries so the ring-full gate never trips and the post path reuses device-owned slots; the ni==NULL continue drops m without m_freem. Device-fed desync, different mechanism from rt2860's DF-3749. qid-check+floor+free fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3967 Β· 11 files
FileTypeDescriptionSize
README.md β€” 1.1 KB ↓ raw
VERDICT.md β€” 1.7 KB ↓ raw
trigger.c β€” 2.0 KB view raw
build.sh β€” 67 B view raw
run.sh β€” 91 B view raw
run.log β€” 12 B view raw
env.txt β€” 1021 B view raw
fix.diff β€” 1.0 KB view raw
build.log β€” 37.9 KB view raw
manifest.json β€” 370 B view raw
verdict.json β€” 3.2 KB view raw

DF-3967 β€” rt2661_tx_intr: device-fed TX-status desync (qid garbage β†’ mgtq, unguarded queued--, stat-cursor assumption) β†’ mbuf UAF window / m leak

File: sys/dev/netif/ral/rt2661.c (pass 2, checklist item (b) TX ring indices)

What

rt2661_tx_intr (896–960) attributes each device-posted TX result to txq->data[txq->stat] β€” the driver's cursor β€” and trusts the device's qid field ((val>>8)&0xf; qid 5..15 silently mapped to the mgt ring at 906). txq->queued-- (955) has no floor, so spurious results underflow queued and defeat the ring-full gate at 1687 β†’ the post path (1561–1562, 1643–1644) overwrites slots the device still owns. A result landing on an in-flight slot frees its mbuf via ieee80211_tx_complete (959) while the device may still DMA it. The ni == NULL continue (916–917) drops m without freeing (leak).

Device-gated (malicious/buggy NIC firmware), same trust class as rt2860's DF-3749 but a different mechanism (cursor desync vs. stale node map).

Build / Run

Hardware-gated; see trigger.c (fw-patched NIC or PCIe emulation posting spurious TX_STAT_VALID entries).

VERDICT.md
↓ download raw

DF-3967 verdict β€” likely device-fed desync, Low

Reproduced?

No Ralink NIC on the guest (env.txt).

Analysis

  • rt2661reg.h:191 RT2661_TX_QID(v) ((v>>8)&0xf) β†’ 0..15; rt2661.c:906 txq = (qid <= 3) ? &sc->txq[qid] : &sc->mgtq; β€” qid 4 is the intended mgt id, 5..15 are garbage yet indistinguishable from mgt.
  • rt2661.c:909 data = &txq->data[txq->stat] β€” completion is matched to the driver's sequential cursor, not to any device-provided index; any device reordering/duplication desyncs stat from the true completion order.
  • rt2661.c:955 txq->queued-- unguarded; gate at 1687 compares queued >= RT2661_TX_RING_COUNT - 1 β€” negative queued never trips it, so cur laps next and slots owned by the device are reused (1561-1562/1643-1644 overwrite data->m/desc while DMA pending).
  • rt2661.c:916-917: if (ni == NULL) continue; after m = data->m; data->m = NULL; β€” m is dropped, never freed (leak per spurious entry).
  • Driver-fed cursors themselves are in-bounds (cur/next/stat wrapped at count), so the memory-safety exposure is strictly device-fed desync.

Severity rationale

Low: requires a misbehaving device (same bar as DF-3749/DF-1312-class findings); consequence is an mbuf UAF write window (device DMA into a freed cluster) or resource exhaustion β€” real but hardware-gated.

Fix

fix.diff: reject qid>4, free m on the ni==NULL path, floor the queued--.

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_testable
baseline no→ patch + rebuild →patched clean

fix.diff closes the three gap (qid mapping, m leak, queued underflow); git apply --check clean. Runtime validation needs the NIC fix.diff applied to the guest /usr/src copy and the if_ral.ko module rebuilt clean with -Werror (build.log; combined with the other two rt2661 fix.diffs of this batch); runtime validation still impossible without the NIC.

fix.diff; fix.diff applied to the guest /usr/src copy and the if_ral.ko module rebuilt clean with -Werror (build.log; combined with the other two rt2661 fix.diffs of this batch); runtime validation still impossible without the NIC.
↓ fix.diffper-fix-DF-3967

Confirmed kernel references

Detail

Exploit chain

device posts duplicated/reordered TX_STAT_VALID entries -> stat cursor desync -> ieee80211_tx_complete frees an mbuf whose cluster the device still DMAs into -> freed-cluster reuse corruption window; independently queued<0 reopens a full ring -> slot overwrite while pending.

Evidence (decisive lines)

VERDICT.md (cursor/gate analysis path:line), trigger.c, env.txt, fix.diff (qid guard + m free + queued floor)

PoC changes

Informational trigger only (needs device firmware control / PCIe emulation).

Verified recommended fix

Validate qid<=4, free m on the ni==NULL path, and floor txq->queued at zero (fix.diff).

Verdict

Device-fed TX-completion desync in rt2661_tx_intr (rt2661.c:896-960): qid (val>>8)&0xf values 5..15 are silently attributed to the mgt ring (:906); results are matched to the driver's sequential stat cursor (:909) rather than a device index, so reordered/duplicated STA_CSR4 entries complete the wrong slot β€” freeing an in-flight mbuf via ieee80211_tx_complete (:959) while the device may still DMA it β€” and the unguarded txq->queued-- (:955) underflows on spurious entries, defeating the ring-full gate (:1687) so the post path reuses device-owned slots; the ni==NULL continue (:916-917) also leaks m. Requires a misbehaving/compromised NIC (same trust bar as sibling rt2860 DF-3749, different mechanism). Not reproduced: no Ralink hardware on the guest.