⬢ DragonFlyBSD Kernel Audit
DF-4868 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/mps/mps_table.c
+++ b/sys/dev/raid/mps/mps_table.c
@@ -446,16 +446,24 @@ mps_print_sasphy0(struct mps_softc *sc, MPI2_CONFIG_PAGE_SAS_PHY_0 *buf)
 void
 mps_print_sgl(struct mps_softc *sc, struct mps_command *cm, int offset)
 {
 	MPI2_SGE_SIMPLE64 *sge;
 	MPI2_SGE_CHAIN32 *sgc;
 	struct mps_chain *chain = NULL;
 	char *frame;
 	u_int i = 0, flags;
+	u_int seg = 0;
+	int framewords = sc->facts->IOCRequestFrameSize;
+
+	if (offset < 0 || offset >= framewords)
+		return;
 
 	frame = (char *)cm->cm_req;
 	sge = (MPI2_SGE_SIMPLE64 *)&frame[offset * 4];
 	kprintf("SGL for command %p\n", cm);
 
-	hexdump(frame, 128, NULL, 0);
+	hexdump(frame, imin(framewords * 4, 128), NULL, 0);
 	while (frame != NULL) {
 		flags = le32toh(sge->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT;
 		kprintf("seg%d flags=0x%02x len=0x%06x addr=0x%016jx\n",
@@ -468,15 +476,26 @@ mps_print_sgl(struct mps_softc *sc, struct mps_command *cm, int offset)
 		    MPI2_SGE_FLAGS_END_OF_BUFFER))
 			break;
 		sge++;
 		i++;
+		/* IOCRequestFrameSize is in dwords; a SIMPLE64 SGE is 4 dwords */
+		if (++seg >= (u_int)(framewords / 4)) {
+			kprintf("%s: SGL walk exceeded frame bounds\n", __func__);
+			break;
+		}
 		if (flags & MPI2_SGE_FLAGS_LAST_ELEMENT) {
 			sgc = (MPI2_SGE_CHAIN32 *)sge;
 			kprintf("chain flags=0x%x len=0x%x Offset=0x%x "
 				"Address=0x%x\n", sgc->Flags, le16toh(sgc->Length),
 				sgc->NextChainOffset, le32toh(sgc->Address));
 			if (chain == NULL)
 				chain = TAILQ_FIRST(&cm->cm_chain_list);
 			else
 				chain = TAILQ_NEXT(chain, chain_link);
+			if (chain == NULL) {
+				kprintf("%s: chain list exhausted\n", __func__);
+				break;
+			}
 			frame = (char *)chain->chain;
 			sge = (MPI2_SGE_SIMPLE64 *)frame;
-			hexdump(frame, 128, NULL, 0);
+			seg = 0;
+			hexdump(frame, imin(framewords * 4, 128), NULL, 0);
 		}
 	}
 }