{
  "finding_id": "DF-4364",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "REPRODUCED (harness; guest has no mps HBA - DF-1556/1557 method). mps_request_polled (mps.c:2140-2161) returns ETIMEDOUT with the request still posted to the IOC; every getter in mps_config.c then frees the command at its out: label (mps_config.c:167,311,637,762,884,1001,1120,1241,1386). When the wedged IOC later completes the stale SMID, mps_intr_locked (mps.c:1581-1600) writes cm_reply/cm_reply_data into the freed/reallocated object and runs mps_complete_command on it: the new owners completion callback fires with the stale CONFIG reply (cross-request type confusion), and the follow-on free returns a foreign reply frame to the reply free queue (or leaks it -> queue exhaustion). The mpr driver fixed exactly this lifecycle (mpr_wait_command takes mpr_command**, reinit-on-timeout, *cmp=NULL). Harness mirrors the kernel lifecycle field-for-field: 2/2 scenarios violate the invariants (exit 1); the fix.diff model (mps_request_polled calls mps_reinit on timeout) holds all invariants (exit 0).",
  "exploit_chain": "hung/malicious IOC stalls a config request ~50s then completes it late -> freed mps_command is reused for unrelated SCSI IO -> late completion invokes the SCSI completion callback with a CONFIG reply (misparsed as MPI2_SCSI_IO_REPLY) and stamps foreign cm_reply/cm_reply_data -> subsequent free corrupts the reply free queue (foreign/double slot free) or leaks the slot (reply exhaustion -> adapter wedge); alternatively the late completion lands on a still-FREE command, arming the same corruption for the next owner. Device-driven (firmware must stall then complete); realistic ceiling is kernel panic / I/O corruption / adapter DoS, not direct code execution",
  "evidence": "findings/poc/DF-4364/run.log: baseline Scenario A prints CROSS-REQUEST COMPLETION + FOREIGN FIELDS ON LIVE SCSI IO COMMAND + REPLY FOREIGN-FREE (RUN_EXIT=1), Scenario B prints STALE FIELDS ON FREE OBJECT + DOUBLE-BOOKED reply slot; fixed run prints invariants hold 2x, FIXED_EXIT=0",
  "kernel_refs": [
    "sys/dev/raid/mps/mps.c:2140",
    "sys/dev/raid/mps/mps_config.c:167",
    "sys/dev/raid/mps/mpsvar.h:514",
    "sys/dev/raid/mps/mps.c:1581",
    "sys/dev/raid/mps/mps.c:1405",
    "sys/dev/raid/mps/mps.c:1516",
    "sys/dev/raid/mpr/mpr.c:3557"
  ],
  "poc_changes": "wrote harness from scratch (no seed): field-for-field lifecycle model of mpsvar.h:514-555 free-list semantics, mps.c:2140-2161 polled timeout, mps.c:1581-1600 late completion, reply-slot ownership epochs; first draft had missing BUSY transition + weak confusion check, fixed during verification",
  "attempts": 3,
  "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": 240,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -o harness harness.c",
  "run_cmd": "./harness; ./harness_fixed",
  "code_hash": "8a0bc989c37b784227bad48307e05a78b2eae8982a1512add09c25fd5734a84d",
  "notes": "Guest clean (userland harness only, /tmp artifacts). Distinct from known DF-1556/1557: those are single-value bounds bugs at :1117/:462; this is the command-lifecycle defect common to all ten getters. Checklist cross-check of the rest of mps_config.c: remaining getters all MIN-bounds (163,634,880,998,1237,1382), set_dpm_pg0 allocation+bcopy both sized from fw length with MIN (725-737), no ext/phy-page getters in this vintage, iounit_pg8/pcie pages absent (nothing to check).",
  "recommended_fix": "Mirror the mpr fix: on polled timeout, mps_request_polled() must quiesce the chip (mps_reinit) before returning so the callers mps_free_command cannot race a late IOC completion (fix.diff); minimal backport alternative: leak the cm on ETIMEDOUT in the mps_config.c getters.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Harness-level fix validation: baseline violates all invariants (RUN_EXIT=1); with fix.diff modeled (-DFIXED: mps_reinit on timeout quiesces the IOC before the free) the identical scenarios hold all invariants (FIXED_EXIT=0). Kernel-build validation not possible on this guest (no LSI HBA); the change mirrors the already-proven mpr_wait_command pattern.",
  "fix_evidence": "findings/poc/DF-4364/run.log (baseline vs FIXED sections); fix.diff"
}