⬢ DragonFlyBSD Kernel Audit
DF-3801 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/raid/mpr/mpr_sas.c b/sys/dev/raid/mpr/mpr_sas.c
index 1111111..2222222 100644
--- a/sys/dev/raid/mpr/mpr_sas.c
+++ b/sys/dev/raid/mpr/mpr_sas.c
@@ -3390,9 +3390,21 @@ mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm)
 	resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
 	ccb = tm->cm_complete_data;
 
+	/*
+	 * DF-3801: a Diag Reset completes outstanding TMs with a NULL
+	 * reply (mprsas_complete_all_commands); every other TM completion
+	 * handler guards this.  Without the guard we deref resp below and
+	 * panic.
+	 */
 	/*
 	 * Currently there should be no way we can hit this case.  It only
 	 * happens when we have a failure to allocate chain frames, and
 	 * task management commands don't have S/G lists.
 	 */
 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
@@ -3407,6 +3419,15 @@ mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm)
 		goto bailout;
 	}
 
+	if (resp == NULL) {
+		mpr_dprint(sc, MPR_RECOVERY,
+		    "NULL reset reply for tm %p\n", tm);
+		if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0)
+			mprsas_set_ccbstatus(ccb, CAM_SCSI_BUS_RESET);
+		else
+			mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
+		goto bailout;
+	}
+
 	mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n",
 	    __func__, le16toh(resp->IOCStatus), le32toh(resp->ResponseCode));