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

slstart drains sc_fastq/ifsq under tty locks while sloutput fills them under the ifsq serializer β€” no common lock, concurrent ifqueue corruption

Summary

Producer sloutput_serialized holds only the ifsq hardware serializer; consumer slstart holds only tty_token+t_token. The lock domains never intersect and ifqueue ops are non-atomic TAILQ manipulations -> concurrent enqueue/dequeue corrupts the queue: mbufs on two queues, m_nextpkt chains freed twice (double-free/UAF) or dequeue into freed chains. sloutput_serialized calling slstart directly while holding the serializer crosses the domains even same-CPU. MPSAFE tag is wrong for the fastq. Root-gated SLIP setup + SMP interactive-class TX while the tty drains -> mbuf-queue memory corruption. LEGACY bucket; not reproduced (needs serial driver + SMP contention). Fix: hold the tty token around the fastq enqueue (or a dedicated lock) + run slstart's dequeue under the ifsq serializer.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3402 Β· 2 files
FileTypeDescriptionSize
README.md β€” 2.4 KB ↓ raw
verdict.json β€” 1.7 KB view raw

DF-3402 β€” if_sl: slstart drains sc_fastq/ifsq under the tty locks while sloutput fills them under the ifsq serializer (no common lock)

What

sys/net/sl/if_sl.c shares two packet queues between two lock domains that never intersect:

  • Producer β€” sloutput_serialized (:451-507), running under the interface's hardware serializer (sloutput :516 ifsq_serialize_hw): IF_ENQUEUE(&sc->sc_fastq, m) (:494) and ifsq_enqueue(ifsq, m) (:498). Holds no tty token.
  • Consumer β€” slstart (:529-713), invoked from the tty drain path (e.g. sio's siopoll under tty_token, sys/dev/serial/sio/sio.c:2241) or from sl_outfill (:1040-1060): IF_DEQUEUE(&sc->sc_fastq, m) (:568) and ifsq_dequeue(ifsq) (:572) under t_token only (:539). Holds no ifsq serializer.

struct ifqueue/ifaltq operations are non-atomic TAILQ manipulations. Concurrent enqueue on one CPU and dequeue on another corrupts the queue: lost mbufs, one mbuf reachable from two queues, or a m_nextpkt chain that later gets m_freem'd twice (double free into the mbuf objcache β†’ use-after-free on subsequent allocations), or a dequeue that walks into a freed chain. sloutput_serialized:505 also calls slstart directly while holding the serializer β€” the reverse order of every other caller β€” so even the same-CPU interleavings cross the domains.

DF-0576..0579 covered the callout/t_typ lifetime races and the BPF stack copy; this queue-domain violation was missed. MPSAFE tag at :2 notwithstanding, the fastq has no lock at all and the ifsq's serializer is not held by the drain side.

Impact

Requires SLIP configured (root: SLIPDISC line discipline needs SYSCAP_RESTRICTEDROOT, :251) and then concurrent interactive-class (IPTOS_LOWDELAY β†’ fastq) TX traffic while the tty drains β€” e.g. a multi-CPU box routing telnet-style traffic over slip. Mbuf queue corruption is memory-safety class (double-free/UAF), realistically a panic. LEGACY bucket. Low / likely. Phase V skipped (legacy, race, needs serial-line driver + SMP contention β€” per batch instructions).

Fix

Protect sc->sc_fastq with the tty token in sloutput_serialized (acquire sc->sc_ttyp->t_token around the fastq enqueue) and make slstart's ifsq dequeue run under the serializer (or move both sides to a single lock, e.g. always call slstart via the ifsq serializer the way sloutput:505 already does).

Fix verification

not_testable
per-fix-DF-3402

Confirmed kernel references

Detail

Evidence (decisive lines)

['findings/poc/DF-3402/README.md']

PoC changes

n/a (Phase V skipped for this Low finding per batch contract)

Verified recommended fix

Hold the tty token around fastq enqueue in sloutput_serialized (or a dedicated fastq lock) and run slstart's ifsq dequeue under the ifsq serializer

Verdict

sloutput_serialized (if_sl.c:451-507) enqueues to sc->sc_fastq/ifsq holding only the ifsq hardware serializer (sloutput :516), while slstart (:529-713) dequeues the same queues holding only tty_token+t_token (called from sio's siopoll under tty_token, sio.c:2241, or from sl_outfill). The two lock domains never intersect and ifqueue ops are non-atomic TAILQ manipulations, so concurrent enqueue/dequeue corrupts the queue -- lost mbufs, mbuf on two queues, m_nextpkt chains freed twice (objcache double-free/UAF) or dequeue walking freed chains. Root-gated SLIP setup + SMP interactive traffic; LEGACY bucket; memory-safety class but realistically a panic. Phase V skipped (legacy race, per batch instructions).