mpssas_resetdev_complete dereferences a NULL task-management reply: XPT_RESET_DEV outstanding during a Diag Reset panics the kernel (DF-3801 twin)
Summary
mpssas_resetdev_complete is the only TM completion handler in the file without a cm_reply==NULL guard: it falls straight to kprintf(resp->IOCStatus, resp->ResponseCode) with resp==NULL. complete_all_commands sets cm_reply=NULL and invokes cm_complete for every outstanding command during a Diag Reset, so an XPT_RESET_DEV in flight when recovery escalates to a controller reset reads near NULL and panics. All six sibling handlers carry the guard. Any failing/recovering mps-attached device whose error recovery overlaps a device reset with a controller diag reset - the standard recovery storm a dying disk produces. Guard fix (the accepted mpr DF-3801 pattern).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3893 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.4 KB | β raw | |
| VERDICT.md | β | 2.9 KB | β raw | |
| run.sh | β | 111 B | view raw | |
| run.log | β | 482 B | view raw | |
| env.txt | β | 274 B | view raw | |
| fix.diff | β | 970 B | view raw | |
| verdict.json | β | 2.4 KB | view raw | |
| manifest.json | β | 698 B | view raw |
DF-3893 β mpssas_resetdev_complete dereferences a NULL task-management reply: XPT_RESET_DEV outstanding during a Diag Reset panics the kernel
File: sys/dev/raid/mps/mps_sas.c (pass 2). Twin of DF-3801 (mpr_sas.c).
What
mpssas_resetdev_complete (sys/dev/raid/mps/mps_sas.c:2791-2834) is the
completion handler for XPT_RESET_DEV task-management commands. Unlike every
other TM completion handler in the file, it has no cm_reply == NULL
guard before dereferencing the reply:
resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; /* :2799 */
ccb = tm->cm_complete_data;
if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { /* :2807 */
... goto bailout;
}
kprintf("%s: IOCStatus = 0x%x ResponseCode = 0x%x\n",
__func__, resp->IOCStatus, resp->ResponseCode); /* :2819-2820 NULL deref */
tm->cm_reply is NULL whenever the command is completed by
mpssas_complete_all_commands (sys/dev/raid/mps/mps_sas.c:1030-1073),
which explicitly sets cm->cm_reply = NULL (line 1042) and then invokes
cm->cm_complete(sc, cm) (line 1053) for every outstanding command during
a diagnostic reset (mpssas_handle_reinit β mpssas_complete_all_commands,
mps_sas.c:1098; called from mps_reinit, mps.c:317).
Sibling handlers all guard this exact case:
- mpssas_logical_unit_reset_complete mps_sas.c:1160-1173
- mpssas_target_reset_complete mps_sas.c:1246-1259
- mpssas_abort_complete mps_sas.c:1378-1392
- mpssas_remove_device mps_sas.c:557-563, mpssas_remove_complete
mps_sas.c:627-633, mpssas_remove_volume mps_sas.c:360-366
Impact
Kernel NULL-pointer read (resp->IOCStatus at a small struct offset) β
panic. Trigger: any XPT_RESET_DEV in flight (issued by CAM error recovery
when a da(4) LUN keeps timing out, or by camcontrol reset) at the moment
error recovery escalates to a controller diagnostic reset
(mps_reinit, e.g. via mpssas_tm_timeout mps_sas.c:1131 or a NULL TM
reply escalation at mps_sas.c:1170/1256/1389). This is precisely the
recovery storm a failing disk produces.
Build/run
run.sh records the hardware gate (no SAS2 HBA in the guest; driver
compiled in but SIM never attaches). Source-level certainty: total.
Fix
Add the missing NULL guard, completing the CCB with CAM_SCSI_BUS_RESET and freeing the TM (see fix.diff) β identical to the guard pattern of the three sibling handlers and to the DF-3801 fix in mpr(4).
DF-3893 β VERDICT
Status: not_reproduced (hardware-gated) β defect certain from source. Impact class (on real hardware): kernel panic via NULL deref (DoS).
Proof chain
sys/dev/raid/mps/mps_sas.c:2784-2787β XPT_RESET_DEV is dispatched bympssas_action(mps_sas.c:981-984) tompssas_action_resetdev, which sends a TARGET_RESET TMF withtm->cm_complete = mpssas_resetdev_complete(mps_sas.c:2784).mps_reinit(sys/dev/raid/mps/mps.c:285-363) runs on error-recovery escalation paths βmpssas_tm_timeout(mps_sas.c:1131), NULL-reply escalations inmpssas_logical_unit_reset_complete(mps_sas.c:1170),mpssas_target_reset_complete(mps_sas.c:1256),mpssas_abort_complete(mps_sas.c:1389), and the failed-target-reset escalation (mps_sas.c:1289).mps_reinitβmpssas_handle_reinit(mps.c:317, mps_sas.c:1076) βmpssas_complete_all_commands(mps_sas.c:1098), which for every outstanding command setscm->cm_reply = NULL(mps_sas.c:1042) and callscm->cm_complete(sc, cm)(mps_sas.c:1053).- For an in-flight XPT_RESET_DEV,
cm_completeismpssas_resetdev_complete. Its ERROR_MASK branch (mps_sas.c:2807) is not taken (TM commands have no SGL, so CHAIN_FAILED cannot be set β the code's own comment at mps_sas.c:2802-2806 says so). It falls straight tokprintf(... resp->IOCStatus, resp->ResponseCode)at mps_sas.c:2819-2820 withresp == NULLβ read at NULL+offset β kernel panic. - Contrast: all six other TM/IOU completion handlers in this file have the
reply == NULLguard (mps_sas.c:360, 557, 627, 1160, 1246, 1378).mpssas_resetdev_completeis the lone omission β exactly the asymmetry that was DF-3801 in mpr_sas.c (fixed there by adding the guard).
Why not reproduced on this guest
No LSI SAS2 HBA exists in QEMU (env.txt, run.log): mps_attach never runs,
no SIM registers with CAM, and XPT_RESET_DEV can never be routed to
mpssas_action. Reproduction would need: real HBA + camcontrol reset (or
a da LUN in deep error recovery) racing a controller diag reset; expected
result: Fatal trap 12: page fault while in kernel mode reading near NULL
in mpssas_resetdev_complete.
Exploitability
DoS/panic only (NULL-page read). No escalation path; not pursued beyond classification because the primitive is a fixed near-NULL read.
Fix validation
Not testable on this guest. fix.diff adds the same guard the three sibling
handlers (and the mpr DF-3801 fix) use; behavior then matches
mpssas_target_reset_complete's DIAGRESET cleanup path.
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_testablefix.diff adds the guard; cannot be exercised on this guest (no SAS2 HBA).
findings/poc/DF-3893/fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (path:line proof incl. all sibling guards), env.txt (no SAS2 HBA), run.sh + run.log (hardware gate), fix.diff (NULL guard completing ccb with CAM_SCSI_BUS_RESET)
PoC changes
Trigger requires an XPT_RESET_DEV racing a controller diag reset on real SAS2 hardware; run.sh records the hardware gate.
Verified recommended fix
Add resp == NULL guard completing the CCB with CAM_SCSI_BUS_RESET and freeing the TM, matching mpssas_target_reset_complete.
Verdict
mpssas_resetdev_complete (sys/dev/raid/mps/mps_sas.c:2791) is the only TM completion handler in the file without a cm_reply==NULL guard; it dereferences resp->IOCStatus/resp->ResponseCode at mps_sas.c:2819-2820 immediately after the ERROR_MASK check. mpssas_complete_all_commands (mps_sas.c:1030-1073) invokes cm_complete with cm_reply=NULL (set at mps_sas.c:1042) for every outstanding command during a Diag Reset (mpssas_handle_reinit, mps_sas.c:1098, called from mps_reinit at mps.c:317), so an XPT_RESET_DEV TM outstanding at reset time reads near NULL and panics. All six sibling handlers have the guard (mps_sas.c:360, 557, 627, 1160, 1246, 1378). Not reproduced: guest has no SAS2 HBA (env.txt), the mps SIM never attaches, and XPT_RESET_DEV cannot reach mpssas_action. Missing guard is certain from source.
No comments yet.