{
  "finding_id": "DF-3673",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Source-provable CCB lifetime race, timing-dependent, not executable on this guest (no MPT hardware). mpt_req_untimeout() is plain callout_stop() (mpt.h:769-772) on a callout_init_mp() callout, which per kern_timeout.c:1073-1096 does not interlock against an in-progress callback. mpt_timeout() (mpt_cam.c:1234-1255) reads ccb->ccb_h.ccb_mpt_ptr before the lock and ccb->ccb_h.ccb_req_ptr after acquiring it; if the timeout callback is already executing and blocked on the mpt lock while the completion path (mpt_scsi_reply_handler:2662-2723, or the turbo target paths 5252/5315) runs callout_stop + xpt_done, the callback resumes with a CCB that CAM has recycled (pooled XPT_SCSI_IO CCBS) or kfreed (zone CTIO CCBS, armed 60s at mpt_cam.c:4849): garbage req pointer -> req->serno wild read -> panic, or stale req -> TAILQ move of an innocent request to the timeout list -> spurious abort / list confusion. Window is user-amplifiable: pass(4) callers set ccb_h.timeout per command (1ms). Expected impact on hardware: local DoS/panic from an operator-group user; write-primitive via TAILQ_REMOVE not demonstrated.",
  "exploit_chain": "operator-group user -> pass CAMIOCOMMAND XPT_SCSI_IO with ccb_h.timeout=1ms in a tight loop -> callout fires on CPU A, blocks on mpt lock -> completion on CPU B: callout_stop (no interlock), xpt_done recycles/frees CCB -> CPU A resumes, reads ccb_req_ptr from reused memory -> wild request_t* deref (panic) or wrong-request TAILQ_MOVE + REQ_STATE_TIMEDOUT -> recovery aborts unrelated command",
  "evidence": "VERDICT.md (full interleaving with path:line); mpt_timeout_race.c (load harness); env.txt/run.log (no LSI hardware on guest); fix.diff (pool-resident callout arg + under-lock re-validation)",
  "kernel_refs": [
    "sys/dev/disk/mpt/mpt_cam.c:1234-1255",
    "sys/dev/disk/mpt/mpt_cam.c:2662",
    "sys/dev/disk/mpt/mpt_cam.c:2710",
    "sys/dev/disk/mpt/mpt_cam.c:5252",
    "sys/dev/disk/mpt/mpt_cam.c:5315",
    "sys/dev/disk/mpt/mpt_cam.c:4849",
    "sys/dev/disk/mpt/mpt_cam.c:1638-1641",
    "sys/dev/disk/mpt/mpt.h:769-775",
    "sys/kern/kern_timeout.c:1073-1096"
  ],
  "poc_changes": "n/a (authored from scratch)",
  "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": 38,
  "guest_dirty": 0,
  "build_cmd": "cc -O -o mpt_timeout_race mpt_timeout_race.c",
  "run_cmd": "./mpt_timeout_race /dev/passN (blocked: no mpt hardware on guest; presence probe run instead)",
  "code_hash": "2baa2361c245aba7a43968f71e94424316a3475a8baef14050c4cb964f4be24f",
  "notes": "Race exists in upstream FreeBSD too (its mpt_timeout uses MPT_LOCK_ASSERT), but DFlys self-locking variant adds the pre-lock ccb_mpt_ptr read. Cannot be triggered on this guest even on baseline (no mpt bus exists).",
  "recommended_fix": "Arm the callout with the pool-resident request_t instead of the CCB; take the mpt lock via a request back-pointer, re-validate REQ_STATE_QUEUED under the lock before touching the CCB",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff authored against read-only sys/ (request_t gains to_arg + sc back-pointer; callout arg becomes the request; under-lock re-validation). Build-and-run validation impossible: bug not triggerable on the baseline guest (no MPT hardware).",
  "fix_evidence": "fix.diff; env.txt documents hardware absence"
}