⬢ DragonFlyBSD Kernel Audit
DF-2267 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/cam/cam_periph.c	2026-10-21 04:28:14.594687408 +0000
+++ b/sys/bus/cam/cam_periph.c	2026-10-21 04:28:14.594687408 +0000
@@ -1,20 +1,50 @@
-		while (found == 0) {
-			ccb->cgdl.index = 0;
-			ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS;
-			while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) {
+		/*
+		 * DF-2267: the outer loop previously only exited on
+		 * CAM_GDEVLIST_LAST_DEVICE or a pass match; ERROR or
+		 * LIST_CHANGED from every xpt_action span it forever while
+		 * the caller held the SIM lock.  Bound the restarts and
+		 * terminate on error.
+		 */
+		{
+			int df_restarts = 0;
 
-				/* we want the next device in the list */
-				xpt_action(ccb);
-				if (strncmp(ccb->cgdl.periph_name, 
-				    "pass", 4) == 0){
-					found = 1;
+			while (found == 0) {
+				if (++df_restarts > 100) {
+					ccb->cgdl.periph_name[0] = '\0';
+					ccb->cgdl.unit_number = 0;
+					ccb->cgdl.status =
+					    CAM_GDEVLIST_ERROR;
+					break;
+				}
+				ccb->cgdl.index = 0;
+				ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS;
+				while (ccb->cgdl.status ==
+				    CAM_GDEVLIST_MORE_DEVS) {
+
+					/* we want the next device in the list */
+					xpt_action(ccb);
+					if (strncmp(ccb->cgdl.periph_name,
+					    "pass", 4) == 0){
+						found = 1;
+						break;
+					}
+					if (ccb->cgdl.status ==
+					    CAM_GDEVLIST_ERROR) {
+						ccb->cgdl.periph_name[0] = '\0';
+						ccb->cgdl.unit_number = 0;
+						found = -1;	/* give up */
+						break;
+					}
+				}
+				if (found != 0)
+					break;
+				if ((ccb->cgdl.status ==
+				     CAM_GDEVLIST_LAST_DEVICE)) {
+					ccb->cgdl.periph_name[0] = '\0';
+					ccb->cgdl.unit_number = 0;
 					break;
 				}
 			}
-			if ((ccb->cgdl.status == CAM_GDEVLIST_LAST_DEVICE) &&
-			    (found == 0)) {
-				ccb->cgdl.periph_name[0] = '\0';
-				ccb->cgdl.unit_number = 0;
-				break;
-			}
+			if (found == -1)
+				found = 0;
 		}
\ No newline at end of file