⬢ DragonFlyBSD Kernel Audit
DF-2283 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2283",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "denial_of_service",
  "confidence": "certain",
  "verdict": "REPRODUCED on the stock INVARIANTS kernel: sgread() parks read(2) forever on an unmatched pack_id because tsleep(&hstat, PCATCH, sgnull, 0) at scsi_sg.c:790 has NO wakeup source anywhere in the tree (hstat is a stack local of that very invocation; sgdone only wakeup()s rdwr at :363 and &ccb_h.cbfcnp at :346/:367). Control read with a matching pack_id returned instantly (result=0); the unmatched read sat in wchan sgnull for the full 23 s observation (timo=0) and only a signal could break it. Aggravation discovered live: after SIGTERM the reader transitioned from S4/sgnull to a kernel-bound R4 spin and the guest livelocked within ~2 minutes (sshd dead, serial silent, qemu alive) on both attempts -- the indefinite block escalates to a whole-system livelock when the sleeper is signaled. RESTRICTEDROOT/operator gated (sgopen checks SYSCAP_RESTRICTEDROOT at :385; /dev/sg0 is 0600 root:operator on this guest, so the unprivileged actor is excluded).",
  "exploit_chain": "",
  "evidence": "run.log: control read result=0 vs test read parked in wchan sgnull (S4 then I4 at +3s/+23s); run.log section run2: after SIGTERM the reader shows R4 (running, kernel priority) and the guest subsequently became unresponsive; env.txt: /dev/sg0 crw------- root operator",
  "kernel_refs": [
    "sys/bus/cam/scsi/scsi_sg.c:763",
    "sys/bus/cam/scsi/scsi_sg.c:784",
    "sys/bus/cam/scsi/scsi_sg.c:788",
    "sys/bus/cam/scsi/scsi_sg.c:790",
    "sys/bus/cam/scsi/scsi_sg.c:329",
    "sys/bus/cam/scsi/scsi_sg.c:346",
    "sys/bus/cam/scsi/scsi_sg.c:363",
    "sys/bus/cam/scsi/scsi_sg.c:367"
  ],
  "poc_changes": "v1 blocked the whole ssh session because the forked child inherited stdout; v2 parks the reader under nohup and observes it with external ps probes, keeping one fd open for the whole session to avoid interleaving with the DF-2282 close-underflow. The signal experiment was added after the first guest wedge.",
  "attempts": 4,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "runtime_sec": 180,
  "guest_dirty": 1,
  "build_cmd": "cc -O -Wall -o sg2283 sg2283.c",
  "run_cmd": "./sg2283 block  (reader parks; ps -o pid,stat,wchan probe externally)",
  "code_hash": "d6ac9cb14da15cee7aba18b068fd8dd04cb09341ac068d5cd8bb83c8c6f5b598",
  "notes": "Aggravation (livelock on signal) documented; primary claim (indefinite block) is the finding. Guest reset after runs.",
  "recommended_fix": "Bound the &hstat sleep with sc->sg_timeout and return ENOENT on timeout (fix.diff); validated on the fix kernel: the same read returns errno=2 after the 60 s command timeout instead of parking forever (fix_validation: fixed).",
  "fix_status": "fixed",
  "fix_validation": "fix kernel BUSAUDIT+fix: TEST read returned errno 2 (ENOENT) after the bounded timeout; process exited; no park, no livelock (fix2283.log captured in run.log appendix of VERDICT.md)"
}