⬢ DragonFlyBSD Kernel Audit
DF-4789 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/mpr/mpr_table.c
+++ b/sys/dev/raid/mpr/mpr_table.c
@@ -537,7 +537,8 @@ mpr_print_sgl(struct mpr_softc *sc, struct mpr_command *cm, int offset)
 	MPI2_SGE_SIMPLE64 *sge;
 	MPI2_REQUEST_HEADER *req;
 	struct mpr_chain *chain = NULL;
 	char *frame;
 	u_int i = 0, flags, length;
+	u_int seg = 0;
 
 	req = (MPI2_REQUEST_HEADER *)cm->cm_req;
 	frame = (char *)cm->cm_req;
@@ -545,6 +546,7 @@ mpr_print_sgl(struct mpr_softc *sc, struct mpr_command *cm, int offset)
 	sge = (MPI2_SGE_SIMPLE64 *)&frame[offset * 4];
 	kprintf("SGL for command %p\n", cm);
 
 	hexdump(frame, 128, NULL, 0);
+	seg = 0;
 	while ((frame != NULL) && (!(cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE))) {
 		flags = ieee_sge->Flags;
 		length = le32toh(ieee_sge->Length);
@@ -553,14 +555,22 @@ mpr_print_sgl(struct mpr_softc *sc, struct mpr_command *cm, int offset)
 		if (flags & MPI25_IEEE_SGE_FLAGS_END_OF_LIST)
 			break;
 		ieee_sge++;
 		i++;
+		/* a frame is at most 128 bytes = 8 16-byte SGEs; 32 is a hard stop */
+		if (++seg >= 32) {
+			kprintf("%s: SGL walk exceeded frame bounds\n", __func__);
+			break;
+		}
 		if (flags & MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT) {
 			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;
 			ieee_sge = (MPI2_IEEE_SGE_SIMPLE64 *)frame;
+			seg = 0;
 			hexdump(frame, 128, NULL, 0);
 		}
 	}
@@ -573,6 +583,10 @@ mpr_print_sgl(struct mpr_softc *sc, struct mpr_command *cm, int offset)
 			MPI2_SGE_FLAGS_END_OF_BUFFER))
 			break;
 		sge++;
 		i++;
+		if (i >= 32) {
+			kprintf("%s: SGL walk exceeded frame bounds\n", __func__);
+			break;
+		}
 	}
 }