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)
PoC verification
Evidence pack
findings/poc/DF-3402 Β· 2 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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:516ifsq_serialize_hw):IF_ENQUEUE(&sc->sc_fastq, m)(:494) andifsq_enqueue(ifsq, m)(:498). Holds no tty token. - Consumer β
slstart(:529-713), invoked from the tty drain path (e.g. sio'ssiopollundertty_token,sys/dev/serial/sio/sio.c:2241) or fromsl_outfill(:1040-1060):IF_DEQUEUE(&sc->sc_fastq, m)(:568) andifsq_dequeue(ifsq)(:572) undert_tokenonly (: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_testableConfirmed 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).
No comments yet.