DF-4335 / verdict.json
{ "finding_id": "DF-4335", "status": "untested", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Kernel path not runnable on this guest (no 3ware 9000-series hardware: no /dev/twa*, 0 PCI 13c1 devices), but the defect is a deterministic single-threaded logic error, and its queue-corruption mechanism was reproduced on the guest with the drivers own TW_CL_Q_* list macros: after a 60s poll timeout of a PENDING internal request, tw_cli_get_param/tw_cli_set_param insert the request into FREE_Q a second time (helper already inserted it at tw_cl_io.c:1029), producing an unwalkable self-looped free queue (in-kernel: unbounded spin while holding the gen_lock spinlock) and repeated handout of the same request context to two owners; the BUSY-timeout variant leaves one request simultaneously in BUSY_Q and FREE_Q, so its cmd_pkt DMA buffer is rebuilt under live firmware ownership and the late response completes the wrong request including a 1024-byte copyback into a foreign OSL buffer (tw_cl_intr.c:407-416). Sibling of DF-1814/DF-4274 at a distinct site in this file.", "exploit_chain": "3ware controller present + internal get/set_param poll request times out (wedged/slow firmware at attach or during controller reset; no ioctl needed) -> FREE_Q double-insert or BUSY+FREE dual membership -> (a) any CPU touching a CL request queue spins forever on gen_lock (hard wedge), or (b) same request context handed to two owners -> cmd_pkt rewritten while firmware owns the DMA -> late firmware response completes the wrong request -> 1024-byte firmware-controlled copyback into wrong kernel buffer. Not exercisable on this guest.", "evidence": "run.log (guest-executed model reproducer: Case 1 INFINITE CYCLE + handed out 2 time(s), Case 2 dual-queue membership, Case 3 fixed-sequence clean); VERDICT.md (line-by-line trace); fix.diff (git-apply-valid against sys/)", "kernel_refs": [ "sys/dev/raid/twa/tw_cl_io.c:781", "sys/dev/raid/twa/tw_cl_io.c:812", "sys/dev/raid/twa/tw_cl_io.c:899", "sys/dev/raid/twa/tw_cl_io.c:929", "sys/dev/raid/twa/tw_cl_io.c:999", "sys/dev/raid/twa/tw_cl_io.c:1029", "sys/dev/raid/twa/tw_cl_intr.c:407", "sys/dev/raid/twa/tw_cl_misc.c:140", "sys/dev/raid/twa/tw_cl.h:270" ], "poc_changes": "No hardware PoC possible; authored a deterministic logic-model reproducer using the drivers verbatim TW_CL_Q_* macros (tw_cl_share.h) modeling submit_and_polls timeout tail vs get/set_params out: path; bounded the queue walkers with cycle guards so the (deliberately corrupted) list walk terminates and reports the cycle instead of hanging.", "attempts": 3, "guest_uname": "DragonFly dfbsd 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": 900, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o poc_dblinsert poc_dblinsert.c", "run_cmd": "./poc_dblinsert", "code_hash": "313a78085b9c5092fc6ed5954fc25d82239d20a6026e90d6edb609d2b0526f7d", "notes": "Device is 0600 root:operator (tw_osl_freebsd.c:405) but the trigger needs no ioctl: attach-time notify_ctlr_info get_param or reset-time SYNC_TIME set_param with a wedged firmware suffices. Poll-mode requests run only while controller interrupts are torn down, so the code comments Need to revisit ISR race is unreachable; this finding needs no race at all.", "recommended_fix": "get_param/set_param out: paths must not re-queue (nor clear internal_req_busy) on TW_OSL_ETIMEDOUT; give BUSY-timed-out poll-mode requests a tw_cli_poll_requeue_callback so the next reset drain re-queues them exactly once (fix.diff).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "Kernel fix validation impossible on this guest (no twa hardware). fix.diff is git-apply-valid against sys/; the model reproducers Case 3 demonstrates the patched call sequence restores single-queue membership in both timeout variants.", "fix_evidence": "findings/poc/DF-4335/fix.diff (git apply --check PASS); run.log Case 3 lines" } |