DF-4590 / verdict.json
{ "finding_id": "DF-4590", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "tws_detach() (tws.c:346-410) frees sc->reqs (398), sense_bufs (399), the AEN/trace queues (401-402) and lockuninit()s (403-406) while driver callouts referencing exactly that memory stay armed: sc->reset_cb_handle (tws_cam.c:1217/1232, hz/10 poll), sc->reinit_handle (tws_cam.c:1238/1256, self-re-arming every 5 s while the controller is not ready), and per-request thandle 60 s timeouts (tws_cam.c:847/893). No callout_stop/callout_cancel exists anywhere in the detach or attach-failure unwinds. A pending callout firing after detach executes tws_reinit/tws_reset_cb/tws_timeout on freed heap (and, with the module build that sys/dev/raid/tws/Makefile provides, potentially unmapped module text) - use-after-free in softirq context, panic or slab corruption. Not reproduced on the audit guest: no LSI 3ware (0x13C1) PCI device exists, tws is compiled into X86_64_GENERIC and attached to nothing, and QEMU cannot emulate a 9700-series controller (run.log/env.txt/guest_probe.log). Defect certain from source: every consumer pointer is freed by the same function that fails to cancel it. Trigger is root-privileged (kldunload during pending reset/reinit) - severity Low, class memcorrupt (UAF).", "exploit_chain": "", "evidence": "VERDICT.md (callout-consumer vs free-site line map); trigger.sh (exact unload-during-recovery recipe); run.log/env.txt/guest_probe.log (no 3ware HW on guest: pciconf empty for 13c1, dev.tws absent, kldload reports in-kernel); fix.diff (callout_cancel of 3 softc callouts + all reqs[i].thandle in detach + callout_init of thandles in tws_init_reqs; git-apply clean)", "kernel_refs": [ "sys/dev/raid/tws/tws.c:274", "sys/dev/raid/tws/tws.c:346", "sys/dev/raid/tws/tws.c:398", "sys/dev/raid/tws/tws.c:403", "sys/dev/raid/tws/tws_cam.c:847", "sys/dev/raid/tws/tws_cam.c:1217", "sys/dev/raid/tws/tws_cam.c:1238", "sys/dev/raid/tws/tws_cam.c:1256" ], "poc_changes": "No seed pack existed; trigger authored as documented unload-during-recovery recipe plus guest hardware-absence probe.", "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": 15, "guest_dirty": 0, "build_cmd": "n/a (hardware-gated; no guest-compilable trigger)", "run_cmd": "./run.sh", "code_hash": "50d9b120a8a21db03d9c1c5e17e52974c3d3a267e4dda7fc4745528a33078b11", "notes": "Hardware-gated (3ware 13C1:1010 + module config needed; tws is compiled into X86_64_GENERIC so the classic kldunload trigger needs the KMOD build). Ceiling: UAF panic / heap corruption at unload; root-privileged trigger (Low severity, memcorrupt class). Distinct from DF-1731 (pre-alloc window) and DF-4398-4403 (tws_cam.c completion/reset races).", "recommended_fix": "callout_cancel() the reset/reinit/print-stats callouts and every reqs[i].thandle in tws_detach (and attach-failure unwinds) after IRQ teardown, and callout_init() all thandles in tws_init_reqs so cancellation is always safe (see fix.diff).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "Fix not validated on guest: baseline cannot run (no 3ware controller, no QEMU emulation). fix.diff is git-apply clean against tws.c:346-410/597-636 and cancels every callout the recovery paths arm; validated by inspection.", "fix_evidence": "findings/poc/DF-4590/fix.diff" } |