Skip to content

Commit

Permalink
staging: comedi: comedi_fops: introduce __comedi_get_user_chanlist()
Browse files Browse the repository at this point in the history
The COMEDI_CMD and COMEDI_CMDTEST ioctl functions both copy the chanlist
passed by the user from __user memory space to kernel memory space. They
then do some sanity checking of the chanlist with comedi_check_chanlist()
before the subdevice (*do_cmdtest) and (*do_cmd) operations are called.

Introduce a helper function to handle the memdup_user() and the sanity
checking.

Also, remove the unnecessary dev_dbg() when the memdup_user() or
comedi_check_chanlist() fail.

Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
H Hartley Sweeten authored and Greg Kroah-Hartman committed Mar 17, 2014
1 parent 87ece58 commit c6cd0ee
Showing 1 changed file with 36 additions and 40 deletions.
76 changes: 36 additions & 40 deletions drivers/staging/comedi/comedi_fops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,35 @@ static int __comedi_get_user_cmd(struct comedi_device *dev,
return 0;
}

static int __comedi_get_user_chanlist(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int __user *user_chanlist,
struct comedi_cmd *cmd)
{
unsigned int *chanlist;
int ret;

/* user_chanlist could be NULL for do_cmdtest ioctls */
if (!user_chanlist)
return 0;

chanlist = memdup_user(user_chanlist,
cmd->chanlist_len * sizeof(unsigned int));
if (IS_ERR(chanlist))
return PTR_ERR(chanlist);

/* make sure each element in channel/gain list is valid */
ret = comedi_check_chanlist(s, cmd->chanlist_len, chanlist);
if (ret < 0) {
kfree(chanlist);
return ret;
}

cmd->chanlist = chanlist;

return 0;
}

static int do_cmd_ioctl(struct comedi_device *dev,
struct comedi_cmd __user *arg, void *file)
{
Expand Down Expand Up @@ -1496,26 +1525,11 @@ static int do_cmd_ioctl(struct comedi_device *dev,

async->cmd = cmd;
async->cmd.data = NULL;
/* load channel/gain list */
async->cmd.chanlist = memdup_user(user_chanlist,
async->cmd.chanlist_len *
sizeof(int));
if (IS_ERR(async->cmd.chanlist)) {
ret = PTR_ERR(async->cmd.chanlist);
async->cmd.chanlist = NULL;
dev_dbg(dev->class_dev, "memdup_user failed with code %d\n",
ret);
goto cleanup;
}

/* make sure each element in channel/gain list is valid */
ret = comedi_check_chanlist(s,
async->cmd.chanlist_len,
async->cmd.chanlist);
if (ret < 0) {
dev_dbg(dev->class_dev, "bad chanlist\n");
/* load channel/gain list */
ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &async->cmd);
if (ret)
goto cleanup;
}

ret = s->do_cmdtest(dev, s, &async->cmd);

Expand Down Expand Up @@ -1598,26 +1612,9 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
s = &dev->subdevices[cmd.subdev];

/* load channel/gain list */
if (cmd.chanlist) {
chanlist = memdup_user(user_chanlist,
cmd.chanlist_len * sizeof(int));
if (IS_ERR(chanlist)) {
ret = PTR_ERR(chanlist);
chanlist = NULL;
dev_dbg(dev->class_dev,
"memdup_user exited with code %d", ret);
goto cleanup;
}

/* make sure each element in channel/gain list is valid */
ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist);
if (ret < 0) {
dev_dbg(dev->class_dev, "bad chanlist\n");
goto cleanup;
}

cmd.chanlist = chanlist;
}
ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd);
if (ret)
return ret;

ret = s->do_cmdtest(dev, s, &cmd);

Expand All @@ -1627,9 +1624,8 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
dev_dbg(dev->class_dev, "bad cmd address\n");
ret = -EFAULT;
goto cleanup;
}
cleanup:

kfree(chanlist);

return ret;
Expand Down

0 comments on commit c6cd0ee

Please sign in to comment.