DragonFlyBSD Kernel Audit
DF-2274 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/bus/cam/scsi/scsi_da.c b/sys/bus/cam/scsi/scsi_da.c
--- a/sys/bus/cam/scsi/scsi_da.c
+++ b/sys/bus/cam/scsi/scsi_da.c
@@ -353,7 +353,7 @@
 static void		daprevent(struct cam_periph *periph, int action);
 static int		dagetcapacity(struct cam_periph *periph, int ccbflags);
 static int		dacheckmedia(struct cam_periph *periph);
-static void		dasetgeom(struct cam_periph *periph, uint32_t block_len,
+static int		dasetgeom(struct cam_periph *periph, uint32_t block_len,
 				  uint64_t maxsector);
 static void		daflushbioq(struct bio_queue_head *bioq, int error);
 static void		dashutdown(void *arg, int howto);
@@ -2276,7 +2276,7 @@
 	return (error);
 }
 
-static void
+static int
 dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector)
 {
 	struct ccb_calc_geometry *ccg;
@@ -2285,6 +2285,17 @@
 
 	softc = (struct da_softc *)periph->softc;
 
+	/*
+	 * A block size of zero from READ CAPACITY is nonsensical and would
+	 * cause divide-by-zero traps everywhere the driver (and every SIM's
+	 * XPT_CALC_GEOMETRY handler) divide by secsize.  Reject it rather
+	 * than caching a value that crashes the kernel on the next I/O.
+	 */
+	if (block_len == 0) {
+		xpt_print(periph->path, "READ CAPACITY returned 0 block size\n");
+		return (EINVAL);
+	}
+
 	dp = &softc->params;
 	dp->secsize = block_len;
 	dp->sectors = maxsector + 1;
@@ -2323,6 +2334,8 @@
 		dp->cylinders = ccg->cylinders;
 	}
 	xpt_free_ccb(&ccg->ccb_h);
+
+	return (0);
 }
 
 /*