⬢ DragonFlyBSD Kernel Audit
DF-4363 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/raid/mps/mps_config.c b/sys/dev/raid/mps/mps_config.c
index 1111111..2222222 100644
--- a/sys/dev/raid/mps/mps_config.c
+++ b/sys/dev/raid/mps/mps_config.c
@@ -251,7 +251,18 @@ mps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply)
 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-	page = kmalloc(MPS_MAN_PAGE10_SIZE, M_MPT2, M_ZERO | M_INTWAIT);
+	/*
+	 * DF-4363: the IOC DMAs ExtPageLength/PageLength dwords into this
+	 * buffer (mps.c mps_map_command maps cm->cm_length bytes starting at
+	 * cm->cm_data). The buffer must be sized for cm->cm_length, not for
+	 * the fixed MPS_MAN_PAGE10_SIZE, or a firmware page header larger
+	 * than 0x5C walks the DMA past the allocation. Keep 0x5C as the
+	 * minimum so the ProductSpecificInfo[] derefs below stay in bounds.
+	 */
+	if (cm->cm_length < 0x1C) {
+		kprintf("%s: short man page 10 (%d bytes)\n", __func__,
+		    cm->cm_length);
+		error = EINVAL;
+		goto out;
+	}
+	page = kmalloc(MAX(cm->cm_length, MPS_MAN_PAGE10_SIZE), M_MPT2,
+	    M_ZERO | M_INTWAIT);
 	if (!page) {
 		kprintf("%s: page alloc failed\n", __func__);
 		error = ENOMEM;