DF-4401 / verdict.json
{ "finding_id": "DF-4401", "status": "inconclusive", "reproduced": 0, "impact": "dos", "confidence": "certain", "verdict": "Certain from source, hardware-gated to trigger. tws_reset() guards re-entry with an unlocked state read (tws_cam.c:1203-1205) while the TWS_RESET transition happens later under gen_lock (:1207-1209) and tws_send_event asserts single entry (KASSERT at tws.c:666). Three concurrent callers exist (ccb-timeout callout :1191-1194 armed per I/O at :807; controller-error interrupt :1143-1153; passthrough ETIMEDOUT thread tws_user.c:146 holding gen_lock, survivable only via LK_CANRECURSE). Double entry: INVARIANTS kernels panic at tws.c:666/674; production kernels leak an xpt_freeze_simq count (double freeze at :1212-1214 vs single release in tws_reinit :1268-1270, counter semantics in sys/bus/cam/cam_xpt.c:4863-4865) leaving the SIM queue frozen forever = permanent adapter I/O hang, plus duplicated soft resets. tws_reinit also keeps retry counters in function-static storage shared across adapters (:1246). Guest lacks the HBA.", "exploit_chain": "", "evidence": "VERDICT.md (race proof + freeze-count arithmetic); fix.diff (locked re-check + per-adapter counters); trigger.c (reproduction recipe)", "kernel_refs": [ "sys/dev/raid/tws/tws_cam.c:1203", "sys/dev/raid/tws/tws_cam.c:1212", "sys/dev/raid/tws/tws_cam.c:1268", "sys/dev/raid/tws/tws.c:666", "sys/dev/raid/tws/tws_user.c:146", "sys/bus/cam/cam_xpt.c:4863" ], "poc_changes": "no seed; recipe stub only", "attempts": 1, "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": 0, "guest_dirty": 0, "build_cmd": "cc -o trigger trigger.c", "run_cmd": "n/a \u2014 needs distressed 3ware controller (see trigger.c recipe)", "notes": "Same defect class as DF-4336 (twa reset entry guard); rated Low for consistency. KASSERT/KKASSERT are INVARIANTS-only on DragonFly (sys/sys/systm.h:94-122).", "recommended_fix": "Serialize tws_reset entry: take gen_lock, re-check TWS_RESET, then run the RESET_START transition; move tws_reinit retry counters into the softc.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff moves the state check under gen_lock and makes reinit counters per-adapter; not validatable on the guest (no controller).", "fix_evidence": "fix.diff", "code_hash": "ecf867eff1bee1edc3e5a6d38e84c45c520a56732955b18cb58f7e64a0094a53" } |