{
  "finding_id": "DF-5592",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "cam_sim_release() (cam_sim.c:241-256) kfrees the cam_sim with zero synchronization against the CAM completion softint: xpt_done() links the sim onto the global cam_simq lock-free from interrupt context (cam_xpt.c:4901-4917), camisr pops it and only then blocks on the sim lock (cam_xpt.c:7395-7406), and the standard driver detach (lock; xpt_bus_deregister(); cam_sim_free(); unlock -- ahci_cam.c:210-227 et al.) completes the whole free while camisr is blocked, so the softint subsequently writes the freed chunk (flags RMW at 7403, lockmgr at 7402, spin_lock/doneq walk at 7415-17) and dispatches (*ccb_h->cbfcnp)() from freed-object contents (7506). Deterministically reproduced on the stock guest kernel with a production-symbol mini-SIM rig: mode 1 executed a completion callback out of a kfreed sim (marker_hit=1, silent); mode 2 (poisoned freed chunk) stopped the guest in DDB at camisr_runqueue+0x53 (page fault on the wild doneq head). Trigger class is controller detach racing completion (root kldunload / virtio destroy / surprise removal + softint delay), so recorded impact is the proven panic/DoS; the function-pointer dispatch from freed memory is the documented uid0 ceiling on this unhardened guest (no SMAP/SMEP/KASLR), not weaponized in this run.",
  "exploit_chain": "detacher holds sim lock -> late xpt_done() (lock-free, interrupt context) links sim on cam_simq and arms swi -> camisr pops sim, blocks on sim lock -> detacher runs xpt_bus_deregister()+cam_sim_free() -> kfree(sim) while camisr holds raw pointer -> lock release -> camisr: lockmgr on freed lock, flags RMW write, spin_lock, walks freed sim_doneq, calls (*ccb_h->cbfcnp)(path->periph, ccb) with ccb image living in freed/reused memory -> attacker who reallocates the 168-byte M_CAMSIM chunk controls the call target and both pointer args (arbitrary kernel call; retpoline-thunked but resolvable on this guest). PoC chain executed up to the controlled-callback stage via marker ccb (cbfcnp invoked from freed sim) and to a hard fault via poisoned doneq head.",
  "evidence": "run.log (decisive serial lines incl. *** UAF CONFIRMED: kernel ran a completion callback out of a cam_sim chunk that cam_sim_free() had already kfree()d ***); panic.txt (full console: [Stopped at camisr_runqueue+0x53: movq 0x20(%r15),%rax] db>); ptsim3.c (rig; modes 1/2/4); VERDICT.md; fix.diff + fix_build.log + fix_run.log (fix validation); mode 4 baseline trail shows chunk refcount 0 (freed) immediately after cam_sim_free while camisr still blocked",
  "kernel_refs": [
    "sys/bus/cam/cam_sim.c:241-256",
    "sys/bus/cam/cam_sim.c:228-234",
    "sys/bus/cam/cam_xpt.c:4891-4926",
    "sys/bus/cam/cam_xpt.c:7389-7407",
    "sys/bus/cam/cam_xpt.c:7415-7417",
    "sys/bus/cam/cam_xpt.c:7506",
    "sys/bus/cam/cam_xpt.c:4322",
    "sys/dev/disk/ahci/ahci_cam.c:210-227",
    "sys/dev/virtual/virtio/scsi/virtio_scsi.c:675-687"
  ],
  "poc_changes": "Original sketch did not exist (new finding); rig chassis derived from DF-5550s ptsim2 with: LK_CANRECURSE sim lock (rig boot panic otherwise), noattach INQUIRY mode + scan-on-demand (first deregistration attempt wedged in periph destroy_dev teardown under the sim lock), marker-ccb callback instead of heap-spray reclaim (spray missed the chunk twice on this allocator), direct write of the freed chunk for the crash demo, mode-4 fix-validation trail",
  "attempts": 5,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026\troot@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "runtime_sec": 2400,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh   (in guest /root/df5592; builds ptsim3/ptsim3.ko)",
  "run_cmd": "kldload ./ptsim3/ptsim3.ko; sleep 2; sysctl debug.ptsim3.go=1   # or =2 (panic) / =4 (fix check)",
  "code_hash": "ac2b604d727bb3aa794653c523e00e54cb2279eab77c82e9f42b5a994c71debb",
  "notes": "Rig incidentally captured cam_devq_release: WARNING active allocations 8 active send 8! during the detach (DF-5552/DF-5594 provenance firing live) and the DF-5593 pool leak (8 orphaned ccbs) in the same flows. The camisr-blocked interleaving is the deterministic form of the in-tree race (softint delayed past a full deregister+free under the sim lock); no unlocked xpt_done is required, although xpt_done also being lock-free vs the free is the second, wider window (stale path->bus->sim read vs topo-lock retarget) noted for future work in cam_xpt.c Guest was dirtied during fix validation (patched kernel installed + booted); vm.sh reset with-src executed before return, clean snapshot restored.",
  "recommended_fix": "Pin the sim (atomic ref under cam_simq_spin) while linked on cam_simq; camisr drops the pin after processing; rewrite cam_sim_release() as an atomic cmpset protocol (xpt_sim_finalize under cam_simq_spin for the 1->0 transition); pin cam_dead_sim.refcount high -- see validated fix.diff",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "fix.diff applied to guest /usr/src, kernel rebuilt (make nativekernel KERNCONF=X86_64_GENERIC, fix_build.log), installed, rebooted; the exact mode-4 rig choreography that baseline-crashed (mode 2) and freed the sim early (modes 1/4: chunk refcount 0 right after cam_sim_free) now shows chunk refcount 1 (cam_simq pin held -> sim NOT freed while camisr blocked), the completion callback runs with the sim valid+locked, and the chunk reaches kfree only after camisr drops the pin -- UAF window closed, no trap",
  "fix_evidence": "fix.diff; fix_build.log; fix_run.log (patched-kernel mode-4 serial trail)"
}