scsi: aacraid: Improve compat_ioctl handlers

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: 572ee53a9b ("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>
This commit is contained in:
Arnd Bergmann 2020-10-30 17:44:19 +01:00 committed by Martin K. Petersen
parent 2030745877
commit 077054215a
2 changed files with 22 additions and 61 deletions

View 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)))
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
*

View 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,