DragonFlyBSD Kernel Audit
DF-2262 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/bus/cam/cam_xpt.c b/sys/bus/cam/cam_xpt.c
--- a/sys/bus/cam/cam_xpt.c
+++ b/sys/bus/cam/cam_xpt.c
@@ -2435,17 +2435,33 @@
 	 * needs to reset everything and start over.
 	 */
 	if ((cdm->pos.position_type & CAM_DEV_POS_BUS)
-	 && (cdm->pos.generations[CAM_BUS_GENERATION] != 0)
-	 && (cdm->pos.generations[CAM_BUS_GENERATION] != xsoftc.bus_generation)) {
-		cdm->status = CAM_DEV_MATCH_LIST_CHANGED;
-		return(0);
-	}
-
-	if ((cdm->pos.position_type & CAM_DEV_POS_BUS)
-	 && (cdm->pos.cookie.bus != NULL))
+	 && (cdm->pos.cookie.bus != NULL)) {
+		/*
+		 * A non-NULL resume cookie is dereferenced verbatim by
+		 * xptbustraverse().  Refuse to honour it unless the caller also
+		 * supplied a current bus generation: the old test allowed a
+		 * malicious caller to bypass the generation check simply by
+		 * setting generations[CAM_BUS_GENERATION]=0 and then supply an
+		 * arbitrary kernel pointer as cookie.bus -> controlled-deref
+		 * panic / potential UAF.  (Full hardening would additionally
+		 * re-validate that cookie.bus names a live cam_eb; this closes
+		 * the trivial bypass.)
+		 */
+		if ((cdm->pos.generations[CAM_BUS_GENERATION] == 0)
+		 || (cdm->pos.generations[CAM_BUS_GENERATION] !=
+		      xsoftc.bus_generation)) {
+			cdm->status = CAM_DEV_MATCH_LIST_CHANGED;
+			return(0);
+		}
 		ret = xptbustraverse((struct cam_eb *)cdm->pos.cookie.bus,
 				     xptedtbusfunc, cdm);
-	else
+	} else if ((cdm->pos.position_type & CAM_DEV_POS_BUS)
+		&& (cdm->pos.generations[CAM_BUS_GENERATION] != 0)
+		&& (cdm->pos.generations[CAM_BUS_GENERATION] !=
+		    xsoftc.bus_generation)) {
+		cdm->status = CAM_DEV_MATCH_LIST_CHANGED;
+		return(0);
+	} else
 		ret = xptbustraverse(NULL, xptedtbusfunc, cdm);
 
 	/*