forked from Minki/linux
scsi: hpsa: Lift {BIG_,}IOCTL_Command_struct copy{in,out} into hpsa_ioctl()
Link: https://lore.kernel.org/r/20200529234028.46373-1-viro@ZenIV.linux.org.uk Acked-by: Don Brace <don.brace@microsemi.com> Tested-by: Don Brace <don.brace@microsemi.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
7b6668d8b8
commit
138125f74b
@ -6358,37 +6358,33 @@ static int hpsa_getdrivver_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
static int hpsa_passthru_ioctl(struct ctlr_info *h,
|
||||
IOCTL_Command_struct *iocommand)
|
||||
{
|
||||
IOCTL_Command_struct iocommand;
|
||||
struct CommandList *c;
|
||||
char *buff = NULL;
|
||||
u64 temp64;
|
||||
int rc = 0;
|
||||
|
||||
if (!argp)
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_RAWIO))
|
||||
return -EPERM;
|
||||
if (copy_from_user(&iocommand, argp, sizeof(iocommand)))
|
||||
return -EFAULT;
|
||||
if ((iocommand.buf_size < 1) &&
|
||||
(iocommand.Request.Type.Direction != XFER_NONE)) {
|
||||
if ((iocommand->buf_size < 1) &&
|
||||
(iocommand->Request.Type.Direction != XFER_NONE)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (iocommand.buf_size > 0) {
|
||||
buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
|
||||
if (iocommand->buf_size > 0) {
|
||||
buff = kmalloc(iocommand->buf_size, GFP_KERNEL);
|
||||
if (buff == NULL)
|
||||
return -ENOMEM;
|
||||
if (iocommand.Request.Type.Direction & XFER_WRITE) {
|
||||
if (iocommand->Request.Type.Direction & XFER_WRITE) {
|
||||
/* Copy the data into the buffer we created */
|
||||
if (copy_from_user(buff, iocommand.buf,
|
||||
iocommand.buf_size)) {
|
||||
if (copy_from_user(buff, iocommand->buf,
|
||||
iocommand->buf_size)) {
|
||||
rc = -EFAULT;
|
||||
goto out_kfree;
|
||||
}
|
||||
} else {
|
||||
memset(buff, 0, iocommand.buf_size);
|
||||
memset(buff, 0, iocommand->buf_size);
|
||||
}
|
||||
}
|
||||
c = cmd_alloc(h);
|
||||
@ -6398,23 +6394,23 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
c->scsi_cmd = SCSI_CMD_BUSY;
|
||||
/* Fill in Command Header */
|
||||
c->Header.ReplyQueue = 0; /* unused in simple mode */
|
||||
if (iocommand.buf_size > 0) { /* buffer to fill */
|
||||
if (iocommand->buf_size > 0) { /* buffer to fill */
|
||||
c->Header.SGList = 1;
|
||||
c->Header.SGTotal = cpu_to_le16(1);
|
||||
} else { /* no buffers to fill */
|
||||
c->Header.SGList = 0;
|
||||
c->Header.SGTotal = cpu_to_le16(0);
|
||||
}
|
||||
memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN));
|
||||
memcpy(&c->Header.LUN, &iocommand->LUN_info, sizeof(c->Header.LUN));
|
||||
|
||||
/* Fill in Request block */
|
||||
memcpy(&c->Request, &iocommand.Request,
|
||||
memcpy(&c->Request, &iocommand->Request,
|
||||
sizeof(c->Request));
|
||||
|
||||
/* Fill in the scatter gather information */
|
||||
if (iocommand.buf_size > 0) {
|
||||
if (iocommand->buf_size > 0) {
|
||||
temp64 = dma_map_single(&h->pdev->dev, buff,
|
||||
iocommand.buf_size, DMA_BIDIRECTIONAL);
|
||||
iocommand->buf_size, DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(&h->pdev->dev, (dma_addr_t) temp64)) {
|
||||
c->SG[0].Addr = cpu_to_le64(0);
|
||||
c->SG[0].Len = cpu_to_le32(0);
|
||||
@ -6422,12 +6418,12 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
goto out;
|
||||
}
|
||||
c->SG[0].Addr = cpu_to_le64(temp64);
|
||||
c->SG[0].Len = cpu_to_le32(iocommand.buf_size);
|
||||
c->SG[0].Len = cpu_to_le32(iocommand->buf_size);
|
||||
c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */
|
||||
}
|
||||
rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
|
||||
NO_TIMEOUT);
|
||||
if (iocommand.buf_size > 0)
|
||||
if (iocommand->buf_size > 0)
|
||||
hpsa_pci_unmap(h->pdev, c, 1, DMA_BIDIRECTIONAL);
|
||||
check_ioctl_unit_attention(h, c);
|
||||
if (rc) {
|
||||
@ -6436,16 +6432,12 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
}
|
||||
|
||||
/* Copy the error information out */
|
||||
memcpy(&iocommand.error_info, c->err_info,
|
||||
sizeof(iocommand.error_info));
|
||||
if (copy_to_user(argp, &iocommand, sizeof(iocommand))) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if ((iocommand.Request.Type.Direction & XFER_READ) &&
|
||||
iocommand.buf_size > 0) {
|
||||
memcpy(&iocommand->error_info, c->err_info,
|
||||
sizeof(iocommand->error_info));
|
||||
if ((iocommand->Request.Type.Direction & XFER_READ) &&
|
||||
iocommand->buf_size > 0) {
|
||||
/* Copy the data out of the buffer we created */
|
||||
if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) {
|
||||
if (copy_to_user(iocommand->buf, buff, iocommand->buf_size)) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
@ -6457,9 +6449,9 @@ out_kfree:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
static int hpsa_big_passthru_ioctl(struct ctlr_info *h,
|
||||
BIG_IOCTL_Command_struct *ioc)
|
||||
{
|
||||
BIG_IOCTL_Command_struct *ioc;
|
||||
struct CommandList *c;
|
||||
unsigned char **buff = NULL;
|
||||
int *buff_size = NULL;
|
||||
@ -6470,29 +6462,17 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
u32 sz;
|
||||
BYTE __user *data_ptr;
|
||||
|
||||
if (!argp)
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_RAWIO))
|
||||
return -EPERM;
|
||||
ioc = vmemdup_user(argp, sizeof(*ioc));
|
||||
if (IS_ERR(ioc)) {
|
||||
status = PTR_ERR(ioc);
|
||||
goto cleanup1;
|
||||
}
|
||||
|
||||
if ((ioc->buf_size < 1) &&
|
||||
(ioc->Request.Type.Direction != XFER_NONE)) {
|
||||
status = -EINVAL;
|
||||
goto cleanup1;
|
||||
}
|
||||
(ioc->Request.Type.Direction != XFER_NONE))
|
||||
return -EINVAL;
|
||||
/* Check kmalloc limits using all SGs */
|
||||
if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
|
||||
status = -EINVAL;
|
||||
goto cleanup1;
|
||||
}
|
||||
if (ioc->buf_size > ioc->malloc_size * SG_ENTRIES_IN_CMD) {
|
||||
status = -EINVAL;
|
||||
goto cleanup1;
|
||||
}
|
||||
if (ioc->malloc_size > MAX_KMALLOC_SIZE)
|
||||
return -EINVAL;
|
||||
if (ioc->buf_size > ioc->malloc_size * SG_ENTRIES_IN_CMD)
|
||||
return -EINVAL;
|
||||
buff = kcalloc(SG_ENTRIES_IN_CMD, sizeof(char *), GFP_KERNEL);
|
||||
if (!buff) {
|
||||
status = -ENOMEM;
|
||||
@ -6565,10 +6545,6 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
|
||||
/* Copy the error information out */
|
||||
memcpy(&ioc->error_info, c->err_info, sizeof(ioc->error_info));
|
||||
if (copy_to_user(argp, ioc, sizeof(*ioc))) {
|
||||
status = -EFAULT;
|
||||
goto cleanup0;
|
||||
}
|
||||
if ((ioc->Request.Type.Direction & XFER_READ) && ioc->buf_size > 0) {
|
||||
int i;
|
||||
|
||||
@ -6594,7 +6570,6 @@ cleanup1:
|
||||
kfree(buff);
|
||||
}
|
||||
kfree(buff_size);
|
||||
kvfree(ioc);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -6628,18 +6603,39 @@ static int hpsa_ioctl(struct scsi_device *dev, unsigned int cmd,
|
||||
return hpsa_getpciinfo_ioctl(h, argp);
|
||||
case CCISS_GETDRIVVER:
|
||||
return hpsa_getdrivver_ioctl(h, argp);
|
||||
case CCISS_PASSTHRU:
|
||||
case CCISS_PASSTHRU: {
|
||||
IOCTL_Command_struct iocommand;
|
||||
|
||||
if (!argp)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&iocommand, argp, sizeof(iocommand)))
|
||||
return -EFAULT;
|
||||
if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0)
|
||||
return -EAGAIN;
|
||||
rc = hpsa_passthru_ioctl(h, argp);
|
||||
rc = hpsa_passthru_ioctl(h, &iocommand);
|
||||
atomic_inc(&h->passthru_cmds_avail);
|
||||
if (!rc && copy_to_user(argp, &iocommand, sizeof(iocommand)))
|
||||
rc = -EFAULT;
|
||||
return rc;
|
||||
case CCISS_BIG_PASSTHRU:
|
||||
}
|
||||
case CCISS_BIG_PASSTHRU: {
|
||||
BIG_IOCTL_Command_struct *ioc;
|
||||
if (!argp)
|
||||
return -EINVAL;
|
||||
if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0)
|
||||
return -EAGAIN;
|
||||
rc = hpsa_big_passthru_ioctl(h, argp);
|
||||
ioc = vmemdup_user(argp, sizeof(*ioc));
|
||||
if (IS_ERR(ioc)) {
|
||||
atomic_inc(&h->passthru_cmds_avail);
|
||||
return PTR_ERR(ioc);
|
||||
}
|
||||
rc = hpsa_big_passthru_ioctl(h, ioc);
|
||||
atomic_inc(&h->passthru_cmds_avail);
|
||||
if (!rc && copy_to_user(argp, ioc, sizeof(*ioc)))
|
||||
rc = -EFAULT;
|
||||
kvfree(ioc);
|
||||
return rc;
|
||||
}
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user