comedi: get rid of compat_alloc_user_space() mess in COMEDI_CHANINFO compat
Just take copy_from_user() out of do_chaninfo_ioctl() into the caller and have compat_chaninfo() build a native version and pass it to do_chaninfo_ioctl() directly. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
5c6a8747e0
commit
3fbfd2223a
@ -1049,31 +1049,28 @@ static int do_subdinfo_ioctl(struct comedi_device *dev,
|
|||||||
* array of range table lengths to chaninfo->range_table_list if requested
|
* array of range table lengths to chaninfo->range_table_list if requested
|
||||||
*/
|
*/
|
||||||
static int do_chaninfo_ioctl(struct comedi_device *dev,
|
static int do_chaninfo_ioctl(struct comedi_device *dev,
|
||||||
struct comedi_chaninfo __user *arg)
|
struct comedi_chaninfo *it)
|
||||||
{
|
{
|
||||||
struct comedi_subdevice *s;
|
struct comedi_subdevice *s;
|
||||||
struct comedi_chaninfo it;
|
|
||||||
|
|
||||||
lockdep_assert_held(&dev->mutex);
|
lockdep_assert_held(&dev->mutex);
|
||||||
if (copy_from_user(&it, arg, sizeof(it)))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (it.subdev >= dev->n_subdevices)
|
if (it->subdev >= dev->n_subdevices)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
s = &dev->subdevices[it.subdev];
|
s = &dev->subdevices[it->subdev];
|
||||||
|
|
||||||
if (it.maxdata_list) {
|
if (it->maxdata_list) {
|
||||||
if (s->maxdata || !s->maxdata_list)
|
if (s->maxdata || !s->maxdata_list)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (copy_to_user(it.maxdata_list, s->maxdata_list,
|
if (copy_to_user(it->maxdata_list, s->maxdata_list,
|
||||||
s->n_chan * sizeof(unsigned int)))
|
s->n_chan * sizeof(unsigned int)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it.flaglist)
|
if (it->flaglist)
|
||||||
return -EINVAL; /* flaglist not supported */
|
return -EINVAL; /* flaglist not supported */
|
||||||
|
|
||||||
if (it.rangelist) {
|
if (it->rangelist) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!s->range_table_list)
|
if (!s->range_table_list)
|
||||||
@ -1081,9 +1078,9 @@ static int do_chaninfo_ioctl(struct comedi_device *dev,
|
|||||||
for (i = 0; i < s->n_chan; i++) {
|
for (i = 0; i < s->n_chan; i++) {
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
|
x = (dev->minor << 28) | (it->subdev << 24) | (i << 16) |
|
||||||
(s->range_table_list[i]->length);
|
(s->range_table_list[i]->length);
|
||||||
if (put_user(x, it.rangelist + i))
|
if (put_user(x, it->rangelist + i))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2205,9 +2202,14 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
|
|||||||
(struct comedi_subdinfo __user *)arg,
|
(struct comedi_subdinfo __user *)arg,
|
||||||
file);
|
file);
|
||||||
break;
|
break;
|
||||||
case COMEDI_CHANINFO:
|
case COMEDI_CHANINFO: {
|
||||||
rc = do_chaninfo_ioctl(dev, (void __user *)arg);
|
struct comedi_chaninfo it;
|
||||||
|
if (copy_from_user(&it, (void __user *)arg, sizeof(it)))
|
||||||
|
rc = -EFAULT;
|
||||||
|
else
|
||||||
|
rc = do_chaninfo_ioctl(dev, &it);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case COMEDI_RANGEINFO:
|
case COMEDI_RANGEINFO:
|
||||||
rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
|
rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
|
||||||
break;
|
break;
|
||||||
@ -2874,35 +2876,25 @@ struct comedi32_insnlist_struct {
|
|||||||
/* Handle 32-bit COMEDI_CHANINFO ioctl. */
|
/* Handle 32-bit COMEDI_CHANINFO ioctl. */
|
||||||
static int compat_chaninfo(struct file *file, unsigned long arg)
|
static int compat_chaninfo(struct file *file, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct comedi_chaninfo __user *chaninfo;
|
struct comedi_file *cfp = file->private_data;
|
||||||
struct comedi32_chaninfo_struct __user *chaninfo32;
|
struct comedi_device *dev = cfp->dev;
|
||||||
|
struct comedi32_chaninfo_struct chaninfo32;
|
||||||
|
struct comedi_chaninfo chaninfo;
|
||||||
int err;
|
int err;
|
||||||
union {
|
|
||||||
unsigned int uint;
|
|
||||||
compat_uptr_t uptr;
|
|
||||||
} temp;
|
|
||||||
|
|
||||||
chaninfo32 = compat_ptr(arg);
|
if (copy_from_user(&chaninfo32, compat_ptr(arg), sizeof(chaninfo32)))
|
||||||
chaninfo = compat_alloc_user_space(sizeof(*chaninfo));
|
|
||||||
|
|
||||||
/* Copy chaninfo structure. Ignore unused members. */
|
|
||||||
if (!access_ok(chaninfo32, sizeof(*chaninfo32)) ||
|
|
||||||
!access_ok(chaninfo, sizeof(*chaninfo)))
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
err = 0;
|
memset(&chaninfo, 0, sizeof(chaninfo));
|
||||||
err |= __get_user(temp.uint, &chaninfo32->subdev);
|
chaninfo.subdev = chaninfo32.subdev;
|
||||||
err |= __put_user(temp.uint, &chaninfo->subdev);
|
chaninfo.maxdata_list = compat_ptr(chaninfo32.maxdata_list);
|
||||||
err |= __get_user(temp.uptr, &chaninfo32->maxdata_list);
|
chaninfo.flaglist = compat_ptr(chaninfo32.flaglist);
|
||||||
err |= __put_user(compat_ptr(temp.uptr), &chaninfo->maxdata_list);
|
chaninfo.rangelist = compat_ptr(chaninfo32.rangelist);
|
||||||
err |= __get_user(temp.uptr, &chaninfo32->flaglist);
|
|
||||||
err |= __put_user(compat_ptr(temp.uptr), &chaninfo->flaglist);
|
|
||||||
err |= __get_user(temp.uptr, &chaninfo32->rangelist);
|
|
||||||
err |= __put_user(compat_ptr(temp.uptr), &chaninfo->rangelist);
|
|
||||||
if (err)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
return comedi_unlocked_ioctl(file, COMEDI_CHANINFO, (unsigned long)chaninfo);
|
mutex_lock(&dev->mutex);
|
||||||
|
err = do_chaninfo_ioctl(dev, &chaninfo);
|
||||||
|
mutex_unlock(&dev->mutex);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle 32-bit COMEDI_RANGEINFO ioctl. */
|
/* Handle 32-bit COMEDI_RANGEINFO ioctl. */
|
||||||
|
Loading…
Reference in New Issue
Block a user