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

mpssas_send_abort/mpssas_send_reset early -1 returns are ignored by every caller: targ->tm wedged forever, TM leaked, timed-out CCBs never returned to CAM, simq frozen for the life of the adapter (DF-3802 twin)

Summary

Both TM senders return -1 on a zero dev handle without unwinding: the TM is not freed, targ->tm is not cleared, and no TM timeout is armed on that leg. All five callers drop the return. Only TM completion handlers ever clear targ->tm - none will run - so later timeouts pile onto timedout_commands forever, the victim CCBs never reach xpt_done (XPT_ABORT is faked-success, so nothing can unwedge them), the high-priority TM leaks, and tm_count stays >=1 keeping the simq frozen. Provable trigger: mpssas_remove_volume clears targ->handle without draining targ->commands - unlike mpssas_remove_device which drains - and handle_reinit zeroes all handles without purging timedout_commands. Unprivileged IO outstanding on an IR volume being deleted wedges the entire adapter's I/O permanently. Port the accepted mpr DF-3802 fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3895 Β· 8 files
FileTypeDescriptionSize
README.md β€” 3.1 KB ↓ raw
VERDICT.md β€” 3.1 KB ↓ raw
run.sh β€” 111 B view raw
run.log β€” 482 B view raw
env.txt β€” 274 B view raw
fix.diff β€” 3.1 KB view raw
verdict.json β€” 2.8 KB view raw
manifest.json β€” 747 B view raw

DF-3895 β€” mpssas_send_abort/mpssas_send_reset early -1 returns are ignored by every caller: targ->tm wedged forever, TM leaked, unkillable CCBs, simq frozen permanently

File: sys/dev/raid/mps/mps_sas.c (pass 2). Twin of DF-3802 (mpr_sas.c).

What

Both task-management senders bail out early β€” without freeing the TM, without clearing targ->tm, without arming the TM timeout β€” when the target's handle has been cleared:

 mpssas_send_reset(...)                       /* mps_sas.c:1296 */
        target = tm->cm_targ;
        if (target->handle == 0) {
                mps_printf(...);
                return -1;                    /* mps_sas.c:1307 β€” tm leaked, targ->tm still == tm */
        }
 mpssas_send_abort(...)                       /* mps_sas.c:1436 */
        targ = cm->cm_targ;
        if (targ->handle == 0) {
                mps_printf(...);
                return -1;                    /* mps_sas.c:1447 β€” same */
        }

Every caller ignores the return value: - mpssas_scsiio_timeout mps_sas.c:1531-1537 (mpssas_send_abort(sc, targ->tm, cm) β€” return dropped) - mpssas_logical_unit_reset_complete mps_sas.c:1201-1204 (mpssas_send_abort), :1218-1220 (mpssas_send_reset escalation) - mpssas_abort_complete mps_sas.c:1418 (mpssas_send_abort continuation), :1428-1430 (mpssas_send_reset escalation)

Consequence (permanent wedge)

After the ignored -1: - targ->tm remains set. Only the TM completion handlers clear it (mps_sas.c:1165, 1206, 1251, 1278, 1384, 1409) β€” and no TM was ever sent, so none will run. Every later timeout on the target just queues onto targ->timedout_commands (mps_sas.c:1524-1530) and is never processed. - The triggering CCBs are never returned to CAM β€” the upper periph waits forever; even camcontrol abort cannot help because mpssas_action fakes success for XPT_ABORT without aborting anything (mps_sas.c:986-991). - The TM command leaks (high-priority credit gone) and tm_count stays β‰₯ 1, so the simq is frozen for the life of the adapter (mps_sas.c:262-265) β€” no further I/O through this SIM at all.

Provable trigger (same asymmetry DF-3802 proved for mpr)

mpssas_remove_volume clears targ->handle = 0x0 on successful IR volume removal (mps_sas.c:387-397) without draining targ->commands, unlike its sibling mpssas_remove_device which explicitly completes all missed commands (mps_sas.c:592-599, "Completing missed command"). Outstanding volume I/O therefore survives the handle clear; if any of it subsequently times out, mpssas_scsiio_timeout β†’ mpssas_send_abort hits targ->handle == 0 β†’ -1 β†’ wedge. The same zeroed-handle state also occurs for every target during diag-reset rediscovery (mpssas_handle_reinit, mps_sas.c:1113-1121), while timedout_commands are not purged.

Build/run

run.sh records the hardware gate (no SAS2 HBA in guest).

Fix

Mirror the accepted DF-3802 fix (findings/poc/DF-3802/fix.diff): on the -1 paths, clear targ->tm, free the TM, and complete every queued timedout command with CAM_DEV_NOT_THERE; additionally drain targ->commands in mpssas_remove_volume like mpssas_remove_device does. See fix.diff.

VERDICT.md
↓ download raw

DF-3895 β€” VERDICT

Status: not_reproduced (hardware-gated) β€” defect certain from source. Impact class (on real hardware): permanent adapter-wide I/O hang (DoS) + high-priority command leak; CCBs never returned to CAM.

Proof chain

  1. Early-exit-without-unwind sites: - sys/dev/raid/mps/mps_sas.c:1303-1307 (mpssas_send_reset, target->handle == 0 β†’ return -1) - sys/dev/raid/mps/mps_sas.c:1443-1447 (mpssas_send_abort, targ->handle == 0 β†’ return -1) In both, tm was already associated (targ->tm == tm, set by the caller at mps_sas.c:1531, or carried through escalation) and no callout_reset has been armed on this leg (those happen at mps_sas.c:1338/1466, after the handle check) β€” so nothing will ever complete or time this TM out.
  2. All five call sites drop the return: mps_sas.c:1203, 1218 (mpssas_logical_unit_reset_complete), 1418, 1428 (mpssas_abort_complete), 1536 (mpssas_scsiio_timeout).
  3. Wedge mechanics: targ->tm is cleared only inside TM completion handlers (mps_sas.c:1165, 1206, 1251, 1278, 1384, 1409) β€” none of which will run; subsequent timeouts queue onto targ->timedout_commands forever (mps_sas.c:1522-1530); the victim CCBs never reach xpt_done; XPT_ABORT is faked-success (mps_sas.c:986-991) so nothing external can unwedge them; tm_count remains β‰₯1 (incremented in mpssas_alloc_tm, mps_sas.c:242) so xpt_release_simq never happens (mps_sas.c:262-265) β€” the SIM queue is frozen for the life of the adapter.
  4. Provable trigger (twin of the mpr DF-3802 proof): mpssas_remove_volume zeroes targ->handle (mps_sas.c:387-397) after issuing the TM but without draining targ->commands, while mpssas_remove_device drains them ("Completing missed command", mps_sas.c:592-599). Outstanding volume I/O + a later timeout β‡’ mpssas_send_abort sees handle==0 β‡’ -1 β‡’ wedge. Additionally, mpssas_handle_reinit zeroes all target handles (mps_sas.c:1113-1121) without purging timedout_commands, so a timeout processed in the rediscovery window wedges identically.

Why not reproduced on this guest

No SAS2 HBA (env.txt, run.log); SIM never attaches; no mps command can time out. On hardware the wedge is observable as: console spam from mpssas_send_abort's mps_printf, camcontrol devlist hangs on that bus, all mps I/O blocked, tm_count stuck at 1 in MPS_TRACE logs.

Exploitability

DoS. An unprivileged user with access to a volume/disk being deleted (or any target during diag-reset rediscovery) whose I/O stalls can wedge the entire adapter's I/O permanently. No memory-corruption primitive.

Fix validation

Not testable on this guest. fix.diff ports the accepted DF-3802 fix verbatim to mps (unwind on the -1 paths + drain in remove_volume).

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

fix.diff ports the accepted DF-3802 mpr fix verbatim to mps; cannot be exercised on this guest (no SAS2 HBA).

findings/poc/DF-3895/fix.diff
↓ fix.diffper-fix-DF-3895

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (path:line proof incl. remove_volume/remove_device asymmetry), env.txt, run.sh + run.log (hardware gate), fix.diff (ports the accepted DF-3802 fix)

PoC changes

Trigger needs real SAS2 hardware (volume delete or diag-reset rediscovery racing a timeout); run.sh records the hardware gate.

Verified recommended fix

On the -1 paths clear targ->tm, free the TM, and complete queued timedout commands with CAM_DEV_NOT_THERE; drain targ->commands in mpssas_remove_volume like mpssas_remove_device.

Verdict

mpssas_send_reset (mps_sas.c:1303-1307) and mpssas_send_abort (mps_sas.c:1443-1447) return -1 on a zero dev handle without unwinding β€” the TM is not freed, targ->tm is not cleared, and no TM timeout is armed on that leg. All five callers ignore the return (mps_sas.c:1203, 1218, 1418, 1428, 1536). Result: only TM completion handlers ever clear targ->tm (mps_sas.c:1165/1206/1251/1278/1384/1409), so the target is wedged forever β€” later timeouts pile onto timedout_commands (mps_sas.c:1522-1530), the victim CCBs never reach xpt_done (XPT_ABORT is faked-success at mps_sas.c:986-991 so nothing can unwedge them), the TM high-priority credit leaks, and tm_count stays >=1 keeping the simq frozen for the life of the adapter (mps_sas.c:262-265). Provable trigger, twin of DF-3802's mpr proof: mpssas_remove_volume clears targ->handle (mps_sas.c:389) without draining targ->commands, unlike mpssas_remove_device (mps_sas.c:592-599); mpssas_handle_reinit zeroes all handles (mps_sas.c:1113-1121) without purging timedout_commands. Not reproduced: guest has no SAS2 HBA, SIM never attaches; wedge mechanics certain from source.