media: v4l2-core: split out data copy from video_usercopy
The copy-in/out portions of video_usercopy() are about to get more complex, so turn then into separate functions as a cleanup first. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
parent
4a873f3fa5
commit
c8ef1a6076
@ -3023,8 +3023,69 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int video_translate_cmd(unsigned int cmd)
|
||||
{
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static int video_get_user(void __user *arg, void *parg, unsigned int cmd,
|
||||
bool *always_copy)
|
||||
{
|
||||
unsigned int n = _IOC_SIZE(cmd);
|
||||
|
||||
if (!(_IOC_DIR(cmd) & _IOC_WRITE)) {
|
||||
/* read-only ioctl */
|
||||
memset(parg, 0, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
default:
|
||||
/*
|
||||
* In some cases, only a few fields are used as input,
|
||||
* i.e. when the app sets "index" and then the driver
|
||||
* fills in the rest of the structure for the thing
|
||||
* with that index. We only need to copy up the first
|
||||
* non-input field.
|
||||
*/
|
||||
if (v4l2_is_known_ioctl(cmd)) {
|
||||
u32 flags = v4l2_ioctls[_IOC_NR(cmd)].flags;
|
||||
|
||||
if (flags & INFO_FL_CLEAR_MASK)
|
||||
n = (flags & INFO_FL_CLEAR_MASK) >> 16;
|
||||
*always_copy = flags & INFO_FL_ALWAYS_COPY;
|
||||
}
|
||||
|
||||
if (copy_from_user(parg, (void __user *)arg, n))
|
||||
return -EFAULT;
|
||||
|
||||
/* zero out anything we don't copy from userspace */
|
||||
if (n < _IOC_SIZE(cmd))
|
||||
memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int video_put_user(void __user *arg, void *parg, unsigned int cmd)
|
||||
{
|
||||
if (!(_IOC_DIR(cmd) & _IOC_READ))
|
||||
return 0;
|
||||
|
||||
switch (cmd) {
|
||||
default:
|
||||
/* Copy results into user buffer */
|
||||
if (copy_to_user(arg, parg, _IOC_SIZE(cmd)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long
|
||||
video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg,
|
||||
v4l2_kioctl func)
|
||||
{
|
||||
char sbuf[128];
|
||||
@ -3036,6 +3097,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
size_t array_size = 0;
|
||||
void __user *user_ptr = NULL;
|
||||
void **kernel_ptr = NULL;
|
||||
unsigned int cmd = video_translate_cmd(orig_cmd);
|
||||
const size_t ioc_size = _IOC_SIZE(cmd);
|
||||
|
||||
/* Copy arguments into temp kernel buffer */
|
||||
@ -3050,37 +3112,12 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
parg = mbuf;
|
||||
}
|
||||
|
||||
err = -EFAULT;
|
||||
if (_IOC_DIR(cmd) & _IOC_WRITE) {
|
||||
unsigned int n = ioc_size;
|
||||
|
||||
/*
|
||||
* In some cases, only a few fields are used as input,
|
||||
* i.e. when the app sets "index" and then the driver
|
||||
* fills in the rest of the structure for the thing
|
||||
* with that index. We only need to copy up the first
|
||||
* non-input field.
|
||||
*/
|
||||
if (v4l2_is_known_ioctl(cmd)) {
|
||||
u32 flags = v4l2_ioctls[_IOC_NR(cmd)].flags;
|
||||
|
||||
if (flags & INFO_FL_CLEAR_MASK)
|
||||
n = (flags & INFO_FL_CLEAR_MASK) >> 16;
|
||||
always_copy = flags & INFO_FL_ALWAYS_COPY;
|
||||
}
|
||||
|
||||
if (copy_from_user(parg, (void __user *)arg, n))
|
||||
goto out;
|
||||
|
||||
/* zero out anything we don't copy from userspace */
|
||||
if (n < ioc_size)
|
||||
memset((u8 *)parg + n, 0, ioc_size - n);
|
||||
} else {
|
||||
/* read-only ioctl */
|
||||
memset(parg, 0, ioc_size);
|
||||
}
|
||||
}
|
||||
|
||||
err = video_get_user((void __user *)arg, parg, orig_cmd, &always_copy);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
@ -3131,15 +3168,8 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
goto out;
|
||||
|
||||
out_array_args:
|
||||
/* Copy results into user buffer */
|
||||
switch (_IOC_DIR(cmd)) {
|
||||
case _IOC_READ:
|
||||
case (_IOC_WRITE | _IOC_READ):
|
||||
if (copy_to_user((void __user *)arg, parg, ioc_size))
|
||||
err = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (video_put_user((void __user *)arg, parg, orig_cmd))
|
||||
err = -EFAULT;
|
||||
out:
|
||||
kvfree(mbuf);
|
||||
return err;
|
||||
|
Loading…
Reference in New Issue
Block a user