--- a/sys/dev/raid/mrsas/mrsas.c +++ b/sys/dev/raid/mrsas/mrsas.c @@ -1148,9 +1148,21 @@ mrsas_ioctl(struct dev_ioctl_args *ap) do_ioctl: switch (cmd) { - case MRSAS_IOC_FIRMWARE_PASS_THROUGH: - ret = mrsas_passthru(sc, (void *)arg); - break; + case MRSAS_IOC_FIRMWARE_PASS_THROUGH: { + struct mrsas_iocpacket ioc; + + /* + * Operate on a kernel copy of the ioctl packet. The raw + * userland pointer must never be dereferenced by the kernel: + * an unmapped/read-only argument faults the kernel, and every + * re-read of user_ioc->sge_count / sgl[] inside + * mrsas_passthru() is a validation->use race that walks past + * the MAX_IOCTL_SGE-sized stack arrays. + */ + ret = copyin(arg, &ioc, sizeof(ioc)); + if (ret != 0) + break; + ret = mrsas_passthru(sc, &ioc); + /* return the (possibly updated) frame header to userspace */ + copyout(&ioc, arg, sizeof(ioc)); + break; + } case MRSAS_IOC_SCAN_BUS: ret = mrsas_bus_scan(sc); break;