⬢ DragonFlyBSD Kernel Audit
DF-4013 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/raid/mps/mps_user.c b/sys/dev/raid/mps/mps_user.c
--- a/sys/dev/raid/mps/mps_user.c	2026-09-17 14:20:44.382606971 +0000
+++ b/sys/dev/raid/mps/mps_user.c	2026-09-17 14:20:44.398606765 +0000
@@ -1373,6 +1373,22 @@
 		*return_code = MPS_FW_DIAG_ERROR_NO_BUFFER;
 		return (MPS_DIAG_FAILURE);
 	}
+
+	/*
+	 * DF-4013: the driver owns exactly ONE shared DMA trio
+	 * (fw_diag_dmat/fw_diag_buffer/fw_diag_map/fw_diag_busaddr) for
+	 * all three buffer types.  Registering a second type while a trio
+	 * is live used to silently replace the pointers (leaking the old
+	 * allocation) while the first type kept its per-type size, so
+	 * later reads were bounds-checked against a stale size and ran off
+	 * the new allocation.  Refuse the second registration (the
+	 * immediate-takeover path above remains the only legal re-use).
+	 */
+	if (sc->fw_diag_buffer != NULL) {
+		*return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
+		return (MPS_DIAG_FAILURE);
+	}
+
         if (bus_dma_tag_create( sc->mps_parent_dmat,    /* parent */
 				1, 0,			/* algnmnt, boundary */
 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
@@ -1424,6 +1440,15 @@
 			    sc->fw_diag_map);
 		if (sc->fw_diag_dmat != NULL)
 			bus_dma_tag_destroy(sc->fw_diag_dmat);
+		/*
+		 * DF-4013: pBuffer stays registered (unique_id/size) when
+		 * the post fails; never leave the freed trio dangling.
+		 */
+		sc->fw_diag_buffer = NULL;
+		sc->fw_diag_dmat = NULL;
+		sc->fw_diag_map = NULL;
+		sc->fw_diag_busaddr = 0;
+		pBuffer->size = 0;
 	}
 
 	return (status);
@@ -1477,6 +1502,15 @@
 			    sc->fw_diag_map);
 		if (sc->fw_diag_dmat != NULL)
 			bus_dma_tag_destroy(sc->fw_diag_dmat);
+		/*
+		 * DF-4013: with the one-trio invariant above this free is
+		 * the right one; NULL the trio so a later read or a second
+		 * unregister cannot touch freed memory (UAF/double-free).
+		 */
+		sc->fw_diag_buffer = NULL;
+		sc->fw_diag_dmat = NULL;
+		sc->fw_diag_map = NULL;
+		sc->fw_diag_busaddr = 0;
 	}
 
 	return (status);
@@ -1578,6 +1612,14 @@
 	pBuffer = &sc->fw_diag_buffer_list[i];
 
 	/*
+	 * DF-4013: never copy out through a freed/absent shared trio.
+	 */
+	if (sc->fw_diag_buffer == NULL) {
+		*return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
+		return (MPS_DIAG_FAILURE);
+	}
+
+	/*
 	 * Make sure requested read is within limits
 	 */
 	if (diag_read_buffer->StartingOffset + diag_read_buffer->BytesToRead >