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

Peer-freezable iocom reader: writer parked in fp_write with KDMSG_STATE_INTERLOCK set turns the 'dmrace' 1s-sleep loop into an indefinite cluster-link stall

Field Value
ID DF-2710
Status new
Severity Medium
CVSS 3.1 CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
CWE CWE-667 Improper Locking
File sys/kern/kern_dmsg.c
Lines 1636-1637 (set), 1663-1667 (clear), 825-828 (wait loop)
Area kern
Confidence certain
Discovered 2026-08-30
Pass 2 (GLM 5.3 second pass)
Bucket base:kern
Reported pending
Known CVE none
CVE match novel

Summary

kdmsg_state_msgtx() sets KDMSG_STATE_INTERLOCK at dequeue time; only cleanuptx β€” after fp_write() returns β€” clears it. A peer that stops reading parks the writer mid-transmission with INTERLOCK set; kdmsg_state_msgrx() then sleeps 1s per iteration on that state and the reader consumes nothing else, freezing both directions of the cluster link (kernel rcvbuf fills; all peer writes EAGAIN) until the peer resumes reading.

Threat model & preconditions

Any cluster peer freezes the kernel's cluster messaging indefinitely (withhold reads + one DELETE for an in-transmission msgid); on a clustered hammer2 mount, cluster-dependent VOPs block for the duration β€” recoverable system-wide DoS.

Proof of concept

VERIFIED on the non-INVARIANTS guest with a single DELETE (isolated from DF-2707): PAD probe 863/1024 then EAGAIN; 1024/1024 after drain; clean unmount (findings/poc/DF-2710/).

Bound the dmrace wait (bail after a few iterations) or move the interlock from state-level to queue-level so writer back-pressure cannot dead-wait the reader (diff sketch in the pack).

References

  • DF-2707 (uses this park primitive)

Timeline

  • 2026-08-30 Discovered during pass-2 audit of kern_dmsg.c (GLM 5.3); reproduced same run.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2710 Β· 4 files
FileTypeDescriptionSize
README.md β€” 2.1 KB ↓ raw
df2707_trigger.c β€” 13.5 KB view raw
manifest.json β€” 765 B view raw
verdict.json β€” 2.2 KB view raw

DF-2710 β€” peer-freezable iocom reader: parked writer turns the

"dmrace" INTERLOCK wait (kern_dmsg.c:827) into an indefinite cluster

link stall

What was verified (non-INVARIANTS kernel #1)

kdmsg_state_msgtx() sets KDMSG_STATE_INTERLOCK on the state of each message it dequeues for transmission (kern_dmsg.c:1636-1637); the bit is cleared only by the same thread's kdmsg_state_cleanuptx() after fp_write() returns (:1663-1667). If the peer stops reading, the writer parks inside fp_write() (unix-socket send buffer full) with INTERLOCK set. kdmsg_state_msgrx() for any subsequent message resolving to that state β€” e.g. the peer's DELETE for that msgid β€” hits the interlock and sleeps 1 second per iteration in the again: loop (kern_dmsg.c:825-828) while holding no other progress: the reader cannot consume anything else, so the kernel-side receive buffer fills and all cluster traffic in both directions stalls until the peer resumes reading.

PoC: df2707_trigger wedge (shared source) β€” parks the writer with SO_SNDBUF=2048 + junk transactions, sends a single DELETE (no duplicates β€” this is the benign control for DF-2707), then probes with non-blocking one-way LNK_PAD bursts:

WEDGE_PROBE1_WRITTEN=863/1024 <== reader stalled (rcvbuf full)
WEDGE_PROBE2_WRITTEN=1024/1024 (reader recovered after drain)
UNMOUNT_OK

Reader demonstrably stops consuming (send-side EAGAIN after 863 frames β‰ˆ rcvbuf capacity) and recovers the moment the peer drains. A peer can hold the link frozen indefinitely; on a clustered hammer2 mount any cluster-dependent VOP then blocks (recoverable system-wide DoS while the peer withholds reads).

Build & run

scp -F dfbsd-qemu/config findings/poc/DF-2710/df2707_trigger.c dfbsd:/root/poc/df2707/
dfbsd-qemu/vm.sh run_root 'cd /root/poc/df2707 && cc -O -I/usr/src/sys -o t df2707_trigger.c && ./t wedge'

Fix direction

Bound the interlock wait (e.g. break out after a few iterations and treat the message as EALREADY), or clear INTERLOCK before blocking in fp_write() (queue-level interlock instead of state-level), so a back-pressured writer cannot dead-wait the reader.

Fix verification

not_testable
per-fix-DF-2710

Confirmed kernel references

Detail

Evidence (decisive lines)

['run.wedge_probe.txt (WEDGE_PROBE1_WRITTEN=863/1024 stalled; WEDGE_PROBE2_WRITTEN=1024/1024 recovered; UNMOUNT_OK)', 'run.attack2_ssh.log + run.attack2_trigger.out (natural occurrence during DF-2707 run 2: trigger blocked writing churn after DRAIN_DONE)']

PoC changes

wedge mode of the DF-2707 trigger: parks the writer, sends a single DELETE for an in-transmission state, probes with non-blocking one-way LNK_PAD bursts before/after drain.

Verified recommended fix

Bound the dmrace wait (bail to EALREADY after a few 1s iterations) or move the interlock from state-level to queue-level so a back-pressured writer cannot dead-wait the reader.

Verdict

kdmsg_state_msgtx() sets KDMSG_STATE_INTERLOCK when dequeuing a message (kern_dmsg.c:1636-1637) and only kdmsg_state_cleanuptx() after fp_write() returns clears it (:1663-1667). A peer that stops reading parks the writer inside fp_write with INTERLOCK set; kdmsg_state_msgrx() then sleeps 1s per iteration on that state (:825-828, 'dmrace') and the reader consumes nothing else - the whole cluster link freezes in both directions until the peer resumes reading. Verified with a single DELETE (no duplicates, isolating it from DF-2707): PAD probe wrote 863/1024 then EAGAIN (kernel rcvbuf full, reader stalled); after drain the probe wrote 1024/1024 and the mount unmounted cleanly. Indefinite peer-held freeze of cluster messaging; cluster-dependent VOPs on a clustered hammer2 mount block for the duration.