DragonFlyBSD Kernel Audit
DF-2831 / fixinst.diff
← back to finding ↓ download raw
--- subr_diskslice.c.orig
+++ subr_diskslice.c
@@ -769,6 +769,8 @@
 	ssp = *sspp;
 	dev->si_bsize_phys = info->d_media_blksize;
 	slice = dkslice(dev);
+	if (slice >= ssp->dss_nslices)
+		return (EINVAL);
 	part = dkpart(dev);
 	sp = &ssp->dss_slices[slice];
 	dssetmask(sp, part);
@@ -852,20 +854,33 @@
 		if (dev_dopen(dev, FREAD, S_IFCHR,
 			      proc0.p_ucred, NULL, NULL) != 0)
 		{
+			kprintf("DF2831 -1 openfail %s\n", devtoname(dev));
 			return (-1);
 		}
 		dev_dclose(dev, FREAD, S_IFCHR, NULL);
 		ssp = *sspp;
 	}
+	/*
+	 * The re-open above may have serialized with a reprobe; the
+	 * reloaded (or original) ssp must be revalidated before use.
+	 */
+	if (slice >= ssp->dss_nslices) {
+		kprintf("DF2831 -1 nslices %s slice=%d ns=%d\n",
+			devtoname(dev), slice, ssp->dss_nslices);
+		return (-1);
+	}
 	lp = ssp->dss_slices[slice].ds_label;
 	if (part == WHOLE_SLICE_PART) {
 		blocks = ssp->dss_slices[slice].ds_size;
 	} else if (lp.opaque == NULL) {
+		kprintf("DF2831 blocks=-1 nolabel %s\n", devtoname(dev));
 		blocks = (u_int64_t)-1;
 	} else {
 		ops = ssp->dss_slices[slice].ds_ops;
-		if (ops->op_getpartbounds(ssp, lp, part, &start, &blocks))
+		if (ops->op_getpartbounds(ssp, lp, part, &start, &blocks)) {
+			kprintf("DF2831 -1 bounds %s\n", devtoname(dev));
 			return (-1);
+		}
 	}
 	return ((int64_t)blocks);
 }
--- subr_disk.c.orig
+++ subr_disk.c
@@ -1265,10 +1265,23 @@
 	if (dp == NULL)
 		return(ENODEV);
 
+	/*
+	 * dssize() walks dp->d_slice (and the per-slice disklabel) with no
+	 * internal serialization while disk_probe()/disk_msg_core replace
+	 * and dsgone() those structures under ds_token (DF-2831).  Run the
+	 * whole walk under ds_token like diskopen/diskclose/diskioctl do.
+	 * Token acquisition is recursive for the dev_dopen() path inside
+	 * dssize() (diskopen takes ds_token itself), and blocking inside
+	 * the token (sync reprobe messages) releases/reacquires it.
+	 */
+	lwkt_gettoken(&ds_token);
 	ap->a_result = dssize(dev, &dp->d_slice);
+	lwkt_reltoken(&ds_token);
 
 	if ((ap->a_result == -1) &&
 	   (dp->d_info.d_dsflags & DSO_RAWPSIZE)) {
+		kprintf("DF2831 RAWPSIZE fallback %s -> raw whole-disk size\n",
+			devtoname(dev));
 		ap->a_head.a_dev = dp->d_rawdev;
 		return dev_doperate(&ap->a_head);
 	}