⬢ DragonFlyBSD Kernel Audit
DF-3985 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/disk/sbp/sbp.c
+++ b/sys/dev/disk/sbp/sbp.c
@@ -1982,6 +1982,9 @@
 
 	if (sdev == NULL)
 		return;
+	/* login_callout is armed by sbp_login(); it must never be left
+	 * pending when the sdev is freed (DF-3981 use-after-free). */
+	callout_stop(&sdev->login_callout);
 	for (i = 0; i < SBP_QUEUE_LEN; i++)
 		bus_dmamap_destroy(sdev->target->sbp->dmat,
 		    sdev->ocb[i].dmamap);
@@ -1995,21 +1998,24 @@
 	struct fw_xfer *xfer, *next;
 	int i;
 
-	if (target->luns == NULL)
-		return;
+	/* also reached for luns == NULL: release the target slot (DF-3985)
+	 * and stop both callouts so nothing dangles */
+	callout_stop(&target->scan_callout);
 	callout_stop(&target->mgm_ocb_timeout);
-	for (i = 0; i < target->num_lun; i++)
-		sbp_free_sdev(target->luns[i]);
+	if (target->luns != NULL) {
+		for (i = 0; i < target->num_lun; i++)
+			sbp_free_sdev(target->luns[i]);
 
-	for (xfer = STAILQ_FIRST(&target->xferlist);
-			xfer != NULL; xfer = next) {
-		next = STAILQ_NEXT(xfer, link);
-		fw_xfer_free_buf(xfer);
+		for (xfer = STAILQ_FIRST(&target->xferlist);
+				xfer != NULL; xfer = next) {
+			next = STAILQ_NEXT(xfer, link);
+			fw_xfer_free_buf(xfer);
+		}
+		STAILQ_INIT(&target->xferlist);
+		kfree(target->luns, M_SBP);
+		target->num_lun = 0;
+		target->luns = NULL;
 	}
-	STAILQ_INIT(&target->xferlist);
-	kfree(target->luns, M_SBP);
-	target->num_lun = 0;
-	target->luns = NULL;
 	target->fwdev = NULL;
 }