DF-4841 / verdict.json
{ "finding_id": "DF-4841", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "tws_init_obfl_q() (tws_hdm.c:118-148) only posts response frames whose sense_bufs[i].posted is false; the flags are cleared at exactly two sites - attach (tws_init_reqs, tws.c:620) and an OBFL-overrun repost failure (tws_cam.c:543) - neither of which runs on the reset/recovery path (tws_reset -> tws_reset_cb -> tws_reinit, tws_cam.c:1198-1266). tws_reinit() nevertheless resets obfl_q_overrun and re-runs the refill (tws_cam.c:1262-1266), which is therefore a complete no-op after the soft reset wipes the firmwares copy of the outbound free list: the firmware is left with zero response frames, init_connects own 60s poll (tws.h:74) cannot be answered, and every post-recovery command times out forever - a recoverable controller hiccup becomes a permanent adapter hang (local DoS of the storage path; root/hardware-fault trigger). The defect is certain from the drivers own invariant structure (the refill intent and the posted flags cannot both be correct), but hardware semantics of the soft reset were inferred, not measured - hence likely. Not reproduced: the audit guest has no 3ware 13C1 PCI device, dev.tws is absent, and QEMU cannot emulate a 9750 (guest_probe.log); same posture as DF-1924/1925/1926/4590/4591. Distinct from DF-1924/1925 (hang inside spin loops) and DF-1926 (init_connect slot leak): this is the successful-reset case where recovery completes and the adapter is still dead because the refill posted nothing.", "exploit_chain": "", "evidence": "VERDICT.md (four-step invariant argument with line receipts); trigger.c (hardware-gated trigger recipe); guest_probe.log (no 3ware PCI dev, dev.tws absent); fix.diff (tws_reset_obfl_q clearing posted flags on the reset path only - deliberately NOT inside init_obfl_q, whose OBFL-overrun caller must not double-post; git-apply dry-run clean)", "kernel_refs": [ "sys/dev/raid/tws/tws_hdm.c:118", "sys/dev/raid/tws/tws_hdm.c:128", "sys/dev/raid/tws/tws_cam.c:1262", "sys/dev/raid/tws/tws_cam.c:1266", "sys/dev/raid/tws/tws.c:620", "sys/dev/raid/tws/tws_cam.c:543" ], "poc_changes": "No seed pack. Authored pack: trigger recipe + hardware-absence probe + fix.diff.", "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": 20, "guest_dirty": 0, "build_cmd": "n/a (hardware-gated; in-kernel driver)", "run_cmd": "./run.sh (recipe only; needs 3ware 9750)", "code_hash": "9d1cf402a0b52573a41f0b15461e22bc541e950bf47d463f62424c3d4981029f", "notes": "DB-verify done for the known trio: DF-1924 (init_ctlr spin, lines 100-109), DF-1925 (ctlr_reset stage-1 spin, lines 473-475), DF-1926 (init_connect slot leak, lines 188-207) are all correctly attributed to sys/dev/raid/tws/tws_hdm.c in the findings table. Negative results this pass: TWS_PULL_MODE_ENABLE=1 (tws.h:60) compiles OUT the fw-controlled-offset bus_space_write loop (tws_hdm.c:316-324) incl. its int i = mfa truncation - dead code, not reported; tws_display_ctlr_info buffers are exact-size (16 into [16], tws_get_param memcpy bounded by param_size, tws_cam.c:949); init_obfl_q walk bounded by the clamped tws_queue_depth (tws.c:455-458) with sense_bufs sized by the same clamped value (tws.c:535-537); tws_aen_synctimes uptime-based epoch math is a functional quirk (can go negative for the first 3 days of uptime), not memory-unsafe; tws_send_generic_cmds stranded-slot-on-submit-failure is dead code (no callers).", "recommended_fix": "Clear sense_bufs[].posted on the reset path before re-running tws_init_obfl_q() (tws_reset_obfl_q() called from tws_reinit; see fix.diff).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "Fix not validated at runtime: no 3ware controller on the audit guest and QEMU cannot emulate one. fix.diff is git-apply clean (dry-run verified), places the clearing on the reset path only (not inside init_obfl_q, whose OBFL-overrun caller must not double-post frames still queued), and is validated by inspection against the four-step invariant argument in VERDICT.md.", "fix_evidence": "findings/poc/DF-4841/fix.diff" } |