⬢ DragonFlyBSD Kernel Audit
DF-4834 / fix.diff
← back to finding ↓ download raw
--- 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;