⬢ DragonFlyBSD Kernel Audit
DF-3833 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/disk/trm/trm.c
+++ b/sys/dev/disk/trm/trm.c
@@ -1336,8 +1336,16 @@
 
 	if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) {
 		pDCB = pACB->pActiveDCB;
-		KASSERT(pDCB != NULL, ("no active DCB"));
-		pSRB = pDCB->pActiveSRB;
+		/*
+		 * DF-3833: a stale completion can arrive after a bus
+		 * reset / disconnect cleared pActiveDCB (or pActiveSRB).
+		 * Drop it instead of dereferencing NULL.
+		 */
+		if (pDCB == NULL || (pSRB = pDCB->pActiveSRB) == NULL) {
+			trm_reg_write16(DO_CLRFIFO | DO_HWRESELECT,
+			    TRMREG_SCSI_CONTROL);
+			return;
+		}
 		if (pDCB->DCBFlag & ABORT_DEV_)
 				trm_EnableMsgOutAbort1(pACB, pSRB);
 		phase = (u_int16_t) pSRB->ScsiPhase;  /* phase: */
@@ -2719,17 +2727,21 @@
 		pDCB->pGoingSRB = pSRB->pNextSRB;
 	else {
 		psrb = pDCB->pGoingSRB;
-		while (psrb->pNextSRB != pSRB) {
+		while (psrb != NULL && psrb->pNextSRB != pSRB) {
 			psrb = psrb->pNextSRB;
 		}
+		if (psrb == NULL)	/* DF-3833: not on the going list */
+			goto skip_unlink;
 		psrb->pNextSRB = pSRB->pNextSRB;
 		if (pSRB == pDCB->pGoingLastSRB) {
 			pDCB->pGoingLastSRB = psrb;
 		}
 	}
+skip_unlink:
 	pSRB->pNextSRB = pACB->pFreeSRB;
 	pACB->pFreeSRB = pSRB;
-	pDCB->GoingSRBCnt--;
+	if (pDCB->GoingSRBCnt)
+		pDCB->GoingSRBCnt--;
 	trm_DoWaitingSRB(pACB);
 
 	crit_exit();