DragonFlyBSD Kernel Audit
DF-1028 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/bus/cam/scsi/scsi_ch.c b/sys/bus/cam/scsi/scsi_ch.c
--- a/sys/bus/cam/scsi/scsi_ch.c
+++ b/sys/bus/cam/scsi/scsi_ch.c
@@ -1163,6 +1163,29 @@
 		    "warning, READ ELEMENT STATUS avail != count\n");
 	}
 
+	/*
+	 * Validate device-controlled lengths before using them.
+	 *
+	 * copy_element_status() reads a fixed
+	 * sizeof(struct read_element_status_descriptor) byte window out of
+	 * every descriptor slot, so a device that reports a shorter edl
+	 * would cause an OOB read past each slot (and, on the last slot,
+	 * past the data allocation).  Likewise, the response may legitimately
+	 * report more available elements than the user asked for; in that
+	 * case the original loop ran past `data`, copying OOB heap bytes
+	 * out to userspace.  Clamp avail to the user-supplied count and
+	 * reject obviously bogus descriptor lengths.
+	 */
+	if (desclen < sizeof(struct read_element_status_descriptor)) {
+		xpt_print(periph->path,
+		    "bogus READ ELEMENT STATUS descriptor length %zu\n",
+		    desclen);
+		error = EIO;
+		goto done;
+	}
+	if (avail > cesr->cesr_element_count)
+		avail = cesr->cesr_element_count;
+
 	user_data = (struct changer_element_status *)
 		kmalloc(avail * sizeof(struct changer_element_status),
 		       M_DEVBUF, M_INTWAIT | M_ZERO);