β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4253

SATA-ID timeout recovery frees in-flight commands (SMID reuse confusion), can Target-Reset the wrong target, and overwrites targ->tm without NULL check

Summary

The scan matches ANY SATA_ID_TIMEOUT command regardless of handle, sends TARGET_RESET on the currently-added target, and the out: loop immediately frees the flagged command - even when the TM allocation failed, i.e. with no abort ever sent. The firmware may still complete the freed SMID; SMID-indexed reply dispatch then completes a reused command spuriously (wrong status/data - silent I/O corruption). targ->tm also assigned without checking for an outstanding TM, orphaning it. mpr twin of mps DF-4014/4015. reset_sent-flag + tm-slot guard fix (compile-validated).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4253 Β· 0 files
FileTypeDescriptionSize
empty

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

not_testable at kernel level on this guest (the defective block is firmware-gated behind mpr_config_get_sas_device_pg0 β€” proven empirically), but replica-validated: the FIXED variant of the verbatim block (fix.diff logic compiled in-module) keeps the flagged command out of the free list when no reset was sent (cm[3] state=2 flags=0x400 'still held'), preserves the outstanding targ->tm, and eliminates SMID reuse; the diff is additionally compile-validated inside the rebuilt patched kernel #1 (full nativekernel rc=0, fix_build.log in DF-4251 pack).

rig_fixed_replica.log (FIXED-variant narrative on baseline kernel, side-by-side with the unfixed replica results in run.log); fix_build.log shows mpr_sas_lsi.c with the fix compiling clean in the kernel build.
↓ fix.diffper-fix-DF-4253

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log: replica variant 1 (bitmask 0xf) 'scan hit cm[3] (owner tid 7 != added tid 5): sending TARGET_RESET to tid 5 -- WRONG TARGET'; 'REAL mpr_free_command(cm[3]) -- command returned to free list while (simulated) firmware still owns SMID 3'; 'REAL mpr_alloc_command() -> == SMID 3 REUSED'; 'targ_new->tm: before=0xfffff8011878e368 after=0xfffff8011878e4b0 (OVERWRITTEN)'. Variant 2 (bitmask 0xa): 'alloc_tm FAILED -- no abort of any kind sent' yet the command is still freed and SMID 3 reused; tm after=0x0 shows the failure branch also clobbers the TM pointer. rig_gate_panic_serial.txt / rig_gate_panic_canonical.txt: real add_device dies at the first config-page read (panic in the config error path β€” see incidental note). rig_fixed_replica.log: FIXED variant leaves cm[3] held (state=2 flags=0x400), tm preserved, no SMID reuse.

PoC changes

No seed PoC existed (previously 'untested'). Authored: (a) live dispatch of the REAL add_device to prove the firmware gate empirically; (b) verbatim replica of mpr_sas_lsi.c:984-1026 wired to the REAL production mprsas_alloc_tm and the REAL header-inline free/alloc commands, with only mprsas_send_reset shimmed (the wrong-target defect is decided at that call boundary, before any firmware I/O); (c) FIXED variant (-DFIXED) carrying the fix.diff logic for replica-level fix validation.

Verified recommended fix

free flagged command only after a Target Reset was actually sent; guard the targ->tm overwrite (fix.diff)

Verdict

INCONCLUSIVE at the firmware level β€” hardware-gated, with the mechanism proven live at the strongest level available short of the HBA. (1) The REAL production mprsas_add_device (nm-resolved 0xffffffff80593d40, prologue-verified) was dispatched on the live kernel and empirically cannot reach the defective block: it dies 0x5e bytes in at its first firmware dependency (mpr_config_get_sas_device_pg0, mpr_sas_lsi.c:817) β€” captured twice from the serial console with identical signature; the SATA-ID timeout precondition (a real identify passthrough timing out against LSI firmware) cannot be produced in QEMU. (2) A verbatim replica of the block driving the REAL production mprsas_alloc_tm (global T) and the REAL header-inline mpr_free_command/mpr_alloc_command (the same source the kernel compiles) demonstrates every defect: wrong-target TARGET_RESET (scan matched a command owned by tid 7, reset sent to the newly-added tid 5); free-while-in-flight INCLUDING the alloc_tm==NULL case where no abort of any kind was sent (the REAL mpr_free_command returned the flagged SMID to the pool and the REAL mpr_alloc_command immediately handed that exact SMID to the next requester β€” the SMID-reuse window in which a late reply is matched to the wrong command by the SMID-indexed dispatch in mpr_intr_locked); targ->tm orphaning on BOTH branches (success overwrites a non-NULL in-flight TM pointer; the failure branch assigns NULL over it β€” the unfixed assignment executes unconditionally). Status inconclusive per the established HW-gating posture (DF-1326 pass 2): every logic element ran production allocator/free code; the missing link is LSI firmware generating the timeout event and the late reply. On INVARIANTS kernels the free is additionally a deterministic KASSERT panic (mpr_free_command asserts cm_state==BUSY at mprvar.h:613 while the scan just set TIMEDOUT); this guest's kernel has no INVARIANTS so the silent release-kernel path was shown.