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

mprsas_resetdev_complete dereferences a NULL task-management reply: XPT_RESET_DEV outstanding during a Diag Reset panics the kernel

Summary

mprsas_resetdev_complete is the only TM completion handler in the file without a cm_reply==NULL guard; it reads resp->IOCStatus/ResponseCode directly. mprsas_complete_all_commands - run by mprsas_handle_reinit during every Diag Reset - completes all outstanding commands with cm_reply=NULL then calls cm_complete. An XPT_RESET_DEV TM in flight at reset time (device error storms classically produce CAM RESET_DEV and controller reset together) faults on the NULL deref: kernel panic instead of recovery, and the ccb is never completed. Hardware-gated (no SAS3 HBA on the guest); fix.diff adds the guard mirroring mprsas_target_reset_complete.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3801 Β· 7 files
FileTypeDescriptionSize
README.md β€” 218 B ↓ raw
VERDICT.md β€” 2.9 KB ↓ raw
run.sh β€” 111 B view raw
env.txt β€” 855 B view raw
fix.diff β€” 1.3 KB view raw
verdict.json β€” 2.0 KB view raw
manifest.json β€” 446 B view raw

DF-3801 evidence pack

mprsas_resetdev_complete NULL-reply dereference β†’ panic during Diag Reset. Read VERDICT.md. fix.diff adds the missing guard. verdict.json: not_reproduced (no SAS3 hardware on guest).

VERDICT.md
↓ download raw

DF-3801 β€” mprsas_resetdev_complete dereferences a NULL reply β†’ kernel panic during Diag Reset

  • File: sys/dev/raid/mpr/mpr_sas.c
  • Class: kernel NULL-deref panic (missing NULL check)
  • Severity: Medium / Confidence: certain (statically provable)
  • Status on guest: not_reproduced β€” no SAS3 HBA (see env.txt)

Defect

Every task-management completion handler in this file guards against cm_reply == NULL:

  • mprsas_abort_complete β€” mpr_sas.c:1545
  • mprsas_logical_unit_reset_complete β€” mpr_sas.c:1300
  • mprsas_target_reset_complete β€” mpr_sas.c:1395
  • mprsas_remove_volume β€” mpr_sas.c:383
  • mprsas_remove_device β€” mpr_sas.c:582
  • mprsas_remove_complete β€” mpr_sas.c:657

mprsas_resetdev_complete (mpr_sas.c:3384-3427) does not:

    resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;   /* :3392 */
    ...
    if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { /* :3400 β€” only bail */
        ...
    }
    mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n",
        __func__, le16toh(resp->IOCStatus), le32toh(resp->ResponseCode)); /* :3412-13 DEREF */

Reachability

mprsas_complete_all_commands() β€” run from mprsas_handle_reinit() during every Diag Reset (mpr_reinit, e.g. from mprsas_tm_timeout mpr_sas.c:1255-1270) β€” deliberately completes all outstanding commands with cm->cm_reply = NULL and then invokes cm->cm_complete(sc, cm) (mpr_sas.c:1173-1207).

If CAM error recovery has an XPT_RESET_DEV in flight (mprsas_action_resetdev β†’ tm->cm_complete = mprsas_resetdev_complete, mpr_sas.c:3372) at the moment the controller is diag-reset, mprsas_resetdev_complete runs with resp == NULL and faults on resp->IOCStatus β†’ kernel panic.

Device error storms classically produce both events together: CAM escalates to XPT_RESET_DEV while the HBA simultaneously needs a controller reset. Note xpt_done(ccb) at mpr_sas.c:3426 is never reached, and the TM is never freed.

Fix

Add the same resp == NULL guard the sibling handlers have (see fix.diff); on NULL, complete the ccb with CAM_REQ_CMP_ERR/CAM_SCSI_BUS_RESET and free the TM.

Guest verification attempt

No SAS3 controller in the QEMU guest (pciconf -l: no LSI/Avago device; camcontrol devlist: only ata0/ata1/xpt0 buses). mpr is compiled in (pci/mpr registered) but mpr_attach never matches, so no XPT_RESET_DEV can ever reach mprsas_action_resetdev. Not reproducible on this hardware; the missing guard is provable from source with certainty. FreeBSD's mpr(4) carries the identical defect in mprsas_resetdev_complete.

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 adds the guard; cannot be exercised on this guest (no SAS3 HBA).

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

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (path:line proof), env.txt (no SAS3 HBA), fix.diff (NULL guard)

PoC changes

Trigger requires CAM error recovery racing a controller diag reset on real SAS3 hardware; run.sh records the hardware gate.

Verified recommended fix

Add resp == NULL guard (complete ccb with CAM_SCSI_BUS_RESET/CAM_REQ_CMP_ERR and free the TM), matching mprsas_target_reset_complete.

Verdict

mprsas_resetdev_complete (mpr_sas.c:3384) is the only TM completion handler in the file without a cm_reply==NULL guard; it dereferences resp->IOCStatus at mpr_sas.c:3412-3413. mprsas_complete_all_commands (mpr_sas.c:1173-1207) invokes cm_complete with cm_reply=NULL during every Diag Reset, so an XPT_RESET_DEV TM outstanding at reset time panics the kernel. Not reproduced on the guest: mpr driver present (pci/mpr) but no SAS3 PCI device exists, so no XPT_RESET_DEV can reach the SIM. The missing guard is certain from source; sibling handlers at mpr_sas.c:1300/1395/1545/383/582/657 all have it.