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)
PoC verification
Evidence pack
findings/poc/DF-4253 Β· 0 files| File | Type | Description | Size | |
|---|---|---|---|---|
| empty | ||||
Fix verification
not_testablenot_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.
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.
No comments yet.