DF-3845 / verdict.json
{ "finding_id": "DF-3845", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "Missing serialization between the OCR flush and the ISR completion path (DF-3813 concurrent-reinit family). mrsas_complete_cmd runs from the MSI handler with no lock (mrsas.c:1219, guard only the pre-walk test_bit at mrsas.c:1213); mrsas_reset_ctrls return-to-CAM loop (mrsas.c:2335-2343) checks mpt_cmd->ccb_ptr and calls mrsas_cmd_done with only a 1-second DELAY heuristic (mrsas.c:2327) protecting against an already-running ISR \u2014 mrsas_disable_intr (mrsas.c:2326) does not stop a delivered interrupt on another CPU. When both sides pass their non-atomic check, one mpt cmd gets double mrsas_cmd_done: double xpt_done (CAM ccb UAF) or xpt_done(NULL) panic, plus double mrsas_release_mpt_cmd duplicating the cmd on the free TAILQ (mrsas_cam.c:611) so two future IOs share one command. Aggravator: mrsas_scsiio_timeout unconditionally re-arms a 600 s callout (mrsas_cam.c:370) and mrsas_cmd_dones callout_stop (mrsas_cam.c:1082) does not drain a running callback, so the timer fires later on the recycled command and re-triggers OCR \u2014 turning a one-in-a-million overlap into a recurring trigger after any single IO timeout. Cannot execute on the audit guest: mrsas is compiled in but no LSI HBA exists, so no completions/OCR can occur (run.log).", "exploit_chain": "induce one IO timeout (slow/stuck firmware) -> timeout callback sets do_timedout_reset and re-arms on the cmd -> OCR thread resets while an ISR drain is in flight -> both sides complete the same mpt cmds -> duplicated free-list entries / double xpt_done -> pool corruption and CAM-layer use-after-free; recurring because the 600 s re-arm fires on recycled commands.", "evidence": "VERDICT.md interleaving with mrsas.c/mrsas_cam.c line cites; run.log guest presence check (driver in kernel, no HBA, no /dev/mrsas*).", "kernel_refs": [ "sys/dev/raid/mrsas/mrsas.c:1213", "sys/dev/raid/mrsas/mrsas.c:1219", "sys/dev/raid/mrsas/mrsas.c:2324", "sys/dev/raid/mrsas/mrsas.c:2326", "sys/dev/raid/mrsas/mrsas.c:2327", "sys/dev/raid/mrsas/mrsas.c:2335", "sys/dev/raid/mrsas/mrsas.c:2340", "sys/dev/raid/mrsas/mrsas.c:2522", "sys/dev/raid/mrsas/mrsas_cam.c:352", "sys/dev/raid/mrsas/mrsas_cam.c:370", "sys/dev/raid/mrsas/mrsas_cam.c:1080", "sys/dev/raid/mrsas/mrsas_cam.c:1082", "sys/dev/raid/mrsas/mrsas_cam.c:611" ], "poc_changes": "No seed PoC; race needs an attached HBA generating completions plus an induced fault/timeout. Guest cannot reach the code (no /dev/mrsas*, no SIM activity).", "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": 10, "guest_dirty": 0, "build_cmd": "n/a (race requires HBA; presence check only)", "run_cmd": "kldstat -v | grep -i mrsas; pciconf -lv | grep -i megaraid; ls /dev/mrsas*", "code_hash": "", "notes": "DF-3813/DF-3673/DF-3710 family. The overlap window for the raw ISR-vs-flush race is narrow (needs an ISR drain still running 1 s after disable_intr); the callout re-arm aggravator widens exposure by re-triggering OCR from a stale timer. callout_stop without drain is itself the same defect class as accepted DF-3673.", "recommended_fix": "Make mrsas_cmd_done idempotent via an atomic cmpset claim of ccb_ptr, stop the unconditional 600 s callout re-arm in mrsas_scsiio_timeout, and have the OCR flush loop rely on the same claim.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff makes completion idempotent (atomic cmpset of ccb_ptr) so no interleaving can double-complete, and removes the 600 s re-arm. Not boot-testable on this guest (no HBA) -> not_testable.", "fix_evidence": "fix.diff hunks in mrsas_cam.c (timeout callback, cmd_done) and mrsas.c reset flush loop." } |