diff --git a/sys/dev/raid/mrsas/mrsas_ioctl.c b/sys/dev/raid/mrsas/mrsas_ioctl.c --- a/sys/dev/raid/mrsas/mrsas_ioctl.c +++ b/sys/dev/raid/mrsas/mrsas_ioctl.c @@ -216,6 +216,25 @@ * kernel buffers in SGLs. The location of SGL is embedded in the * struct iocpacket itself. */ + /* + * DF-1917: user_ioc->sgl_off is an attacker-controlled u32 from + * userspace (mrsas_ioctl.h:83) and was previously used verbatim as + * the in-frame offset at which up to MAX_IOCTL_SGE (=16) 8-byte SGE + * entries are written (mrsas_ioctl.c:225-255). With no validation + * the writes could land past the 1024-byte cmd->frame DMA allocation + * (MRSAS_MFI_FRAME_SIZE). Reject any sgl_off that would push the + * last SGE byte (sgl_off + sge_count*sizeof(mrsas_sge32)) past the + * end of the frame. + */ + if (user_ioc->sgl_off > MRSAS_MFI_FRAME_SIZE || + (uint64_t)user_ioc->sgl_off + + (uint64_t)user_ioc->sge_count * sizeof(struct mrsas_sge32) > + (uint64_t)MRSAS_MFI_FRAME_SIZE) { + device_printf(sc->mrsas_dev, + "In %s() sgl_off=0x%x sge_count=%u overflows frame\n", + __func__, user_ioc->sgl_off, user_ioc->sge_count); + return (EINVAL); + } kern_sge32 = (struct mrsas_sge32 *) ((unsigned long)cmd->frame + user_ioc->sgl_off);