DF-2283 / verdict.json
{ "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)" } |