⬢ DragonFlyBSD Kernel Audit
DF-3800 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/raid/mpr/mpr_sas.c b/sys/dev/raid/mpr/mpr_sas.c
index 1111111..2222222 100644
--- a/sys/dev/raid/mpr/mpr_sas.c
+++ b/sys/dev/raid/mpr/mpr_sas.c
@@ -3908,14 +3908,25 @@ mprsas_check_id(struct mprsas_softc *sassc, int id)
 void
 mprsas_realloc_targets(struct mpr_softc *sc, int maxtargets)
 {
 	struct mprsas_softc *sassc;
 	struct mprsas_lun *lun, *lun_tmp;
 	struct mprsas_target *targ;
-	int i;
+	int i;
+
+	/*
+	 * DF-3800: the targets array must track the *current* IOC facts.
+	 * Callers previously passed the pre-reset ("saved") facts while the
+	 * mapping layer was rebuilt from the new facts, so mapping-derived
+	 * target ids could index past the array (heap OOB write) and, in the
+	 * opposite direction, CAM target ids could index past the shrunken
+	 * mapping_table.
+	 */
+	maxtargets = sc->facts->MaxTargets + sc->facts->MaxVolumes;
 
 	sassc = sc->sassc;
 	/*
 	 * The number of targets is based on IOC Facts, so free all of
 	 * the allocated LUNs for each target and then the target buffer
 	 * itself.
 	 */
-	for (i=0; i< maxtargets; i++) {
+	for (i = 0; i < sassc->maxtargets; i++) {
 		targ = &sassc->targets[i];
 		SLIST_FOREACH_MUTABLE(lun, &targ->luns, lun_link, lun_tmp) {
 			kfree(lun, M_MPR);
 		}
@@ -3930,9 +3941,11 @@ mprsas_realloc_targets(struct mpr_softc *sc, int maxtargets)
 
 	sassc->targets = kmalloc(sizeof(struct mprsas_target) * maxtargets,
 	    M_MPR, M_WAITOK|M_ZERO);
 	if (!sassc->targets) {
 		panic("%s failed to alloc targets with error %d\n",
 		    __func__, ENOMEM);
 	}
+	sassc->maxtargets = maxtargets;
 }
diff --git a/sys/dev/raid/mpr/mpr.c b/sys/dev/raid/mpr/mpr.c
index 3333333..4444444 100644
--- a/sys/dev/raid/mpr/mpr.c
+++ b/sys/dev/raid/mpr/mpr.c
@@ -629,8 +629,9 @@ mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching)
 	 */
 	if (reallocating) {
 		mpr_iocfacts_free(sc);
-		mprsas_realloc_targets(sc, saved_facts.MaxTargets +
-		    saved_facts.MaxVolumes);
+		/* DF-3800: resize to the CURRENT facts; the helper also
+		 * updates sassc->maxtargets. */
+		mprsas_realloc_targets(sc, sc->facts->MaxTargets +
+		    sc->facts->MaxVolumes);
 	}
diff --git a/sys/dev/raid/mpr/mpr_sas_lsi.c b/sys/dev/raid/mpr/mpr_sas_lsi.c
index 5555555..6666666 100644
--- a/sys/dev/raid/mpr/mpr_sas_lsi.c
+++ b/sys/dev/raid/mpr/mpr_sas_lsi.c
@@ -905,6 +905,12 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u16 flag)
 			goto out;
 		}
 	}
+	/* DF-3800 defense-in-depth: mapping ids must honor the target array. */
+	if (id >= sassc->maxtargets) {
+		mpr_dprint(sc, MPR_ERROR, "mapping id %d exceeds maxtargets %d\n",
+		    id, sassc->maxtargets);
+		error = ENXIO;
+		goto out;
+	}
 	mpr_dprint(sc, MPR_MAPPING, "%s: Target ID for added device is %d.\n",
 	    __func__, id);