diff --git a/sys/dev/raid/mpr/mpr_user.c b/sys/dev/raid/mpr/mpr_user.c --- a/sys/dev/raid/mpr/mpr_user.c +++ b/sys/dev/raid/mpr/mpr_user.c @@ -806,6 +806,22 @@ goto RetFreeUnlocked; } + /* + * Cap the user-supplied data sizes to the controller's max I/O. + * Without this, mpr_build_nvme_prp() would be driven past its single + * allocated PRP-list page (one PAGE_SIZE buffer per command, holding + * PAGE_SIZE/8 entries) and write PRP entries off the end of that + * buffer, overflowing the kernel heap with attacker-controlled + * physical addresses. + */ + if (data->DataSize > sc->maxio || data->DataOutSize > sc->maxio) { + mpr_dprint(sc, MPR_FAULT, "%s: data size too large " + "(in %d out %d > maxio %u)\n", __func__, data->DataSize, + data->DataOutSize, sc->maxio); + err = EINVAL; + goto RetFreeUnlocked; + } + function = tmphdr.Function; mpr_dprint(sc, MPR_USER, "%s: Function %02X MsgFlags %02X\n", __func__, function, tmphdr.MsgFlags);