DragonFlyBSD Kernel Audit
DF-2511 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/disk/nvme/nvme.c b/sys/dev/disk/nvme/nvme.c
--- a/sys/dev/disk/nvme/nvme.c
+++ b/sys/dev/disk/nvme/nvme.c
@@ -709,8 +709,25 @@
 		 * request could be on a different queue.  A submission
 		 * queue can have only one completion queue, so we can
 		 * update subq_head without locking the submission queue.
+		 *
+		 * The controller (or a malicious/faulty PCIe device) supplies
+		 * subq_id and cmd_id in the DMA completion entry; both are 16-bit
+		 * and index fixed arrays (subqueues[NVME_MAX_QUEUES=1024] and
+		 * subq->reqary[nqe<=256]).  Validate them; the KKASSERT below is
+		 * compiled out of production/release kernels.  See DF-2511.
 		 */
+		if (res->tail.subq_id >= NVME_MAX_QUEUES) {
+			device_printf(sc->dev,
+			    "bad completion subq_id %u\n", res->tail.subq_id);
+			break;
+		}
 		subq = &sc->subqueues[res->tail.subq_id];
+		if (subq->nqe == 0 || res->tail.cmd_id >= subq->nqe) {
+			device_printf(sc->dev,
+			    "bad completion cmd_id %u (subq %u nqe %u)\n",
+			    res->tail.cmd_id, res->tail.subq_id, subq->nqe);
+			break;
+		}
 		subq->subq_head = res->tail.subq_head_ptr;
 		req = &subq->reqary[res->tail.cmd_id];