DF-2511 / fix.diff
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]; |