{
  "finding_id": "DF-2285",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "REPRODUCED on the stock INVARIANTS guest kernel with the verbatim scsi_targ_bh.c compiled into the kernel via the CAM verbatim-interposition harness (sha256-gated). With a dispatched CTIO held by the fake SIM (stalled initiator), targbhdtor sleeps the fixed hz/2 (65 ticks, no wakeup source exists in the driver), kfrees the softc while the CTIO is still SIM-owned, the freed chunk is deterministically reclaimed as a 0x41 canary victim on the same per-CPU slab zone, and the late completion (699 ticks outstanding, attacker-controlled window) executes targbhdone against the freed softc: the TAILQ_REMOVE at scsi_targ_bh.c:648 dereferences the freed chunk and the kernel panics with Bad link elm prev->next != elm from targbhdone+0x439 (INVARIANTS QMD_TAILQ_CHECK_PREV). Controls (no in-flight CTIO; CTIO completed before teardown) are clean; the A/B fixed kernel (active_ctios counter + wakeup drain in targbhdtor) blocks the dtor until the CTIO completes, shows softc_freed=0 at completion, zero post-free actions, canary intact, and identical control behaviour. Reachability is root-gated: optional targbh in sys/conf/files:46, absent from X86_64_GENERIC, no targbh.ko, requires a PIT_PROCESSOR target-mode SIM; no unprivileged path exists, so the demonstrated primitive (offset-deterministic read/write-after-free on a groomable 280-byte M_SCSIBH chunk plus freed-periph use via camperiphfree) caps at Medium DoS/corruption in root-configured target-mode deployments.",
  "exploit_chain": "remote initiator keeps one CTIO in flight (stall DATA phase past the 500 ms teardown budget) -> SIM/periph deregistration runs targbhdtor -> targbhdislun aborts only idle ATIOs/INs, never the in-flight CTIO -> kfree(softc) with the CTIO outstanding -> late CTIO completion into targbhdone -> TAILQ_REMOVE at :648 reads and writes through the freed chunk (on INVARIANTS: panic at the QMD_TAILQ_CHECK_PREV read; on production kernels: silent NULL+self-pointer writes into the replacement object) -> softc->state read from freed memory steers the re-arm branch at :689 which re-submits the stale ATIO into the torn-down periph -> camperiphfree has also freed periph and path. Escalation to uid0 was NOT developed: the driver is not reachable by unprivileged users on a stock system (root-gated module/config plus target-mode HBA), which caps severity at Medium; the memory-corruption primitive itself was demonstrated mechanically (same-chunk canary reclaim).",
  "evidence": "panic.txt: panic Bad link elm 0xfffff8008db00cc0 prev->next != elm with backtrace targbhdone+0x439 fired by the complete command with softc_freed=1. run.log: kfree(softc=0xfffff8004f296c20 size=280) (CTIO still HELD at fake SIM), targbhdtor RETURNED after 65 ticks (hz/2=50), reclaim: canary victim == freed softc chunk (SAME CHUNK reclaimed), dump damaged_qwords=0 pre-completion, complete: outstanding 699 ticks softc_freed=1; S0/S1 controls clean. fix_run.log: complete ... softc_freed=0, postfree_actions=0 rearm_after_free=0, dtor RETURNED after 192 ticks (drained), damaged_qwords=0, no panic; S0/S1 identical to baseline. rig/check_verbatim.sh output in build.log/fix_gen.log: embedded copy == sys source byte-for-byte (baseline 4bb4bca6..., fixed 4103058d...).",
  "kernel_refs": [
    "sys/bus/cam/scsi/scsi_targ_bh.c:402",
    "sys/bus/cam/scsi/scsi_targ_bh.c:420",
    "sys/bus/cam/scsi/scsi_targ_bh.c:421",
    "sys/bus/cam/scsi/scsi_targ_bh.c:329",
    "sys/bus/cam/scsi/scsi_targ_bh.c:342",
    "sys/bus/cam/scsi/scsi_targ_bh.c:347",
    "sys/bus/cam/scsi/scsi_targ_bh.c:419",
    "sys/bus/cam/scsi/scsi_targ_bh.c:497",
    "sys/bus/cam/scsi/scsi_targ_bh.c:522",
    "sys/bus/cam/scsi/scsi_targ_bh.c:648",
    "sys/bus/cam/scsi/scsi_targ_bh.c:676",
    "sys/bus/cam/scsi/scsi_targ_bh.c:678",
    "sys/bus/cam/scsi/scsi_targ_bh.c:689",
    "sys/bus/cam/cam_periph.c:626",
    "sys/sys/queue.h:528",
    "sys/kern/kern_slaballoc.c:815",
    "sys/conf/files:46"
  ],
  "poc_changes": "No pack existed (seed was the finding text only). Built the CAM verbatim-interposition kernel-compiled harness per the established DF-2270 pattern: df_pre.c renames all externals the driver calls, df_post.c implements the fake target-mode SIM (holds dispatched CTIOs, refuses to abort a SELECTED ATIO), a CPU-pinned dtor thread running the real targbhdtor under a real sim lock, and a same-chunk 0x41 canary victim reclaimed immediately after kfree. Two harness iterations were required: (1) DFly kmalloc/kfree are macros in sys/malloc.h, so the interposition needed #undef first and the shims call _kmalloc/_kfree; (2) post-free 0xDE scribbling corrupted slab free-list linkage (harness artifact, delayed chunk_mark_free panic) and cross-CPU zones broke the reclaim, fixed by the canary-victim design with a CPU-pinned dtor thread.",
  "attempts": 5,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Sun Oct 18 03:32:40 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (fixed-kernel build; baseline verdict kernel built and booted the same way, run.log/panic.txt; stock INVARIANTS config, opt_global.h INVARIANTS 1; guest reset to clean with-src stock kernel afterwards)",
  "runtime_sec": 150,
  "guest_dirty": 0,
  "build_cmd": "cd findings/poc/DF-2285/rig && ./build.sh (pushes df_pre.c/df_post.c + gen.sh to the guest, concatenates pre + verbatim sys/bus/cam/scsi/scsi_targ_bh.c + post into bus/cam/scsi/dftbh_harness.c registered standard in conf/files, make -j6 nativekernel KERNCONF=X86_64_GENERIC, installkernel, reboot; fixed run applies ../fix.diff to the guest /usr/src copy first via make_fix.sh)",
  "run_cmd": "cd findings/poc/DF-2285/rig && ./run.sh (sysctl debug.dftbh.cmd= ctor|inquiry|dtor|dtorwait|dump|complete on the guest; S0/S1 controls + S2 MAIN which panics; panic captured from serial into ../panic.txt); A/B: ./run_fixed.sh after make_fix.sh+build.sh",
  "code_hash": "8acf92baf610bf5dbe2c097d00ab23499a7ee807a0165afae40e1429d42f8095",
  "notes": "No DB writes performed. Guest left reset to the clean with-src stock kernel (harness removed from /usr/src). Baseline guest-side build log was overwritten by the fixed build on the guest; host-side build.log + installkernel.log + booted-kernel run evidence retained; fixed build kept full 35k-line fix_build.log. Reachability quantified: optional targbh (conf/files:46), absent from X86_64_GENERIC, no targbh.ko on the stock guest, requires PIT_PROCESSOR target-mode SIM; the only trigger actors are the root admin (load/config/teardown) and the remote initiator (stall window) - no unprivileged path, so the FOCUS/privesc protocol does not apply and the finding closes root-gated at Medium. Residual theoretical amplifier (abortmode=2: a SIM completing an abort for a ccb it handed to the periph) documented in VERDICT.md but not exercised. FreeBSD CURRENT still carries the identical fixed-sleep+free defect in its scsi_targ_bh.c (divergence noted); their scsi_target.c targ(4) driver frees queued CCBs in its dtor instead.",
  "recommended_fix": "Track dispatched CTIOs with an outstanding counter and drain them before freeing: u_int active_ctios in targbh_softc, increment in targbhstart before xpt_action, decrement+wakeup in the targbhdone XPT_CONT_TARGET_IO case, and replace the bare hz/2 sleep in targbhdtor with while (softc->active_ctios > 0) sim_lock_sleep(&softc->active_ctios, 0, targbhctio, 0, periph->sim->lock); see fix.diff (A/B validated)."
}
