scsi: aacraid: Improve compat_ioctl handlers
authorArnd Bergmann <arnd@arndb.de>
Fri, 30 Oct 2020 16:44:19 +0000 (17:44 +0100)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 5 Nov 2020 02:54:11 +0000 (21:54 -0500)
The use of compat_alloc_user_space() can be easily replaced by handling
compat arguments in the regular handler, and this will make it work for
big-endian kernels as well, which at the moment get an invalid indirect
pointer argument.

Calling aac_ioctl() instead of aac_compat_do_ioctl() means the compat and
native code paths behave the same way again, which they stopped when the
adapter health check was added only in the native function.

Link: https://lore.kernel.org/r/20201030164450.1253641-1-arnd@kernel.org
Fixes: 572ee53a9bad ("scsi: aacraid: check adapter health")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/aacraid/commctrl.c
drivers/scsi/aacraid/linit.c

index e3e157a..1b1da16 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/completion.h>
 #include <linux/dma-mapping.h>
 #include <linux/blkdev.h>
+#include <linux/compat.h>
 #include <linux/delay.h> /* ssleep prototype */
 #include <linux/kthread.h>
 #include <linux/uaccess.h>
@@ -226,6 +227,12 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
        return status;
 }
 
+struct compat_fib_ioctl {
+       u32     fibctx;
+       s32     wait;
+       compat_uptr_t fib;
+};
+
 /**
  *     next_getadapter_fib     -       get the next fib
  *     @dev: adapter to use
@@ -243,8 +250,19 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
        struct list_head * entry;
        unsigned long flags;
 
-       if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
-               return -EFAULT;
+       if (in_compat_syscall()) {
+               struct compat_fib_ioctl cf;
+
+               if (copy_from_user(&cf, arg, sizeof(struct compat_fib_ioctl)))
+                       return -EFAULT;
+
+               f.fibctx = cf.fibctx;
+               f.wait = cf.wait;
+               f.fib = compat_ptr(cf.fib);
+       } else {
+               if (copy_from_user(&f, arg, sizeof(struct fib_ioctl)))
+                       return -EFAULT;
+       }
        /*
         *      Verify that the HANDLE passed in was a valid AdapterFibContext
         *
index 8f37724..0a82afa 100644 (file)
@@ -1182,63 +1182,6 @@ static long aac_cfg_ioctl(struct file *file,
        return aac_do_ioctl(aac, cmd, (void __user *)arg);
 }
 
-#ifdef CONFIG_COMPAT
-static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long arg)
-{
-       long ret;
-       switch (cmd) {
-       case FSACTL_MINIPORT_REV_CHECK:
-       case FSACTL_SENDFIB:
-       case FSACTL_OPEN_GET_ADAPTER_FIB:
-       case FSACTL_CLOSE_GET_ADAPTER_FIB:
-       case FSACTL_SEND_RAW_SRB:
-       case FSACTL_GET_PCI_INFO:
-       case FSACTL_QUERY_DISK:
-       case FSACTL_DELETE_DISK:
-       case FSACTL_FORCE_DELETE_DISK:
-       case FSACTL_GET_CONTAINERS:
-       case FSACTL_SEND_LARGE_FIB:
-               ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
-               break;
-
-       case FSACTL_GET_NEXT_ADAPTER_FIB: {
-               struct fib_ioctl __user *f;
-
-               f = compat_alloc_user_space(sizeof(*f));
-               ret = 0;
-               if (clear_user(f, sizeof(*f)))
-                       ret = -EFAULT;
-               if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32)))
-                       ret = -EFAULT;
-               if (!ret)
-                       ret = aac_do_ioctl(dev, cmd, f);
-               break;
-       }
-
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
-       return ret;
-}
-
-static int aac_compat_ioctl(struct scsi_device *sdev, unsigned int cmd,
-                           void __user *arg)
-{
-       struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
-       if (!capable(CAP_SYS_RAWIO))
-               return -EPERM;
-       return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg);
-}
-
-static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long arg)
-{
-       if (!capable(CAP_SYS_RAWIO))
-               return -EPERM;
-       return aac_compat_do_ioctl(file->private_data, cmd, arg);
-}
-#endif
-
 static ssize_t aac_show_model(struct device *device,
                              struct device_attribute *attr, char *buf)
 {
@@ -1523,7 +1466,7 @@ static const struct file_operations aac_cfg_fops = {
        .owner          = THIS_MODULE,
        .unlocked_ioctl = aac_cfg_ioctl,
 #ifdef CONFIG_COMPAT
-       .compat_ioctl   = aac_compat_cfg_ioctl,
+       .compat_ioctl   = aac_cfg_ioctl,
 #endif
        .open           = aac_cfg_open,
        .llseek         = noop_llseek,
@@ -1536,7 +1479,7 @@ static struct scsi_host_template aac_driver_template = {
        .info                           = aac_info,
        .ioctl                          = aac_ioctl,
 #ifdef CONFIG_COMPAT
-       .compat_ioctl                   = aac_compat_ioctl,
+       .compat_ioctl                   = aac_ioctl,
 #endif
        .queuecommand                   = aac_queuecommand,
        .bios_param                     = aac_biosparm,