[PATCH v2 7/8] media: v4l2: remaining compat handlers

Arnd Bergmann
2020-10-30T16:56:00Z

There are eight remaining ioctl commands handled by copying
incompatible data structures in v4l2_compat_ioctl32(),
all of them fairly simple.

Change them to instead go through the native ioctl
infrastructure and only special-case the data copy.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 283 +++++++-----------
1 file changed, 109 insertions(+), 174 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index f774a17c9271..f54f49bebea7 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -338,27 +338,23 @@ struct v4l2_standard32 {
__u32 reserved[4];
};

-static int get_v4l2_standard32(struct v4l2_standard __user *p64,
+static int get_v4l2_standard32(struct v4l2_standard *p64,
struct v4l2_standard32 __user *p32)
{
/* other fields are not set by the user, nor used by the driver */
- if (!access_ok(p32, sizeof(*p32)) ||
- assign_in_user(&p64->index, &p32->index))
- return -EFAULT;
- return 0;
+ return get_user(p64->index, &p32->index);
}

-static int put_v4l2_standard32(struct v4l2_standard __user *p64,
+static int put_v4l2_standard32(struct v4l2_standard *p64,
struct v4l2_standard32 __user *p32)
{
- if (!access_ok(p32, sizeof(*p32)) ||
- assign_in_user(&p32->index, &p64->index) ||
- assign_in_user(&p32->id, &p64->id) ||
- copy_in_user(p32->name, p64->name, sizeof(p32->name)) ||
- copy_in_user(&p32->frameperiod, &p64->frameperiod,
+ if (put_user(p64->index, &p32->index) ||
+ put_user(p64->id, &p32->id) ||
+ copy_to_user(p32->name, p64->name, sizeof(p32->name)) ||
+ copy_to_user(&p32->frameperiod, &p64->frameperiod,
sizeof(p32->frameperiod)) ||
- assign_in_user(&p32->framelines, &p64->framelines) ||
- copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
+ put_user(p64->framelines, &p32->framelines) ||
+ copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
return -EFAULT;
return 0;
}
@@ -689,33 +685,30 @@ struct v4l2_framebuffer32 {
} fmt;
};

-static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *p64,
+static int get_v4l2_framebuffer32(struct v4l2_framebuffer *p64,
struct v4l2_framebuffer32 __user *p32)
{
compat_caddr_t tmp;

- if (!access_ok(p32, sizeof(*p32)) ||
- get_user(tmp, &p32->base) ||
- put_user_force(compat_ptr(tmp), &p64->base) ||
- assign_in_user(&p64->capability, &p32->capability) ||
- assign_in_user(&p64->flags, &p32->flags) ||
- copy_in_user(&p64->fmt, &p32->fmt, sizeof(p64->fmt)))
+ if (get_user(tmp, &p32->base) ||
+ get_user(p64->capability, &p32->capability) ||
+ get_user(p64->flags, &p32->flags) ||
+ copy_from_user(&p64->fmt, &p32->fmt, sizeof(p64->fmt)))
return -EFAULT;
+ p64->base = (void __force *)compat_ptr(tmp);
+
return 0;
}

-static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *p64,
+static int put_v4l2_framebuffer32(struct v4l2_framebuffer *p64,
struct v4l2_framebuffer32 __user *p32)
{
- void *base;
-
- if (!access_ok(p32, sizeof(*p32)) ||
- get_user(base, &p64->base) ||
- put_user(ptr_to_compat((void __user *)base), &p32->base) ||
- assign_in_user(&p32->capability, &p64->capability) ||
- assign_in_user(&p32->flags, &p64->flags) ||
- copy_in_user(&p32->fmt, &p64->fmt, sizeof(p64->fmt)))
+ if (put_user((uintptr_t)p64->base, &p32->base) ||
+ put_user(p64->capability, &p32->capability) ||
+ put_user(p64->flags, &p32->flags) ||
+ copy_to_user(&p32->fmt, &p64->fmt, sizeof(p64->fmt)))
return -EFAULT;
+
return 0;
}

@@ -735,18 +728,18 @@ struct v4l2_input32 {
* The 64-bit v4l2_input struct has extra padding at the end of the struct.
* Otherwise it is identical to the 32-bit version.
*/
-static inline int get_v4l2_input32(struct v4l2_input __user *p64,
+static inline int get_v4l2_input32(struct v4l2_input *p64,
struct v4l2_input32 __user *p32)
{
- if (copy_in_user(p64, p32, sizeof(*p32)))
+ if (copy_from_user(p64, p32, sizeof(*p32)))
return -EFAULT;
return 0;
}

-static inline int put_v4l2_input32(struct v4l2_input __user *p64,
+static inline int put_v4l2_input32(struct v4l2_input *p64,
struct v4l2_input32 __user *p32)
{
- if (copy_in_user(p32, p64, sizeof(*p32)))
+ if (copy_to_user(p32, p64, sizeof(*p32)))
return -EFAULT;
return 0;
}
@@ -880,38 +873,38 @@ struct v4l2_event32_time32 {
__u32 reserved[8];
};

-static int put_v4l2_event32(struct v4l2_event __user *p64,
+static int put_v4l2_event32(struct v4l2_event *p64,
struct v4l2_event32 __user *p32)
{
- if (!access_ok(p32, sizeof(*p32)) ||
- assign_in_user(&p32->type, &p64->type) ||
- copy_in_user(&p32->u, &p64->u, sizeof(p64->u)) ||
- assign_in_user(&p32->pending, &p64->pending) ||
- assign_in_user(&p32->sequence, &p64->sequence) ||
- assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) ||
- assign_in_user(&p32->timestamp.tv_nsec, &p64->timestamp.tv_nsec) ||
- assign_in_user(&p32->id, &p64->id) ||
- copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
+ if (put_user(p64->type, &p32->type) ||
+ copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) ||
+ put_user(p64->pending, &p32->pending) ||
+ put_user(p64->sequence, &p32->sequence) ||
+ put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) ||
+ put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) ||
+ put_user(p64->id, &p32->id) ||
+ copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
return -EFAULT;
return 0;
}

-static int put_v4l2_event32_time32(struct v4l2_event_time32 __user *p64,
+#ifdef CONFIG_COMPAT_32BIT_TIME
+static int put_v4l2_event32_time32(struct v4l2_event *p64,
struct v4l2_event32_time32 __user *p32)
{
- if (!access_ok(p32, sizeof(*p32)) ||
- assign_in_user(&p32->type, &p64->type) ||
- copy_in_user(&p32->u, &p64->u, sizeof(p64->u)) ||
- assign_in_user(&p32->pending, &p64->pending) ||
- assign_in_user(&p32->sequence, &p64->sequence) ||
- assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) ||
- assign_in_user(&p32->timestamp.tv_nsec, &p64->timestamp.tv_nsec) ||
- assign_in_user(&p32->id, &p64->id) ||
- copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
+ if (put_user(p64->type, &p32->type) ||
+ copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) ||
+ put_user(p64->pending, &p32->pending) ||
+ put_user(p64->sequence, &p32->sequence) ||
+ put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) ||
+ put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) ||
+ put_user(p64->id, &p32->id) ||
+ copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
return -EFAULT;
return 0;
}
#endif
+#endif

struct v4l2_edid32 {
__u32 pad;
@@ -921,34 +914,23 @@ struct v4l2_edid32 {
compat_caddr_t edid;
};

-static int get_v4l2_edid32(struct v4l2_edid __user *p64,
+static int get_v4l2_edid32(struct v4l2_edid *p64,
struct v4l2_edid32 __user *p32)
{
- compat_uptr_t tmp;
-
- if (!access_ok(p32, sizeof(*p32)) ||
- assign_in_user(&p64->pad, &p32->pad) ||
- assign_in_user(&p64->start_block, &p32->start_block) ||
- assign_in_user_cast(&p64->blocks, &p32->blocks) ||
- get_user(tmp, &p32->edid) ||
- put_user_force(compat_ptr(tmp), &p64->edid) ||
- copy_in_user(p64->reserved, p32->reserved, sizeof(p64->reserved)))
+ compat_uptr_t edid;
+
+ if (copy_from_user(p64, p32, offsetof(struct v4l2_edid32, edid)) ||
+ get_user(edid, &p32->edid))
return -EFAULT;
+
+ p64->edid = (void __force *)compat_ptr(edid);
return 0;
}

-static int put_v4l2_edid32(struct v4l2_edid __user *p64,
+static int put_v4l2_edid32(struct v4l2_edid *p64,
struct v4l2_edid32 __user *p32)
{
- void *edid;
-
- if (!access_ok(p32, sizeof(*p32)) ||
- assign_in_user(&p32->pad, &p64->pad) ||
- assign_in_user(&p32->start_block, &p64->start_block) ||
- assign_in_user(&p32->blocks, &p64->blocks) ||
- get_user(edid, &p64->edid) ||
- put_user(ptr_to_compat((void __user *)edid), &p32->edid) ||
- copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
+ if (copy_to_user(p32, p64, offsetof(struct v4l2_edid32, edid)))
return -EFAULT;
return 0;
}
@@ -994,6 +976,10 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd)
return VIDIOC_S_FMT;
case VIDIOC_TRY_FMT32:
return VIDIOC_TRY_FMT;
+ case VIDIOC_G_FBUF32:
+ return VIDIOC_G_FBUF;
+ case VIDIOC_S_FBUF32:
+ return VIDIOC_S_FBUF;
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_QUERYBUF32_TIME32:
return VIDIOC_QUERYBUF;
@@ -1020,6 +1006,22 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd)
return VIDIOC_TRY_EXT_CTRLS;
case VIDIOC_PREPARE_BUF32:
return VIDIOC_PREPARE_BUF;
+ case VIDIOC_ENUMSTD32:
+ return VIDIOC_ENUMSTD;
+ case VIDIOC_ENUMINPUT32:
+ return VIDIOC_ENUMINPUT;
+ case VIDIOC_G_EDID32:
+ return VIDIOC_G_EDID;
+ case VIDIOC_S_EDID32:
+ return VIDIOC_S_EDID;
+#ifdef CONFIG_X86_64
+ case VIDIOC_DQEVENT32:
+ return VIDIOC_DQEVENT;
+#ifdef CONFIG_COMPAT_32BIT_TIME
+ case VIDIOC_DQEVENT32_TIME32:
+ return VIDIOC_DQEVENT;
+#endif
+#endif
}
return cmd;
}
@@ -1031,6 +1033,9 @@ int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd)
case VIDIOC_S_FMT32:
case VIDIOC_TRY_FMT32:
return get_v4l2_format32(parg, arg);
+
+ case VIDIOC_S_FBUF32:
+ return get_v4l2_framebuffer32(parg, arg);
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_QUERYBUF32_TIME32:
case VIDIOC_QBUF32_TIME32:
@@ -1051,6 +1056,16 @@ int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd)

case VIDIOC_CREATE_BUFS32:
return get_v4l2_create32(parg, arg);
+
+ case VIDIOC_ENUMSTD32:
+ return get_v4l2_standard32(parg, arg);
+
+ case VIDIOC_ENUMINPUT32:
+ return get_v4l2_input32(parg, arg);
+
+ case VIDIOC_G_EDID32:
+ case VIDIOC_S_EDID32:
+ return get_v4l2_edid32(parg, arg);
}
return 0;
}
@@ -1062,6 +1077,9 @@ int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd)
case VIDIOC_S_FMT32:
case VIDIOC_TRY_FMT32:
return put_v4l2_format32(parg, arg);
+
+ case VIDIOC_G_FBUF32:
+ return put_v4l2_framebuffer32(parg, arg);
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_QUERYBUF32_TIME32:
case VIDIOC_QBUF32_TIME32:
@@ -1082,6 +1100,24 @@ int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd)

case VIDIOC_CREATE_BUFS32:
return put_v4l2_create32(parg, arg);
+
+ case VIDIOC_ENUMSTD32:
+ return put_v4l2_standard32(parg, arg);
+
+ case VIDIOC_ENUMINPUT32:
+ return put_v4l2_input32(parg, arg);
+
+ case VIDIOC_G_EDID32:
+ case VIDIOC_S_EDID32:
+ return put_v4l2_edid32(parg, arg);
+#ifdef CONFIG_X86_64
+ case VIDIOC_DQEVENT32:
+ return put_v4l2_event32(parg, arg);
+#ifdef CONFIG_COMPAT_32BIT_TIME
+ case VIDIOC_DQEVENT32_TIME32:
+ return put_v4l2_event32_time32(parg, arg);
+#endif
+#endif
}
return 0;
}
@@ -1327,16 +1363,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
* 1. When struct size is different, converts the command.
*/
switch (cmd) {
- case VIDIOC_G_FBUF32: ncmd = VIDIOC_G_FBUF; break;
- case VIDIOC_S_FBUF32: ncmd = VIDIOC_S_FBUF; break;
- case VIDIOC_ENUMSTD32: ncmd = VIDIOC_ENUMSTD; break;
- case VIDIOC_ENUMINPUT32: ncmd = VIDIOC_ENUMINPUT; break;
-#ifdef CONFIG_X86_64
- case VIDIOC_DQEVENT32: ncmd = VIDIOC_DQEVENT; break;
- case VIDIOC_DQEVENT32_TIME32: ncmd = VIDIOC_DQEVENT_TIME32; break;
-#endif
- case VIDIOC_G_EDID32: ncmd = VIDIOC_G_EDID; break;
- case VIDIOC_S_EDID32: ncmd = VIDIOC_S_EDID; break;
default: ncmd = cmd; break;
}

@@ -1346,53 +1372,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
* argument into it.
*/
switch (cmd) {
- case VIDIOC_G_EDID32:
- case VIDIOC_S_EDID32:
- err = alloc_userspace(sizeof(struct v4l2_edid), 0, &new_p64);
- if (!err)
- err = get_v4l2_edid32(new_p64, p32);
- compatible_arg = 0;
- break;
-
- case VIDIOC_S_FBUF32:
- err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
- &new_p64);
- if (!err)
- err = get_v4l2_framebuffer32(new_p64, p32);
- compatible_arg = 0;
- break;
-
- case VIDIOC_G_FBUF32:
- err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
- &new_p64);
- compatible_arg = 0;
- break;
-
- case VIDIOC_ENUMSTD32:
- err = alloc_userspace(sizeof(struct v4l2_standard), 0,
- &new_p64);
- if (!err)
- err = get_v4l2_standard32(new_p64, p32);
- compatible_arg = 0;
- break;
-
- case VIDIOC_ENUMINPUT32:
- err = alloc_userspace(sizeof(struct v4l2_input), 0, &new_p64);
- if (!err)
- err = get_v4l2_input32(new_p64, p32);
- compatible_arg = 0;
- break;
-
-#ifdef CONFIG_X86_64
- case VIDIOC_DQEVENT32:
- err = alloc_userspace(sizeof(struct v4l2_event), 0, &new_p64);
- compatible_arg = 0;
- break;
- case VIDIOC_DQEVENT32_TIME32:
- err = alloc_userspace(sizeof(struct v4l2_event_time32), 0, &new_p64);
- compatible_arg = 0;
- break;
-#endif
}
if (err)
return err;
@@ -1414,55 +1393,11 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
if (err == -ENOTTY)
return err;

- /*
- * 4. Special case: even after an error we need to put the
- * results back for some ioctls.
- *
- * In the case of EXT_CTRLS, the error_idx will contain information
- * on which control failed.
- *
- * In the case of S_EDID, the driver can return E2BIG and set
- * the blocks to maximum allowed value.
- */
- switch (cmd) {
- case VIDIOC_S_EDID32:
- if (put_v4l2_edid32(new_p64, p32))
- err = -EFAULT;
- break;
- }
- if (err)
- return err;
-
/*
* 5. Copy the data returned at the 64 bits userspace pointer to
* the original 32 bits structure.
*/
switch (cmd) {
- case VIDIOC_G_FBUF32:
- err = put_v4l2_framebuffer32(new_p64, p32);
- break;
-
-#ifdef CONFIG_X86_64
- case VIDIOC_DQEVENT32:
- err = put_v4l2_event32(new_p64, p32);
- break;
-
- case VIDIOC_DQEVENT32_TIME32:
- err = put_v4l2_event32_time32(new_p64, p32);
- break;
-#endif
-
- case VIDIOC_G_EDID32:
- err = put_v4l2_edid32(new_p64, p32);
- break;
-
- case VIDIOC_ENUMSTD32:
- err = put_v4l2_standard32(new_p64, p32);
- break;
-
- case VIDIOC_ENUMINPUT32:
- err = put_v4l2_input32(new_p64, p32);
- break;
}
return err;
}
--
2.27.0