Hi Greg,
Those are the backports meant to solve CVE-2017-13166 on Kernel 3.18.
It contains two v4l2-ctrls fixes that are required to avoid crashes at the test application.
I wrote two patches myself for Kernel 3.18 in order to solve some issues specific for Kernel 3.18 with aren't needed upstream. one is actually a one-line change backport. The other one makes sure that both 32-bits and 64-bits version of some ioctl calls will return the same value for a reserved field.
I noticed an extra bug while testing it, but the bug also hits upstream, and should be backported all the way down all stable/LTS versions. So, I'll send it the usual way, after merging upsream.
Regards, Mauro
Daniel Mentz (2): media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
Hans Verkuil (12): media: v4l2-ioctl.c: don't copy back the result for -ENOTTY media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF media: v4l2-compat-ioctl32.c: fix the indentation media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 media: v4l2-compat-ioctl32.c: avoid sizeof(type) media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors media: v4l2-ctrls: fix sparse warning
Mauro Carvalho Chehab (2): media: v4l2-compat-ioctl32: use compat_u64 for video standard media: v4l2-compat-ioctl32: initialize a reserved field
Ricardo Ribalda (2): vb2: V4L2_BUF_FLAG_DONE is set after DQBUF media: media/v4l2-ctrls: volatiles should not generate CH_VALUE
drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1020 +++++++++++++++---------- drivers/media/v4l2-core/v4l2-ctrls.c | 96 ++- drivers/media/v4l2-core/v4l2-ioctl.c | 5 +- drivers/media/v4l2-core/videobuf2-core.c | 5 + 4 files changed, 691 insertions(+), 435 deletions(-)
From: Hans Verkuil hans.verkuil@cisco.com
commit 181a4a2d5a0a7b43cab08a70710d727e7764ccdd upstream.
If the ioctl returned -ENOTTY, then don't bother copying back the result as there is no point.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com --- drivers/media/v4l2-core/v4l2-ioctl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 9ccb19a435ef..bb2387fcbfee 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2539,8 +2539,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
/* Handles IOCTL */ err = func(file, cmd, parg); - if (err == -ENOIOCTLCMD) + if (err == -ENOTTY || err == -ENOIOCTLCMD) { err = -ENOTTY; + goto out; + } + if (err == 0) { if (cmd == VIDIOC_DQBUF) trace_v4l2_dqbuf(video_devdata(file)->minor, parg);
From: Ricardo Ribalda ricardo.ribalda@gmail.com
commit 3171cc2b4eb9831ab4df1d80d0410a945b8bc84e upstream.
According to the doc, V4L2_BUF_FLAG_DONE is cleared after DQBUF:
V4L2_BUF_FLAG_DONE 0x00000004 ... After calling the VIDIOC_QBUF or VIDIOC_DQBUF it is always cleared ...
Unfortunately, it seems that videobuf2 keeps it set after DQBUF. This can be tested with vivid and dev_debug:
[257604.338082] video1: VIDIOC_DQBUF: 71:33:25.00260479 index=3, type=vid-cap, flags=0x00002004, field=none, sequence=163, memory=userptr, bytesused=460800, offset/userptr=0x344b000, length=460800
This patch forces FLAG_DONE to 0 after calling DQBUF.
Reported-by: Dimitrios Katsaros patcherwork@gmail.com Signed-off-by: Ricardo Ribalda Delgado ricardo.ribalda@gmail.com Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com --- drivers/media/v4l2-core/videobuf2-core.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index d5c300150cf4..f0811b7e900d 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2075,6 +2075,11 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n dprintk(1, "dqbuf of buffer %d, with state %d\n", vb->v4l2_buf.index, vb->state);
+ /* + * After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be + * cleared. + */ + b->flags &= ~V4L2_BUF_FLAG_DONE; return 0; }
From: Hans Verkuil hans.verkuil@cisco.com
commit 3ee6d040719ae09110e5cdf24d5386abe5d1b776 upstream.
The result of the VIDIOC_PREPARE_BUF ioctl was never copied back to userspace since it was missing in the switch.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index aa11f02c0a8f..fc4f92a0c985 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -996,6 +996,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_create32(&karg.v2crt, up); break;
+ case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF:
From: Hans Verkuil hans.verkuil@cisco.com
commit b7b957d429f601d6d1942122b339474f31191d75 upstream.
The indentation of this source is all over the place. Fix this. This patch only changes whitespace.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 216 +++++++++++++------------- 1 file changed, 108 insertions(+), 108 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index fc4f92a0c985..866019bbf513 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -48,11 +48,11 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || - copy_from_user(&kp->w, &up->w, sizeof(up->w)) || - get_user(kp->field, &up->field) || - get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount)) - return -EFAULT; + copy_from_user(&kp->w, &up->w, sizeof(up->w)) || + get_user(kp->field, &up->field) || + get_user(kp->chromakey, &up->chromakey) || + get_user(kp->clipcount, &up->clipcount)) + return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; if (kp->clipcount) { @@ -82,10 +82,10 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || - put_user(kp->field, &up->field) || - put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount)) - return -EFAULT; + put_user(kp->field, &up->field) || + put_user(kp->chromakey, &up->chromakey) || + put_user(kp->clipcount, &up->clipcount)) + return -EFAULT; return 0; }
@@ -97,7 +97,7 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi }
static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) + struct v4l2_pix_format_mplane __user *up) { if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -112,7 +112,7 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi }
static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) + struct v4l2_pix_format_mplane __user *up) { if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -200,7 +200,7 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -241,7 +241,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -275,7 +275,7 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 { /* other fields are not set by the user, nor used by the driver */ if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || - get_user(kp->index, &up->index)) + get_user(kp->index, &up->index)) return -EFAULT; return 0; } @@ -283,13 +283,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || - put_user(kp->index, &up->index) || - copy_to_user(up->id, &kp->id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, 24) || - copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) - return -EFAULT; + put_user(kp->index, &up->index) || + copy_to_user(up->id, &kp->id, sizeof(__u64)) || + copy_to_user(up->name, kp->name, 24) || + copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || + put_user(kp->framelines, &up->framelines) || + copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) + return -EFAULT; return 0; }
@@ -329,14 +329,14 @@ struct v4l2_buffer32 { };
static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, - enum v4l2_memory memory) + enum v4l2_memory memory) { void __user *up_pln; compat_long_t p;
if (copy_in_user(up, up32, 2 * sizeof(__u32)) || - copy_in_user(&up->data_offset, &up32->data_offset, - sizeof(__u32))) + copy_in_user(&up->data_offset, &up32->data_offset, + sizeof(__u32))) return -EFAULT;
if (memory == V4L2_MEMORY_USERPTR) { @@ -350,7 +350,7 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ return -EFAULT; } else { if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, - sizeof(__u32))) + sizeof(__u32))) return -EFAULT; }
@@ -358,23 +358,23 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ }
static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, - enum v4l2_memory memory) + enum v4l2_memory memory) { if (copy_in_user(up32, up, 2 * sizeof(__u32)) || - copy_in_user(&up32->data_offset, &up->data_offset, - sizeof(__u32))) + copy_in_user(&up32->data_offset, &up->data_offset, + sizeof(__u32))) return -EFAULT;
/* For MMAP, driver might've set up the offset, so copy it back. * USERPTR stays the same (was userspace-provided), so no copying. */ if (memory == V4L2_MEMORY_MMAP) if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, - sizeof(__u32))) + sizeof(__u32))) return -EFAULT; /* For DMABUF, driver might've set up the fd, so copy it back. */ if (memory == V4L2_MEMORY_DMABUF) if (copy_in_user(&up32->m.fd, &up->m.fd, - sizeof(int))) + sizeof(int))) return -EFAULT;
return 0; @@ -389,19 +389,19 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user int ret;
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || - get_user(kp->index, &up->index) || - get_user(kp->type, &up->type) || - get_user(kp->flags, &up->flags) || - get_user(kp->memory, &up->memory) || - get_user(kp->length, &up->length)) - return -EFAULT; + get_user(kp->index, &up->index) || + get_user(kp->type, &up->type) || + get_user(kp->flags, &up->flags) || + get_user(kp->memory, &up->memory) || + get_user(kp->length, &up->length)) + return -EFAULT;
if (V4L2_TYPE_IS_OUTPUT(kp->type)) if (get_user(kp->bytesused, &up->bytesused) || - get_user(kp->field, &up->field) || - get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, - &up->timestamp.tv_usec)) + get_user(kp->field, &up->field) || + get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + get_user(kp->timestamp.tv_usec, + &up->timestamp.tv_usec)) return -EFAULT;
if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { @@ -418,13 +418,13 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
uplane32 = compat_ptr(p); if (!access_ok(VERIFY_READ, uplane32, - num_planes * sizeof(struct v4l2_plane32))) + num_planes * sizeof(struct v4l2_plane32))) return -EFAULT;
/* We don't really care if userspace decides to kill itself * by passing a very big num_planes value */ uplane = compat_alloc_user_space(num_planes * - sizeof(struct v4l2_plane)); + sizeof(struct v4l2_plane)); kp->m.planes = (__force struct v4l2_plane *)uplane;
while (--num_planes >= 0) { @@ -442,12 +442,12 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user break; case V4L2_MEMORY_USERPTR: { - compat_long_t tmp; + compat_long_t tmp;
- if (get_user(tmp, &up->m.userptr)) - return -EFAULT; + if (get_user(tmp, &up->m.userptr)) + return -EFAULT;
- kp->m.userptr = (unsigned long)compat_ptr(tmp); + kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; case V4L2_MEMORY_OVERLAY: @@ -473,22 +473,22 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user int ret;
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || - put_user(kp->index, &up->index) || - put_user(kp->type, &up->type) || - put_user(kp->flags, &up->flags) || - put_user(kp->memory, &up->memory)) - return -EFAULT; + put_user(kp->index, &up->index) || + put_user(kp->type, &up->type) || + put_user(kp->flags, &up->flags) || + put_user(kp->memory, &up->memory)) + return -EFAULT;
if (put_user(kp->bytesused, &up->bytesused) || - put_user(kp->field, &up->field) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->reserved2, &up->reserved2) || - put_user(kp->reserved, &up->reserved) || - put_user(kp->length, &up->length)) - return -EFAULT; + put_user(kp->field, &up->field) || + put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || + copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || + put_user(kp->sequence, &up->sequence) || + put_user(kp->reserved2, &up->reserved2) || + put_user(kp->reserved, &up->reserved) || + put_user(kp->length, &up->length)) + return -EFAULT;
if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { num_planes = kp->length; @@ -552,11 +552,11 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame u32 tmp;
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || - get_user(tmp, &up->base) || - get_user(kp->capability, &up->capability) || - get_user(kp->flags, &up->flags) || - copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) - return -EFAULT; + get_user(tmp, &up->base) || + get_user(kp->capability, &up->capability) || + get_user(kp->flags, &up->flags) || + copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) + return -EFAULT; kp->base = (__force void *)compat_ptr(tmp); return 0; } @@ -566,11 +566,11 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame u32 tmp = (u32)((unsigned long)kp->base);
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || - put_user(tmp, &up->base) || - put_user(kp->capability, &up->capability) || - put_user(kp->flags, &up->flags) || - copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) - return -EFAULT; + put_user(tmp, &up->base) || + put_user(kp->capability, &up->capability) || + put_user(kp->flags, &up->flags) || + copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) + return -EFAULT; return 0; }
@@ -602,11 +602,11 @@ static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __ }
struct v4l2_ext_controls32 { - __u32 ctrl_class; - __u32 count; - __u32 error_idx; - __u32 reserved[2]; - compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */ + __u32 ctrl_class; + __u32 count; + __u32 error_idx; + __u32 reserved[2]; + compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */ };
struct v4l2_ext_control32 { @@ -645,11 +645,11 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext compat_caddr_t p;
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || - get_user(kp->ctrl_class, &up->ctrl_class) || - get_user(kp->count, &up->count) || - get_user(kp->error_idx, &up->error_idx) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) - return -EFAULT; + get_user(kp->ctrl_class, &up->ctrl_class) || + get_user(kp->count, &up->count) || + get_user(kp->error_idx, &up->error_idx) || + copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + return -EFAULT; n = kp->count; if (n == 0) { kp->controls = NULL; @@ -659,7 +659,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return -EFAULT; ucontrols = compat_ptr(p); if (!access_ok(VERIFY_READ, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + n * sizeof(struct v4l2_ext_control32))) return -EFAULT; kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); kp->controls = (__force struct v4l2_ext_control *)kcontrols; @@ -694,11 +694,11 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext compat_caddr_t p;
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || - put_user(kp->ctrl_class, &up->ctrl_class) || - put_user(kp->count, &up->count) || - put_user(kp->error_idx, &up->error_idx) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) - return -EFAULT; + put_user(kp->ctrl_class, &up->ctrl_class) || + put_user(kp->count, &up->count) || + put_user(kp->error_idx, &up->error_idx) || + copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + return -EFAULT; if (!kp->count) return 0;
@@ -706,7 +706,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return -EFAULT; ucontrols = compat_ptr(p); if (!access_ok(VERIFY_WRITE, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + n * sizeof(struct v4l2_ext_control32))) return -EFAULT;
while (--n >= 0) { @@ -743,15 +743,15 @@ struct v4l2_event32 { static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) || - put_user(kp->type, &up->type) || - copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || - put_user(kp->pending, &up->pending) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || - put_user(kp->id, &up->id) || - copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) - return -EFAULT; + put_user(kp->type, &up->type) || + copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || + put_user(kp->pending, &up->pending) || + put_user(kp->sequence, &up->sequence) || + put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || + put_user(kp->id, &up->id) || + copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) + return -EFAULT; return 0; }
@@ -768,12 +768,12 @@ static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) u32 tmp;
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || - get_user(kp->pad, &up->pad) || - get_user(kp->start_block, &up->start_block) || - get_user(kp->blocks, &up->blocks) || - get_user(tmp, &up->edid) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) - return -EFAULT; + get_user(kp->pad, &up->pad) || + get_user(kp->start_block, &up->start_block) || + get_user(kp->blocks, &up->blocks) || + get_user(tmp, &up->edid) || + copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + return -EFAULT; kp->edid = (__force u8 *)compat_ptr(tmp); return 0; } @@ -783,12 +783,12 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) u32 tmp = (u32)((unsigned long)kp->edid);
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || - put_user(kp->pad, &up->pad) || - put_user(kp->start_block, &up->start_block) || - put_user(kp->blocks, &up->blocks) || - put_user(tmp, &up->edid) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) - return -EFAULT; + put_user(kp->pad, &up->pad) || + put_user(kp->start_block, &up->start_block) || + put_user(kp->blocks, &up->blocks) || + put_user(tmp, &up->edid) || + copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + return -EFAULT; return 0; }
From: Hans Verkuil hans.verkuil@cisco.com
commit 486c521510c44a04cd756a9267e7d1e271c8a4ba upstream.
These helper functions do not really help. Move the code to the __get/put_v4l2_format32 functions.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 84 +++++---------------------- 1 file changed, 16 insertions(+), 68 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 866019bbf513..702757012dc7 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -89,64 +89,6 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return 0; }
-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - struct v4l2_format32 { __u32 type; /* enum v4l2_buf_type */ union { @@ -184,20 +126,23 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + return copy_from_user(&kp->fmt.pix, &up->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp, - &up->fmt.pix_mp); + return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); + return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); + return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", kp->type); @@ -225,20 +170,23 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + return copy_to_user(&up->fmt.pix, &kp->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp, - &up->fmt.pix_mp); + return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); + return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); + return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", kp->type);
From: Hans Verkuil hans.verkuil@cisco.com
commit 333b1e9f96ce05f7498b581509bb30cde03018bf upstream.
Instead of doing sizeof(struct foo) use sizeof(*up). There even were cases where 4 * sizeof(__u32) was used instead of sizeof(kp->reserved), which is very dangerous when the size of the reserved array changes.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 80 +++++++++++++-------------- 1 file changed, 38 insertions(+), 42 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 702757012dc7..b7dd98168a68 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -47,7 +47,7 @@ struct v4l2_window32 {
static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(&kp->w, &up->w, sizeof(up->w)) || get_user(kp->field, &up->field) || get_user(kp->chromakey, &up->chromakey) || @@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); kp->clips = kclips; while (--n >= 0) { if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) @@ -152,14 +152,14 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us
static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32))) + if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; return __get_v4l2_format32(kp, up); }
static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) return -EFAULT; return __get_v4l2_format32(&kp->format, &up->format); @@ -196,17 +196,17 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us
static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || - put_user(kp->type, &up->type)) + if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; return __put_v4l2_format32(kp, up); }
static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || - copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) - return -EFAULT; + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + return -EFAULT; return __put_v4l2_format32(&kp->format, &up->format); }
@@ -222,7 +222,7 @@ struct v4l2_standard32 { static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->index, &up->index)) return -EFAULT; return 0; @@ -230,13 +230,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32
static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->index, &up->index) || copy_to_user(up->id, &kp->id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, 24) || + copy_to_user(up->name, kp->name, sizeof(up->name)) || copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return 0; } @@ -284,7 +284,7 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __
if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(&up->data_offset, &up32->data_offset, - sizeof(__u32))) + sizeof(up->data_offset))) return -EFAULT;
if (memory == V4L2_MEMORY_USERPTR) { @@ -294,11 +294,11 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ if (put_user((unsigned long)up_pln, &up->m.userptr)) return -EFAULT; } else if (memory == V4L2_MEMORY_DMABUF) { - if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int))) + if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd))) return -EFAULT; } else { if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, - sizeof(__u32))) + sizeof(up32->m.mem_offset))) return -EFAULT; }
@@ -310,19 +310,19 @@ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ { if (copy_in_user(up32, up, 2 * sizeof(__u32)) || copy_in_user(&up32->data_offset, &up->data_offset, - sizeof(__u32))) + sizeof(up->data_offset))) return -EFAULT;
/* For MMAP, driver might've set up the offset, so copy it back. * USERPTR stays the same (was userspace-provided), so no copying. */ if (memory == V4L2_MEMORY_MMAP) if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, - sizeof(__u32))) + sizeof(up->m.mem_offset))) return -EFAULT; /* For DMABUF, driver might've set up the fd, so copy it back. */ if (memory == V4L2_MEMORY_DMABUF) if (copy_in_user(&up32->m.fd, &up->m.fd, - sizeof(int))) + sizeof(up->m.fd))) return -EFAULT;
return 0; @@ -336,7 +336,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user int num_planes; int ret;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->index, &up->index) || get_user(kp->type, &up->type) || get_user(kp->flags, &up->flags) || @@ -348,8 +348,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user if (get_user(kp->bytesused, &up->bytesused) || get_user(kp->field, &up->field) || get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, - &up->timestamp.tv_usec)) + get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec)) return -EFAULT;
if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { @@ -366,13 +365,12 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
uplane32 = compat_ptr(p); if (!access_ok(VERIFY_READ, uplane32, - num_planes * sizeof(struct v4l2_plane32))) + num_planes * sizeof(*uplane32))) return -EFAULT;
/* We don't really care if userspace decides to kill itself * by passing a very big num_planes value */ - uplane = compat_alloc_user_space(num_planes * - sizeof(struct v4l2_plane)); + uplane = compat_alloc_user_space(num_planes * sizeof(*uplane)); kp->m.planes = (__force struct v4l2_plane *)uplane;
while (--num_planes >= 0) { @@ -420,7 +418,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user int num_planes; int ret;
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->index, &up->index) || put_user(kp->type, &up->type) || put_user(kp->flags, &up->flags) || @@ -431,7 +429,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user put_user(kp->field, &up->field) || put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || + copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || put_user(kp->sequence, &up->sequence) || put_user(kp->reserved2, &up->reserved2) || put_user(kp->reserved, &up->reserved) || @@ -499,7 +497,7 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame { u32 tmp;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(tmp, &up->base) || get_user(kp->capability, &up->capability) || get_user(kp->flags, &up->flags) || @@ -513,7 +511,7 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame { u32 tmp = (u32)((unsigned long)kp->base);
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(tmp, &up->base) || put_user(kp->capability, &up->capability) || put_user(kp->flags, &up->flags) || @@ -537,14 +535,14 @@ struct v4l2_input32 { Otherwise it is identical to the 32-bit version. */ static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) { - if (copy_from_user(kp, up, sizeof(struct v4l2_input32))) + if (copy_from_user(kp, up, sizeof(*up))) return -EFAULT; return 0; }
static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) { - if (copy_to_user(up, kp, sizeof(struct v4l2_input32))) + if (copy_to_user(up, kp, sizeof(*up))) return -EFAULT; return 0; } @@ -592,7 +590,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext int n; compat_caddr_t p;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->ctrl_class, &up->ctrl_class) || get_user(kp->count, &up->count) || get_user(kp->error_idx, &up->error_idx) || @@ -606,10 +604,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_READ, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols))) return -EFAULT; - kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); + kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols)); kp->controls = (__force struct v4l2_ext_control *)kcontrols; while (--n >= 0) { u32 id; @@ -641,7 +638,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext int n = kp->count; compat_caddr_t p;
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->ctrl_class, &up->ctrl_class) || put_user(kp->count, &up->count) || put_user(kp->error_idx, &up->error_idx) || @@ -653,8 +650,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_WRITE, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols))) return -EFAULT;
while (--n >= 0) { @@ -690,7 +686,7 @@ struct v4l2_event32 {
static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->type, &up->type) || copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || put_user(kp->pending, &up->pending) || @@ -698,7 +694,7 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || put_user(kp->id, &up->id) || - copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return 0; } @@ -715,7 +711,7 @@ static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) { u32 tmp;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->pad, &up->pad) || get_user(kp->start_block, &up->start_block) || get_user(kp->blocks, &up->blocks) || @@ -730,7 +726,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) { u32 tmp = (u32)((unsigned long)kp->edid);
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->pad, &up->pad) || put_user(kp->start_block, &up->start_block) || put_user(kp->blocks, &up->blocks) ||
From: Hans Verkuil hans.verkuil@cisco.com
commit 8ed5a59dcb47a6f76034ee760b36e089f3e82529 upstream.
The struct v4l2_plane32 should set m.userptr as well. The same happens in v4l2_buffer32 and v4l2-compliance tests for this.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 47 ++++++++++++++++----------- 1 file changed, 28 insertions(+), 19 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index b7dd98168a68..a27fd9105948 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -287,19 +287,24 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ sizeof(up->data_offset))) return -EFAULT;
- if (memory == V4L2_MEMORY_USERPTR) { + switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: + if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, + sizeof(up32->m.mem_offset))) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: if (get_user(p, &up32->m.userptr)) return -EFAULT; up_pln = compat_ptr(p); if (put_user((unsigned long)up_pln, &up->m.userptr)) return -EFAULT; - } else if (memory == V4L2_MEMORY_DMABUF) { + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd))) return -EFAULT; - } else { - if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, - sizeof(up32->m.mem_offset))) - return -EFAULT; + break; }
return 0; @@ -308,22 +313,32 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { + unsigned long p; + if (copy_in_user(up32, up, 2 * sizeof(__u32)) || copy_in_user(&up32->data_offset, &up->data_offset, sizeof(up->data_offset))) return -EFAULT;
- /* For MMAP, driver might've set up the offset, so copy it back. - * USERPTR stays the same (was userspace-provided), so no copying. */ - if (memory == V4L2_MEMORY_MMAP) + switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, sizeof(up->m.mem_offset))) return -EFAULT; - /* For DMABUF, driver might've set up the fd, so copy it back. */ - if (memory == V4L2_MEMORY_DMABUF) + break; + case V4L2_MEMORY_USERPTR: + if (get_user(p, &up->m.userptr) || + put_user((compat_ulong_t)ptr_to_compat((__force void *)p), + &up32->m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd))) return -EFAULT; + break; + }
return 0; } @@ -383,6 +398,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (get_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; @@ -396,10 +412,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (get_user(kp->m.fd, &up->m.fd)) return -EFAULT; @@ -456,6 +468,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (put_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; @@ -463,10 +476,6 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user if (put_user(kp->m.userptr, &up->m.userptr)) return -EFAULT; break; - case V4L2_MEMORY_OVERLAY: - if (put_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (put_user(kp->m.fd, &up->m.fd)) return -EFAULT;
From: Hans Verkuil hans.verkuil@cisco.com
commit b8c601e8af2d08f733d74defa8465303391bb930 upstream.
ctrl_is_pointer just hardcoded two known string controls, but that caused problems when using e.g. custom controls that use a pointer for the payload.
Reimplement this function: it now finds the v4l2_ctrl (if the driver uses the control framework) or it calls vidioc_query_ext_ctrl (if the driver implements that directly).
In both cases it can now check if the control is a pointer control or not.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 57 ++++++++++++++++++--------- 1 file changed, 38 insertions(+), 19 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index a27fd9105948..c78462e79a0a 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -18,6 +18,8 @@ #include <linux/videodev2.h> #include <linux/v4l2-subdev.h> #include <media/v4l2-dev.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ctrls.h> #include <media/v4l2-ioctl.h>
static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -575,24 +577,39 @@ struct v4l2_ext_control32 { }; } __attribute__ ((packed));
-/* The following function really belong in v4l2-common, but that causes - a circular dependency between modules. We need to think about this, but - for now this will do. */ - -/* Return non-zero if this control is a pointer type. Currently only - type STRING is a pointer type. */ -static inline int ctrl_is_pointer(u32 id) +/* Return true if this control is a pointer type. */ +static inline bool ctrl_is_pointer(struct file *file, u32 id) { - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; + struct video_device *vdev = video_devdata(file); + struct v4l2_fh *fh = NULL; + struct v4l2_ctrl_handler *hdl = NULL; + struct v4l2_query_ext_ctrl qec = { id }; + const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; + + if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) + fh = file->private_data; + + if (fh && fh->ctrl_handler) + hdl = fh->ctrl_handler; + else if (vdev->ctrl_handler) + hdl = vdev->ctrl_handler; + + if (hdl) { + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id); + + return ctrl && ctrl->is_ptr; } + + if (!ops->vidioc_query_ext_ctrl) + return false; + + return !ops->vidioc_query_ext_ctrl(file, fh, &qec) && + (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); }
-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int get_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; @@ -624,7 +641,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return -EFAULT; if (get_user(id, &kcontrols->id)) return -EFAULT; - if (ctrl_is_pointer(id)) { + if (ctrl_is_pointer(file, id)) { void __user *s;
if (get_user(p, &ucontrols->string)) @@ -639,7 +656,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return 0; }
-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int put_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols = @@ -671,7 +690,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext /* Do not modify the pointer when copying a pointer control. The contents of the pointer was changed, not the pointer itself. */ - if (ctrl_is_pointer(id)) + if (ctrl_is_pointer(file, id)) size -= sizeof(ucontrols->value64); if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; @@ -884,7 +903,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(&karg.v2ecs, up); + err = get_v4l2_ext_controls32(file, &karg.v2ecs, up); compatible_arg = 0; break; case VIDIOC_DQEVENT: @@ -911,7 +930,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - if (put_v4l2_ext_controls32(&karg.v2ecs, up)) + if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) err = -EFAULT; break; }
From: Hans Verkuil hansverk@cisco.com
commit 273caa260035c03d89ad63d72d8cd3d9e5c5e3f1 upstream.
If the device is of type VFL_TYPE_SUBDEV then vdev->ioctl_ops is NULL so the 'if (!ops->vidioc_query_ext_ctrl)' check would crash. Add a test for !ops to the condition.
All sub-devices that have controls will use the control framework, so they do not have an equivalent to ops->vidioc_query_ext_ctrl. Returning false if ops is NULL is the correct thing to do here.
Fixes: b8c601e8af ("v4l2-compat-ioctl32.c: fix ctrl_is_pointer")
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Reported-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index c78462e79a0a..bd4890769e0b 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -600,7 +600,7 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) return ctrl && ctrl->is_ptr; }
- if (!ops->vidioc_query_ext_ctrl) + if (!ops || !ops->vidioc_query_ext_ctrl) return false;
return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
From: Daniel Mentz danielmentz@google.com
commit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream.
Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output overlays.") added the field global_alpha to struct v4l2_window but did not update the compat layer accordingly. This change adds global_alpha to struct v4l2_window32 and copies the value for global_alpha back and forth.
Signed-off-by: Daniel Mentz danielmentz@google.com Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index bd4890769e0b..fd32c9ccc2bb 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -45,6 +45,7 @@ struct v4l2_window32 { compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; compat_caddr_t bitmap; + __u8 global_alpha; };
static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) @@ -53,7 +54,8 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user copy_from_user(&kp->w, &up->w, sizeof(up->w)) || get_user(kp->field, &up->field) || get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount)) + get_user(kp->clipcount, &up->clipcount) || + get_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; @@ -86,7 +88,8 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || put_user(kp->field, &up->field) || put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount)) + put_user(kp->clipcount, &up->clipcount) || + put_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; return 0; }
From: Hans Verkuil hans.verkuil@cisco.com
commit a751be5b142ef6bcbbb96d9899516f4d9c8d0ef4 upstream.
put_v4l2_window32() didn't copy back the clip list to userspace. Drivers can update the clip rectangles, so this should be done.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 61 ++++++++++++++++++--------- 1 file changed, 41 insertions(+), 20 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index fd32c9ccc2bb..8a5c93ce4348 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -50,6 +50,11 @@ struct v4l2_window32 {
static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { + struct v4l2_clip32 __user *uclips; + struct v4l2_clip __user *kclips; + compat_caddr_t p; + u32 n; + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(&kp->w, &up->w, sizeof(up->w)) || get_user(kp->field, &up->field) || @@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; - if (kp->clipcount) { - struct v4l2_clip32 __user *uclips; - struct v4l2_clip __user *kclips; - int n = kp->clipcount; - compat_caddr_t p; - - if (get_user(p, &up->clips)) - return -EFAULT; - uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(*kclips)); - kp->clips = kclips; - while (--n >= 0) { - if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, &kclips->next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else + if (!kp->clipcount) { kp->clips = NULL; + return 0; + } + + n = kp->clipcount; + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (n--) { + if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) + return -EFAULT; + if (put_user(n ? kclips + 1 : NULL, &kclips->next)) + return -EFAULT; + uclips++; + kclips++; + } return 0; }
static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { + struct v4l2_clip __user *kclips = kp->clips; + struct v4l2_clip32 __user *uclips; + u32 n = kp->clipcount; + compat_caddr_t p; + if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || put_user(kp->field, &up->field) || put_user(kp->chromakey, &up->chromakey) || put_user(kp->clipcount, &up->clipcount) || put_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; + + if (!kp->clipcount) + return 0; + + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); + while (n--) { + if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) + return -EFAULT; + uclips++; + kclips++; + } return 0; }
From: Hans Verkuil hans.verkuil@cisco.com
commit 169f24ca68bf0f247d111aef07af00dd3a02ae88 upstream.
There is nothing wrong with using an unknown buffer type. So stop spamming the kernel log whenever this happens. The kernel will just return -EINVAL to signal this.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 8a5c93ce4348..a5f74a508f58 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -170,8 +170,6 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } @@ -214,8 +212,6 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced, sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } }
From: Hans Verkuil hans.verkuil@cisco.com
commit d83a8243aaefe62ace433e4384a4f077bed86acb upstream.
Some ioctls need to copy back the result even if the ioctl returned an error. However, don't do this for the error code -ENOTTY. It makes no sense in that cases.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index a5f74a508f58..9e5807842dad 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -943,6 +943,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar set_fs(old_fs); }
+ if (err == -ENOTTY) + return err; + /* Special case: even after an error we need to put the results back for these ioctls since the error_idx will contain information on which control failed. */
From: Daniel Mentz danielmentz@google.com
commit a1dfb4c48cc1e64eeb7800a27c66a6f7e88d075a upstream.
The 32-bit compat v4l2 ioctl handling is implemented based on its 64-bit equivalent. It converts 32-bit data structures into its 64-bit equivalents and needs to provide the data to the 64-bit ioctl in user space memory which is commonly allocated using compat_alloc_user_space().
However, due to how that function is implemented, it can only be called a single time for every syscall invocation.
Supposedly to avoid this limitation, the existing code uses a mix of memory from the kernel stack and memory allocated through compat_alloc_user_space().
Under normal circumstances, this would not work, because the 64-bit ioctl expects all pointers to point to user space memory. As a workaround, set_fs(KERNEL_DS) is called to temporarily disable this extra safety check and allow kernel pointers. However, this might introduce a security vulnerability: The result of the 32-bit to 64-bit conversion is writeable by user space because the output buffer has been allocated via compat_alloc_user_space(). A malicious user space process could then manipulate pointers inside this output buffer, and due to the previous set_fs(KERNEL_DS) call, functions like get_user() or put_user() no longer prevent kernel memory access.
The new approach is to pre-calculate the total amount of user space memory that is needed, allocate it using compat_alloc_user_space() and then divide up the allocated memory to accommodate all data structures that need to be converted.
An alternative approach would have been to retain the union type karg that they allocated on the kernel stack in do_video_ioctl(), copy all data from user space into karg and then back to user space. However, we decided against this approach because it does not align with other compat syscall implementations. Instead, we tried to replicate the get_user/put_user pairs as found in other places in the kernel:
if (get_user(clipcount, &up->clipcount) || put_user(clipcount, &kp->clipcount)) return -EFAULT;
Notes from hans.verkuil@cisco.com:
This patch was taken from: https://github.com/LineageOS/android_kernel_samsung_apq8084/commit/97b733953...
Clearly nobody could be bothered to upstream this patch or at minimum tell us :-( We only heard about this a week ago.
This patch was rebased and cleaned up. Compared to the original I also swapped the order of the convert_in_user arguments so that they matched copy_in_user. It was hard to review otherwise. I also replaced the ALLOC_USER_SPACE/ALLOC_AND_GET by a normal function.
Fixes: 6b5a9492ca ("v4l: introduce string control support.")
Signed-off-by: Daniel Mentz danielmentz@google.com Co-developed-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 747 +++++++++++++++++--------- 1 file changed, 486 insertions(+), 261 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 9e5807842dad..e03aa0961360 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -22,6 +22,14 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-ioctl.h>
+/* Use the same argument order as copy_in_user */ +#define assign_in_user(to, from) \ +({ \ + typeof(*from) __assign_tmp; \ + \ + get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \ +}) + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = -ENOIOCTLCMD; @@ -35,12 +43,12 @@ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct v4l2_clip32 { struct v4l2_rect c; - compat_caddr_t next; + compat_caddr_t next; };
struct v4l2_window32 { struct v4l2_rect w; - __u32 field; /* enum v4l2_field */ + __u32 field; /* enum v4l2_field */ __u32 chromakey; compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; @@ -48,37 +56,41 @@ struct v4l2_window32 { __u8 global_alpha; };
-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +static int get_v4l2_window32(struct v4l2_window __user *kp, + struct v4l2_window32 __user *up, + void __user *aux_buf, u32 aux_space) { struct v4l2_clip32 __user *uclips; struct v4l2_clip __user *kclips; compat_caddr_t p; - u32 n; + u32 clipcount;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - copy_from_user(&kp->w, &up->w, sizeof(up->w)) || - get_user(kp->field, &up->field) || - get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount) || - get_user(kp->global_alpha, &up->global_alpha)) + copy_in_user(&kp->w, &up->w, sizeof(up->w)) || + assign_in_user(&kp->field, &up->field) || + assign_in_user(&kp->chromakey, &up->chromakey) || + assign_in_user(&kp->global_alpha, &up->global_alpha) || + get_user(clipcount, &up->clipcount) || + put_user(clipcount, &kp->clipcount)) return -EFAULT; - if (kp->clipcount > 2048) + if (clipcount > 2048) return -EINVAL; - if (!kp->clipcount) { - kp->clips = NULL; - return 0; - } + if (!clipcount) + return put_user(NULL, &kp->clips);
- n = kp->clipcount; if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(*kclips)); - kp->clips = kclips; - while (n--) { + if (aux_space < clipcount * sizeof(*kclips)) + return -EFAULT; + kclips = aux_buf; + if (put_user(kclips, &kp->clips)) + return -EFAULT; + + while (clipcount--) { if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, &kclips->next)) + if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next)) return -EFAULT; uclips++; kclips++; @@ -86,27 +98,28 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return 0; }
-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +static int put_v4l2_window32(struct v4l2_window __user *kp, + struct v4l2_window32 __user *up) { struct v4l2_clip __user *kclips = kp->clips; struct v4l2_clip32 __user *uclips; - u32 n = kp->clipcount; compat_caddr_t p; + u32 clipcount;
- if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || - put_user(kp->field, &up->field) || - put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount) || - put_user(kp->global_alpha, &up->global_alpha)) + if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) || + assign_in_user(&up->field, &kp->field) || + assign_in_user(&up->chromakey, &kp->chromakey) || + assign_in_user(&up->global_alpha, &kp->global_alpha) || + get_user(clipcount, &kp->clipcount) || + put_user(clipcount, &up->clipcount)) return -EFAULT; - - if (!kp->clipcount) + if (!clipcount) return 0;
if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); - while (n--) { + while (clipcount--) { if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) return -EFAULT; uclips++; @@ -144,90 +157,150 @@ struct v4l2_create_buffers32 { __u32 reserved[8]; };
-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) { - if (get_user(kp->type, &up->type)) + u32 type; + + if (get_user(type, &up->type)) + return -EFAULT; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { + u32 clipcount; + + if (get_user(clipcount, &up->fmt.win.clipcount)) + return -EFAULT; + if (clipcount > 2048) + return -EINVAL; + *size = clipcount * sizeof(struct v4l2_clip); + return 0; + } + default: + *size = 0; + return 0; + } +} + +static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) +{ + if (!access_ok(VERIFY_READ, up, sizeof(*up))) + return -EFAULT; + return __bufsize_v4l2_format(up, size); +} + +static int __get_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up, + void __user *aux_buf, u32 aux_space) +{ + u32 type; + + if (get_user(type, &up->type) || put_user(type, &kp->type)) return -EFAULT;
- switch (kp->type) { + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return copy_from_user(&kp->fmt.pix, &up->fmt.pix, - sizeof(kp->fmt.pix)) ? -EFAULT : 0; + return copy_in_user(&kp->fmt.pix, &up->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, - sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); + return get_v4l2_window32(&kp->fmt.win, &up->fmt.win, + aux_buf, aux_space); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi, - sizeof(kp->fmt.vbi)) ? -EFAULT : 0; + return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, - sizeof(kp->fmt.sliced)) ? -EFAULT : 0; + return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: return -EINVAL; } }
-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int get_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up, + void __user *aux_buf, u32 aux_space) { if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; - return __get_v4l2_format32(kp, up); + return __get_v4l2_format32(kp, up, aux_buf, aux_space); }
-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up, + u32 *size) +{ + if (!access_ok(VERIFY_READ, up, sizeof(*up))) + return -EFAULT; + return __bufsize_v4l2_format(&up->format, size); +} + +static int get_v4l2_create32(struct v4l2_create_buffers __user *kp, + struct v4l2_create_buffers32 __user *up, + void __user *aux_buf, u32 aux_space) { if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) + copy_in_user(kp, up, + offsetof(struct v4l2_create_buffers32, format))) return -EFAULT; - return __get_v4l2_format32(&kp->format, &up->format); + return __get_v4l2_format32(&kp->format, &up->format, + aux_buf, aux_space); }
-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int __put_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up) { - switch (kp->type) { + u32 type; + + if (get_user(type, &kp->type)) + return -EFAULT; + + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return copy_to_user(&up->fmt.pix, &kp->fmt.pix, - sizeof(kp->fmt.pix)) ? -EFAULT : 0; + return copy_in_user(&up->fmt.pix, &kp->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, - sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi, - sizeof(kp->fmt.vbi)) ? -EFAULT : 0; + return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced, - sizeof(kp->fmt.sliced)) ? -EFAULT : 0; + return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: return -EINVAL; } }
-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int put_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; return __put_v4l2_format32(kp, up); }
-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +static int put_v4l2_create32(struct v4l2_create_buffers __user *kp, + struct v4l2_create_buffers32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || - copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + copy_in_user(up, kp, + offsetof(struct v4l2_create_buffers32, format)) || + copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return __put_v4l2_format32(&kp->format, &up->format); } @@ -241,24 +314,27 @@ struct v4l2_standard32 { __u32 reserved[4]; };
-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +static int get_v4l2_standard32(struct v4l2_standard __user *kp, + struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->index, &up->index)) + assign_in_user(&kp->index, &up->index)) return -EFAULT; return 0; }
-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +static int put_v4l2_standard32(struct v4l2_standard __user *kp, + struct v4l2_standard32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->index, &up->index) || - copy_to_user(up->id, &kp->id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, sizeof(up->name)) || - copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + assign_in_user(&up->index, &kp->index) || + copy_in_user(&up->id, &kp->id, sizeof(up->id)) || + copy_in_user(up->name, kp->name, sizeof(up->name)) || + copy_in_user(&up->frameperiod, &kp->frameperiod, + sizeof(up->frameperiod)) || + assign_in_user(&up->framelines, &kp->framelines) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } @@ -298,11 +374,11 @@ struct v4l2_buffer32 { __u32 reserved; };
-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, +static int get_v4l2_plane32(struct v4l2_plane __user *up, + struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { - void __user *up_pln; - compat_long_t p; + compat_ulong_t p;
if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(&up->data_offset, &up32->data_offset, @@ -317,10 +393,8 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ return -EFAULT; break; case V4L2_MEMORY_USERPTR: - if (get_user(p, &up32->m.userptr)) - return -EFAULT; - up_pln = compat_ptr(p); - if (put_user((unsigned long)up_pln, &up->m.userptr)) + if (get_user(p, &up32->m.userptr) || + put_user((unsigned long)compat_ptr(p), &up->m.userptr)) return -EFAULT; break; case V4L2_MEMORY_DMABUF: @@ -332,7 +406,8 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ return 0; }
-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, +static int put_v4l2_plane32(struct v4l2_plane __user *up, + struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { unsigned long p; @@ -356,8 +431,7 @@ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ return -EFAULT; break; case V4L2_MEMORY_DMABUF: - if (copy_in_user(&up32->m.fd, &up->m.fd, - sizeof(up->m.fd))) + if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd))) return -EFAULT; break; } @@ -365,37 +439,75 @@ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ return 0; }
-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size) { + u32 type; + u32 length; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(type, &up->type) || + get_user(length, &up->length)) + return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + if (length > VIDEO_MAX_PLANES) + return -EINVAL; + + /* + * We don't really care if userspace decides to kill itself + * by passing a very big length value + */ + *size = length * sizeof(struct v4l2_plane); + } else { + *size = 0; + } + return 0; +} + +static int get_v4l2_buffer32(struct v4l2_buffer __user *kp, + struct v4l2_buffer32 __user *up, + void __user *aux_buf, u32 aux_space) +{ + u32 type; + u32 length; + enum v4l2_memory memory; struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; - int num_planes; int ret;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->index, &up->index) || - get_user(kp->type, &up->type) || - get_user(kp->flags, &up->flags) || - get_user(kp->memory, &up->memory) || - get_user(kp->length, &up->length)) + assign_in_user(&kp->index, &up->index) || + get_user(type, &up->type) || + put_user(type, &kp->type) || + assign_in_user(&kp->flags, &up->flags) || + get_user(memory, &up->memory) || + put_user(memory, &kp->memory) || + get_user(length, &up->length) || + put_user(length, &kp->length)) return -EFAULT;
- if (V4L2_TYPE_IS_OUTPUT(kp->type)) - if (get_user(kp->bytesused, &up->bytesused) || - get_user(kp->field, &up->field) || - get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec)) + if (V4L2_TYPE_IS_OUTPUT(type)) + if (assign_in_user(&kp->bytesused, &up->bytesused) || + assign_in_user(&kp->field, &up->field) || + assign_in_user(&kp->timestamp.tv_sec, + &up->timestamp.tv_sec) || + assign_in_user(&kp->timestamp.tv_usec, + &up->timestamp.tv_usec)) return -EFAULT;
- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + u32 num_planes = length; + if (num_planes == 0) { - kp->m.planes = NULL; - /* num_planes == 0 is legal, e.g. when userspace doesn't - * need planes array on DQBUF*/ - return 0; + /* + * num_planes == 0 is legal, e.g. when userspace doesn't + * need planes array on DQBUF + */ + return put_user(NULL, &kp->m.planes); } + if (num_planes > VIDEO_MAX_PLANES) + return -EINVAL;
if (get_user(p, &up->m.planes)) return -EFAULT; @@ -405,37 +517,43 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user num_planes * sizeof(*uplane32))) return -EFAULT;
- /* We don't really care if userspace decides to kill itself - * by passing a very big num_planes value */ - uplane = compat_alloc_user_space(num_planes * sizeof(*uplane)); - kp->m.planes = (__force struct v4l2_plane *)uplane; + /* + * We don't really care if userspace decides to kill itself + * by passing a very big num_planes value + */ + if (aux_space < num_planes * sizeof(*uplane)) + return -EFAULT;
- while (--num_planes >= 0) { - ret = get_v4l2_plane32(uplane, uplane32, kp->memory); + uplane = aux_buf; + if (put_user((__force struct v4l2_plane *)uplane, + &kp->m.planes)) + return -EFAULT; + + while (num_planes--) { + ret = get_v4l2_plane32(uplane, uplane32, memory); if (ret) return ret; - ++uplane; - ++uplane32; + uplane++; + uplane32++; } } else { - switch (kp->memory) { + switch (memory) { case V4L2_MEMORY_MMAP: case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, &up->m.offset)) + if (assign_in_user(&kp->m.offset, &up->m.offset)) return -EFAULT; break; - case V4L2_MEMORY_USERPTR: - { - compat_long_t tmp; + case V4L2_MEMORY_USERPTR: { + compat_ulong_t userptr;
- if (get_user(tmp, &up->m.userptr)) - return -EFAULT; - - kp->m.userptr = (unsigned long)compat_ptr(tmp); - } + if (get_user(userptr, &up->m.userptr) || + put_user((unsigned long)compat_ptr(userptr), + &kp->m.userptr)) + return -EFAULT; break; + } case V4L2_MEMORY_DMABUF: - if (get_user(kp->m.fd, &up->m.fd)) + if (assign_in_user(&kp->m.fd, &up->m.fd)) return -EFAULT; break; } @@ -444,62 +562,70 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user return 0; }
-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +static int put_v4l2_buffer32(struct v4l2_buffer __user *kp, + struct v4l2_buffer32 __user *up) { + u32 type; + u32 length; + enum v4l2_memory memory; struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; - int num_planes; int ret;
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->index, &up->index) || - put_user(kp->type, &up->type) || - put_user(kp->flags, &up->flags) || - put_user(kp->memory, &up->memory)) + assign_in_user(&up->index, &kp->index) || + get_user(type, &kp->type) || + put_user(type, &up->type) || + assign_in_user(&up->flags, &kp->flags) || + get_user(memory, &kp->memory) || + put_user(memory, &up->memory)) return -EFAULT;
- if (put_user(kp->bytesused, &up->bytesused) || - put_user(kp->field, &up->field) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->reserved2, &up->reserved2) || - put_user(kp->reserved, &up->reserved) || - put_user(kp->length, &up->length)) + if (assign_in_user(&up->bytesused, &kp->bytesused) || + assign_in_user(&up->field, &kp->field) || + assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || + assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) || + copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || + assign_in_user(&up->sequence, &kp->sequence) || + assign_in_user(&up->reserved2, &kp->reserved2) || + assign_in_user(&up->reserved, &kp->reserved) || + get_user(length, &kp->length) || + put_user(length, &up->length)) return -EFAULT;
- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + u32 num_planes = length; + if (num_planes == 0) return 0;
- uplane = (__force struct v4l2_plane __user *)kp->m.planes; + if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes))) + return -EFAULT; if (get_user(p, &up->m.planes)) return -EFAULT; uplane32 = compat_ptr(p);
- while (--num_planes >= 0) { - ret = put_v4l2_plane32(uplane, uplane32, kp->memory); + while (num_planes--) { + ret = put_v4l2_plane32(uplane, uplane32, memory); if (ret) return ret; ++uplane; ++uplane32; } } else { - switch (kp->memory) { + switch (memory) { case V4L2_MEMORY_MMAP: case V4L2_MEMORY_OVERLAY: - if (put_user(kp->m.offset, &up->m.offset)) + if (assign_in_user(&up->m.offset, &kp->m.offset)) return -EFAULT; break; case V4L2_MEMORY_USERPTR: - if (put_user(kp->m.userptr, &up->m.userptr)) + if (assign_in_user(&up->m.userptr, &kp->m.userptr)) return -EFAULT; break; case V4L2_MEMORY_DMABUF: - if (put_user(kp->m.fd, &up->m.fd)) + if (assign_in_user(&up->m.fd, &kp->m.fd)) return -EFAULT; break; } @@ -511,7 +637,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user struct v4l2_framebuffer32 { __u32 capability; __u32 flags; - compat_caddr_t base; + compat_caddr_t base; struct { __u32 width; __u32 height; @@ -524,29 +650,32 @@ struct v4l2_framebuffer32 { } fmt; };
-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, + struct v4l2_framebuffer32 __user *up) { - u32 tmp; + compat_caddr_t tmp;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(tmp, &up->base) || - get_user(kp->capability, &up->capability) || - get_user(kp->flags, &up->flags) || - copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) + put_user((__force void *)compat_ptr(tmp), &kp->base) || + assign_in_user(&kp->capability, &up->capability) || + assign_in_user(&kp->flags, &up->flags) || + copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt))) return -EFAULT; - kp->base = (__force void *)compat_ptr(tmp); return 0; }
-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, + struct v4l2_framebuffer32 __user *up) { - u32 tmp = (u32)((unsigned long)kp->base); + void *base;
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(tmp, &up->base) || - put_user(kp->capability, &up->capability) || - put_user(kp->flags, &up->flags) || - copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) + get_user(base, &kp->base) || + put_user(ptr_to_compat(base), &up->base) || + assign_in_user(&up->capability, &kp->capability) || + assign_in_user(&up->flags, &kp->flags) || + copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt))) return -EFAULT; return 0; } @@ -559,21 +688,26 @@ struct v4l2_input32 { __u32 tuner; /* Associated tuner */ v4l2_std_id std; __u32 status; - __u32 reserved[4]; -} __attribute__ ((packed)); + __u32 capabilities; + __u32 reserved[3]; +};
-/* 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 *kp, struct v4l2_input32 __user *up) +/* + * 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 *kp, + struct v4l2_input32 __user *up) { - if (copy_from_user(kp, up, sizeof(*up))) + if (copy_in_user(kp, up, sizeof(*up))) return -EFAULT; return 0; }
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) +static inline int put_v4l2_input32(struct v4l2_input __user *kp, + struct v4l2_input32 __user *up) { - if (copy_to_user(up, kp, sizeof(*up))) + if (copy_in_user(up, kp, sizeof(*up))) return -EFAULT; return 0; } @@ -627,40 +761,64 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); }
+static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up, + u32 *size) +{ + u32 count; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(count, &up->count)) + return -EFAULT; + if (count > V4L2_CID_MAX_CTRLS) + return -EINVAL; + *size = count * sizeof(struct v4l2_ext_control); + return 0; +} + static int get_v4l2_ext_controls32(struct file *file, - struct v4l2_ext_controls *kp, - struct v4l2_ext_controls32 __user *up) + struct v4l2_ext_controls __user *kp, + struct v4l2_ext_controls32 __user *up, + void __user *aux_buf, u32 aux_space) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; - int n; + u32 count; + u32 n; compat_caddr_t p;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->ctrl_class, &up->ctrl_class) || - get_user(kp->count, &up->count) || - get_user(kp->error_idx, &up->error_idx) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + assign_in_user(&kp->ctrl_class, &up->ctrl_class) || + get_user(count, &up->count) || + put_user(count, &kp->count) || + assign_in_user(&kp->error_idx, &up->error_idx) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - n = kp->count; - if (n == 0) { - kp->controls = NULL; - return 0; - } + + if (count == 0) + return put_user(NULL, &kp->controls); + if (count > V4L2_CID_MAX_CTRLS) + return -EINVAL; if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols))) + if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols))) return -EFAULT; - kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols)); - kp->controls = (__force struct v4l2_ext_control *)kcontrols; - while (--n >= 0) { + if (aux_space < count * sizeof(*kcontrols)) + return -EFAULT; + kcontrols = aux_buf; + if (put_user((__force struct v4l2_ext_control *)kcontrols, + &kp->controls)) + return -EFAULT; + + for (n = 0; n < count; n++) { u32 id;
if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) return -EFAULT; + if (get_user(id, &kcontrols->id)) return -EFAULT; + if (ctrl_is_pointer(file, id)) { void __user *s;
@@ -677,43 +835,54 @@ static int get_v4l2_ext_controls32(struct file *file, }
static int put_v4l2_ext_controls32(struct file *file, - struct v4l2_ext_controls *kp, + struct v4l2_ext_controls __user *kp, struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control __user *kcontrols = - (__force struct v4l2_ext_control __user *)kp->controls; - int n = kp->count; + struct v4l2_ext_control __user *kcontrols; + u32 count; + u32 n; compat_caddr_t p;
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->ctrl_class, &up->ctrl_class) || - put_user(kp->count, &up->count) || - put_user(kp->error_idx, &up->error_idx) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + assign_in_user(&up->ctrl_class, &kp->ctrl_class) || + get_user(count, &kp->count) || + put_user(count, &up->count) || + assign_in_user(&up->error_idx, &kp->error_idx) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) || + get_user(kcontrols, &kp->controls)) return -EFAULT; - if (!kp->count) + + if (!count) return 0; - if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols))) + if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols))) return -EFAULT;
- while (--n >= 0) { - unsigned size = sizeof(*ucontrols); + for (n = 0; n < count; n++) { + unsigned int size = sizeof(*ucontrols); u32 id;
- if (get_user(id, &kcontrols->id)) + if (get_user(id, &kcontrols->id) || + put_user(id, &ucontrols->id) || + assign_in_user(&ucontrols->size, &kcontrols->size) || + copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2, + sizeof(ucontrols->reserved2))) return -EFAULT; - /* Do not modify the pointer when copying a pointer control. - The contents of the pointer was changed, not the pointer - itself. */ + + /* + * Do not modify the pointer when copying a pointer control. + * The contents of the pointer was changed, not the pointer + * itself. + */ if (ctrl_is_pointer(file, id)) size -= sizeof(ucontrols->value64); + if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; + ucontrols++; kcontrols++; } @@ -732,17 +901,18 @@ struct v4l2_event32 { __u32 reserved[8]; };
-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) +static int put_v4l2_event32(struct v4l2_event __user *kp, + struct v4l2_event32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->type, &up->type) || - copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || - put_user(kp->pending, &up->pending) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || - put_user(kp->id, &up->id) || - copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + assign_in_user(&up->type, &kp->type) || + copy_in_user(&up->u, &kp->u, sizeof(kp->u)) || + assign_in_user(&up->pending, &kp->pending) || + assign_in_user(&up->sequence, &kp->sequence) || + assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || + assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) || + assign_in_user(&up->id, &kp->id) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } @@ -755,31 +925,34 @@ struct v4l2_edid32 { compat_caddr_t edid; };
-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) +static int get_v4l2_edid32(struct v4l2_edid __user *kp, + struct v4l2_edid32 __user *up) { - u32 tmp; + compat_uptr_t tmp;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->pad, &up->pad) || - get_user(kp->start_block, &up->start_block) || - get_user(kp->blocks, &up->blocks) || + assign_in_user(&kp->pad, &up->pad) || + assign_in_user(&kp->start_block, &up->start_block) || + assign_in_user(&kp->blocks, &up->blocks) || get_user(tmp, &up->edid) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + put_user(compat_ptr(tmp), &kp->edid) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - kp->edid = (__force u8 *)compat_ptr(tmp); return 0; }
-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) +static int put_v4l2_edid32(struct v4l2_edid __user *kp, + struct v4l2_edid32 __user *up) { - u32 tmp = (u32)((unsigned long)kp->edid); + void *edid;
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->pad, &up->pad) || - put_user(kp->start_block, &up->start_block) || - put_user(kp->blocks, &up->blocks) || - put_user(tmp, &up->edid) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + assign_in_user(&up->pad, &kp->pad) || + assign_in_user(&up->start_block, &kp->start_block) || + assign_in_user(&up->blocks, &kp->blocks) || + get_user(edid, &kp->edid) || + put_user(ptr_to_compat(edid), &up->edid) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } @@ -796,7 +969,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) #define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32) #define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32) -#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) +#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) @@ -812,22 +985,23 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32) #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
+static int alloc_userspace(unsigned int size, u32 aux_space, + void __user **up_native) +{ + *up_native = compat_alloc_user_space(size + aux_space); + if (!*up_native) + return -ENOMEM; + if (clear_user(*up_native, size)) + return -EFAULT; + return 0; +} + static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - union { - struct v4l2_format v2f; - struct v4l2_buffer v2b; - struct v4l2_framebuffer v2fb; - struct v4l2_input v2i; - struct v4l2_standard v2s; - struct v4l2_ext_controls v2ecs; - struct v4l2_event v2ev; - struct v4l2_create_buffers v2crt; - struct v4l2_edid v2edid; - unsigned long vx; - int vi; - } karg; void __user *up = compat_ptr(arg); + void __user *up_native = NULL; + void __user *aux_buf; + u32 aux_space; int compatible_arg = 1; long err = 0;
@@ -866,30 +1040,52 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_STREAMOFF: case VIDIOC_S_INPUT: case VIDIOC_S_OUTPUT: - err = get_user(karg.vi, (s32 __user *)up); + err = alloc_userspace(sizeof(unsigned int), 0, &up_native); + if (!err && assign_in_user((unsigned int __user *)up_native, + (compat_uint_t __user *)up)) + err = -EFAULT; compatible_arg = 0; break;
case VIDIOC_G_INPUT: case VIDIOC_G_OUTPUT: + err = alloc_userspace(sizeof(unsigned int), 0, &up_native); compatible_arg = 0; break;
case VIDIOC_G_EDID: case VIDIOC_S_EDID: - err = get_v4l2_edid32(&karg.v2edid, up); + err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native); + if (!err) + err = get_v4l2_edid32(up_native, up); compatible_arg = 0; break;
case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: - err = get_v4l2_format32(&karg.v2f, up); + err = bufsize_v4l2_format(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_format), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_format); + err = get_v4l2_format32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break;
case VIDIOC_CREATE_BUFS: - err = get_v4l2_create32(&karg.v2crt, up); + err = bufsize_v4l2_create(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_create_buffers), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_create_buffers); + err = get_v4l2_create32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break;
@@ -897,36 +1093,63 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: - err = get_v4l2_buffer32(&karg.v2b, up); + err = bufsize_v4l2_buffer(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_buffer), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_buffer); + err = get_v4l2_buffer32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break;
case VIDIOC_S_FBUF: - err = get_v4l2_framebuffer32(&karg.v2fb, up); + err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, + &up_native); + if (!err) + err = get_v4l2_framebuffer32(up_native, up); compatible_arg = 0; break;
case VIDIOC_G_FBUF: + err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, + &up_native); compatible_arg = 0; break;
case VIDIOC_ENUMSTD: - err = get_v4l2_standard32(&karg.v2s, up); + err = alloc_userspace(sizeof(struct v4l2_standard), 0, + &up_native); + if (!err) + err = get_v4l2_standard32(up_native, up); compatible_arg = 0; break;
case VIDIOC_ENUMINPUT: - err = get_v4l2_input32(&karg.v2i, up); + err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native); + if (!err) + err = get_v4l2_input32(up_native, up); compatible_arg = 0; break;
case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(file, &karg.v2ecs, up); + err = bufsize_v4l2_ext_controls(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_ext_controls), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_ext_controls); + err = get_v4l2_ext_controls32(file, up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break; case VIDIOC_DQEVENT: + err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native); compatible_arg = 0; break; } @@ -935,25 +1158,26 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
if (compatible_arg) err = native_ioctl(file, cmd, (unsigned long)up); - else { - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - err = native_ioctl(file, cmd, (unsigned long)&karg); - set_fs(old_fs); - } + else + err = native_ioctl(file, cmd, (unsigned long)up_native);
if (err == -ENOTTY) return err;
- /* Special case: even after an error we need to put the - results back for these ioctls since the error_idx will - contain information on which control failed. */ + /* + * Special case: even after an error we need to put the + * results back for these ioctls since the error_idx will + * contain information on which control failed. + */ switch (cmd) { case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) + if (put_v4l2_ext_controls32(file, up_native, up)) + err = -EFAULT; + break; + case VIDIOC_S_EDID: + if (put_v4l2_edid32(up_native, up)) err = -EFAULT; break; } @@ -965,45 +1189,46 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_S_OUTPUT: case VIDIOC_G_INPUT: case VIDIOC_G_OUTPUT: - err = put_user(((s32)karg.vi), (s32 __user *)up); + if (assign_in_user((compat_uint_t __user *)up, + ((unsigned int __user *)up_native))) + err = -EFAULT; break;
case VIDIOC_G_FBUF: - err = put_v4l2_framebuffer32(&karg.v2fb, up); + err = put_v4l2_framebuffer32(up_native, up); break;
case VIDIOC_DQEVENT: - err = put_v4l2_event32(&karg.v2ev, up); + err = put_v4l2_event32(up_native, up); break;
case VIDIOC_G_EDID: - case VIDIOC_S_EDID: - err = put_v4l2_edid32(&karg.v2edid, up); + err = put_v4l2_edid32(up_native, up); break;
case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: - err = put_v4l2_format32(&karg.v2f, up); + err = put_v4l2_format32(up_native, up); break;
case VIDIOC_CREATE_BUFS: - err = put_v4l2_create32(&karg.v2crt, up); + err = put_v4l2_create32(up_native, up); break;
case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: - err = put_v4l2_buffer32(&karg.v2b, up); + err = put_v4l2_buffer32(up_native, up); break;
case VIDIOC_ENUMSTD: - err = put_v4l2_standard32(&karg.v2s, up); + err = put_v4l2_standard32(up_native, up); break;
case VIDIOC_ENUMINPUT: - err = put_v4l2_input32(&karg.v2i, up); + err = put_v4l2_input32(up_native, up); break; } return err;
From: Hans Verkuil hans.verkuil@cisco.com
The warning is simple:
drivers/media/v4l2-core/v4l2-ctrls.c:1685:15: warning: incorrect type in assignment (different address spaces)
but the fix isn't.
The core problem was that the conversion from user to kernelspace was done at too low a level and that needed to be moved up. That made it possible to drop pointers to v4l2_ext_control from set_ctrl and validate_new and clean up this sparse warning because those functions now always operate on kernelspace pointers.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Signed-off-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com --- drivers/media/v4l2-core/v4l2-ctrls.c | 87 +++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 35 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 7905ad9ffa35..3c4e22855652 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1668,10 +1668,8 @@ static int check_range(enum v4l2_ctrl_type type, }
/* Validate a new control */ -static int validate_new(const struct v4l2_ctrl *ctrl, - struct v4l2_ext_control *c) +static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) { - union v4l2_ctrl_ptr ptr; unsigned idx; int err = 0;
@@ -1684,19 +1682,14 @@ static int validate_new(const struct v4l2_ctrl *ctrl, case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BUTTON: case V4L2_CTRL_TYPE_CTRL_CLASS: - ptr.p_s32 = &c->value; - return ctrl->type_ops->validate(ctrl, 0, ptr); - case V4L2_CTRL_TYPE_INTEGER64: - ptr.p_s64 = &c->value64; - return ctrl->type_ops->validate(ctrl, 0, ptr); + return ctrl->type_ops->validate(ctrl, 0, p_new); default: break; } } - ptr.p = c->ptr; - for (idx = 0; !err && idx < c->size / ctrl->elem_size; idx++) - err = ctrl->type_ops->validate(ctrl, idx, ptr); + for (idx = 0; !err && idx < ctrl->elems; idx++) + err = ctrl->type_ops->validate(ctrl, idx, p_new); return err; }
@@ -3020,6 +3013,7 @@ static int validate_ctrls(struct v4l2_ext_controls *cs, cs->error_idx = cs->count; for (i = 0; i < cs->count; i++) { struct v4l2_ctrl *ctrl = helpers[i].ctrl; + union v4l2_ctrl_ptr p_new;
cs->error_idx = i;
@@ -3033,7 +3027,17 @@ static int validate_ctrls(struct v4l2_ext_controls *cs, best-effort to avoid that. */ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) return -EBUSY; - ret = validate_new(ctrl, &cs->controls[i]); + /* + * Skip validation for now if the payload needs to be copied + * from userspace into kernelspace. We'll validate those later. + */ + if (ctrl->is_ptr) + continue; + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + p_new.p_s64 = &cs->controls[i].value64; + else + p_new.p_s32 = &cs->controls[i].value; + ret = validate_new(ctrl, p_new); if (ret) return ret; } @@ -3128,7 +3132,11 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, /* Copy the new caller-supplied control values. user_to_new() sets 'is_new' to 1. */ do { - ret = user_to_new(cs->controls + idx, helpers[idx].ctrl); + struct v4l2_ctrl *ctrl = helpers[idx].ctrl; + + ret = user_to_new(cs->controls + idx, ctrl); + if (!ret && ctrl->is_ptr) + ret = validate_new(ctrl, ctrl->p_new); idx = helpers[idx].next; } while (!ret && idx);
@@ -3178,10 +3186,10 @@ int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
/* Helper function for VIDIOC_S_CTRL compatibility */ -static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, - struct v4l2_ext_control *c, u32 ch_flags) +static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) { struct v4l2_ctrl *master = ctrl->cluster[0]; + int ret; int i;
/* Reset the 'is_new' flags of the cluster */ @@ -3189,8 +3197,9 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, if (master->cluster[i]) master->cluster[i]->is_new = 0;
- if (c) - user_to_new(c, ctrl); + ret = validate_new(ctrl, ctrl->p_new); + if (ret) + return ret;
/* For autoclusters with volatiles that are switched from auto to manual mode we have to update the current volatile values since @@ -3207,15 +3216,14 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c) { - int ret = validate_new(ctrl, c); + int ret;
- if (!ret) { - v4l2_ctrl_lock(ctrl); - ret = set_ctrl(fh, ctrl, c, 0); - if (!ret) - cur_to_user(c, ctrl); - v4l2_ctrl_unlock(ctrl); - } + v4l2_ctrl_lock(ctrl); + user_to_new(c, ctrl); + ret = set_ctrl(fh, ctrl, 0); + if (!ret) + cur_to_user(c, ctrl); + v4l2_ctrl_unlock(ctrl); return ret; }
@@ -3223,7 +3231,7 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, struct v4l2_control *control) { struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); - struct v4l2_ext_control c; + struct v4l2_ext_control c = { control->id }; int ret;
if (ctrl == NULL || !ctrl->is_int) @@ -3252,7 +3260,7 @@ int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val) /* It's a driver bug if this happens. */ WARN_ON(!ctrl->is_int); ctrl->val = val; - return set_ctrl(NULL, ctrl, NULL, 0); + return set_ctrl(NULL, ctrl, 0); } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl);
@@ -3263,7 +3271,7 @@ int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val) /* It's a driver bug if this happens. */ WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64); *ctrl->p_new.p_s64 = val; - return set_ctrl(NULL, ctrl, NULL, 0); + return set_ctrl(NULL, ctrl, 0); } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64);
@@ -3274,7 +3282,7 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s) /* It's a driver bug if this happens. */ WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING); strlcpy(ctrl->p_new.p_char, s, ctrl->maximum + 1); - return set_ctrl(NULL, ctrl, NULL, 0); + return set_ctrl(NULL, ctrl, 0); } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
@@ -3297,8 +3305,8 @@ EXPORT_SYMBOL(v4l2_ctrl_notify); int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, s64 min, s64 max, u64 step, s64 def) { + bool changed; int ret; - struct v4l2_ext_control c;
lockdep_assert_held(ctrl->handler->lock);
@@ -3325,11 +3333,20 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, ctrl->maximum = max; ctrl->step = step; ctrl->default_value = def; - c.value = *ctrl->p_cur.p_s32; - if (validate_new(ctrl, &c)) - c.value = def; - if (c.value != *ctrl->p_cur.p_s32) - ret = set_ctrl(NULL, ctrl, &c, V4L2_EVENT_CTRL_CH_RANGE); + cur_to_new(ctrl); + if (validate_new(ctrl, ctrl->p_new)) { + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + *ctrl->p_new.p_s64 = def; + else + *ctrl->p_new.p_s32 = def; + } + + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64; + else + changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32; + if (changed) + ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); else send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); return ret;
From: Ricardo Ribalda ricardo.ribalda@gmail.com
Volatile controls should not generate CH_VALUE events.
Set has_changed to false to prevent this happening.
Signed-off-by: Ricardo Ribalda Delgado ricardo.ribalda@gmail.com Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Signed-off-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com --- drivers/media/v4l2-core/v4l2-ctrls.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 3c4e22855652..2bdb2a3512a4 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1619,6 +1619,15 @@ static int cluster_changed(struct v4l2_ctrl *master)
if (ctrl == NULL) continue; + /* + * Set has_changed to false to avoid generating + * the event V4L2_EVENT_CTRL_CH_VALUE + */ + if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { + ctrl->has_changed = false; + continue; + } + for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++) ctrl_changed = !ctrl->type_ops->equal(ctrl, idx, ctrl->p_cur, ctrl->p_new);
Instead of using the "v4l2_std_id" typedef, use compat_u64, as otherwise it fails to properly handle some ioctls.
Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index e03aa0961360..c76438dd3ead 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -686,7 +686,7 @@ struct v4l2_input32 { __u32 type; /* Type of input */ __u32 audioset; /* Associated audios (bitfield) */ __u32 tuner; /* Associated tuner */ - v4l2_std_id std; + compat_u64 std; __u32 status; __u32 capabilities; __u32 reserved[3];
The get_v4l2_create32() function is missing a logic with would be cleaning a reserved field, causing v4l2-compliance to complain:
Buffer ioctls (Input 0): fail: v4l2-test-buffers.cpp(506): check_0(crbufs.reserved, sizeof(crbufs.reserved)) test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: FAIL
Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index c76438dd3ead..ca0a43ad4ec8 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -247,7 +247,8 @@ static int get_v4l2_create32(struct v4l2_create_buffers __user *kp, { if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_in_user(kp, up, - offsetof(struct v4l2_create_buffers32, format))) + offsetof(struct v4l2_create_buffers32, format)) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; return __get_v4l2_format32(&kp->format, &up->format, aux_buf, aux_space);
Hi Mauro,
2018년 03월 29일 03:12에 Mauro Carvalho Chehab 이(가) 쓴 글:
Hi Greg,
Those are the backports meant to solve CVE-2017-13166 on Kernel 3.18.
It contains two v4l2-ctrls fixes that are required to avoid crashes at the test application.
I wrote two patches myself for Kernel 3.18 in order to solve some issues specific for Kernel 3.18 with aren't needed upstream. one is actually a one-line change backport. The other one makes sure that both 32-bits and 64-bits version of some ioctl calls will return the same value for a reserved field.
I noticed an extra bug while testing it, but the bug also hits upstream, and should be backported all the way down all stable/LTS versions. So, I'll send it the usual way, after merging upsream.
Really thanks for doing this. :) There would be many users who use Linux-3.18 for their products yet.
Thanks, Inki Dae
Regards, Mauro
Daniel Mentz (2): media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
Hans Verkuil (12): media: v4l2-ioctl.c: don't copy back the result for -ENOTTY media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF media: v4l2-compat-ioctl32.c: fix the indentation media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 media: v4l2-compat-ioctl32.c: avoid sizeof(type) media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors media: v4l2-ctrls: fix sparse warning
Mauro Carvalho Chehab (2): media: v4l2-compat-ioctl32: use compat_u64 for video standard media: v4l2-compat-ioctl32: initialize a reserved field
Ricardo Ribalda (2): vb2: V4L2_BUF_FLAG_DONE is set after DQBUF media: media/v4l2-ctrls: volatiles should not generate CH_VALUE
drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1020 +++++++++++++++---------- drivers/media/v4l2-core/v4l2-ctrls.c | 96 ++- drivers/media/v4l2-core/v4l2-ioctl.c | 5 +- drivers/media/v4l2-core/videobuf2-core.c | 5 + 4 files changed, 691 insertions(+), 435 deletions(-)
On Thu, Mar 29, 2018 at 08:22:08AM +0900, Inki Dae wrote:
Really thanks for doing this. :) There would be many users who use Linux-3.18 for their products yet.
For new products? They really should not be. The kernel is officially end-of-life, but I'm keeping it alive for a short while longer just because too many people seem to still be using it. However, they are not actually updating the kernel in their devices, so I don't think I will be doing many more new 3.18.y releases.
It's a problem when people ask for support, and then don't use the releases given to them :(
What is keeping you on 3.18.y and not allowing you to move to a newer kernel version?
thanks,
greg k-h
2018년 03월 29일 13:25에 Greg KH 이(가) 쓴 글:
On Thu, Mar 29, 2018 at 08:22:08AM +0900, Inki Dae wrote:
Really thanks for doing this. :) There would be many users who use Linux-3.18 for their products yet.
For new products? They really should not be. The kernel is officially
Really no. Old products would still be using Linux-3.18 kernel without kernel upgrade. For new product, most of SoC vendors will use Linux-4.x including us. Actually, we are preparing for kernel upgrade for some devices even some old devices (to Linux-4.14-LTS) and almost done.
end-of-life, but I'm keeping it alive for a short while longer just because too many people seem to still be using it. However, they are not actually updating the kernel in their devices, so I don't think I will be doing many more new 3.18.y releases.
It's a problem when people ask for support, and then don't use the releases given to them :(
What is keeping you on 3.18.y and not allowing you to move to a newer kernel version?
We also want to move to latest kernel version. However, there is a case that we cannot upgrade the kernel. In case that SoC vendor never share firmwares and relevant data sheets, we cannot upgrade the kernel. However, we have to resolve the security issues for users of this device.
Thanks, Inki Dae
thanks,
greg k-h
On Thu, Mar 29, 2018 at 03:39:54PM +0900, Inki Dae wrote:
2018년 03월 29일 13:25에 Greg KH 이(가) 쓴 글:
On Thu, Mar 29, 2018 at 08:22:08AM +0900, Inki Dae wrote:
Really thanks for doing this. :) There would be many users who use Linux-3.18 for their products yet.
For new products? They really should not be. The kernel is officially
Really no. Old products would still be using Linux-3.18 kernel without kernel upgrade. For new product, most of SoC vendors will use Linux-4.x including us. Actually, we are preparing for kernel upgrade for some devices even some old devices (to Linux-4.14-LTS) and almost done.
That is great to hear.
What is keeping you on 3.18.y and not allowing you to move to a newer kernel version?
We also want to move to latest kernel version. However, there is a case that we cannot upgrade the kernel. In case that SoC vendor never share firmwares and relevant data sheets, we cannot upgrade the kernel. However, we have to resolve the security issues for users of this device.
It sounds like you need to be getting those security updates from those SoC vendors, as they are the ones you are paying for support for that kernel version that they are forcing you to stay on.
good luck!
greg k-h
2018년 03월 29일 16:00에 Greg KH 이(가) 쓴 글:
On Thu, Mar 29, 2018 at 03:39:54PM +0900, Inki Dae wrote:
2018년 03월 29일 13:25에 Greg KH 이(가) 쓴 글:
On Thu, Mar 29, 2018 at 08:22:08AM +0900, Inki Dae wrote:
Really thanks for doing this. :) There would be many users who use Linux-3.18 for their products yet.
For new products? They really should not be. The kernel is officially
Really no. Old products would still be using Linux-3.18 kernel without kernel upgrade. For new product, most of SoC vendors will use Linux-4.x including us. Actually, we are preparing for kernel upgrade for some devices even some old devices (to Linux-4.14-LTS) and almost done.
That is great to hear.
What is keeping you on 3.18.y and not allowing you to move to a newer kernel version?
We also want to move to latest kernel version. However, there is a case that we cannot upgrade the kernel. In case that SoC vendor never share firmwares and relevant data sheets, we cannot upgrade the kernel. However, we have to resolve the security issues for users of this device.
It sounds like you need to be getting those security updates from those SoC vendors, as they are the ones you are paying for support for that
It's true but some open source developers like me who use vendor kernel without vendor's support will never get the security updates from them. So if you merge CVE patches even through this kernel is already EOL then many open source developers would be glad. :)
Thanks, Inki Dae
kernel version that they are forcing you to stay on.
good luck!
greg k-h
Em Thu, 29 Mar 2018 08:22:08 +0900 Inki Dae inki.dae@samsung.com escreveu:
Hi Mauro,
2018년 03월 29일 03:12에 Mauro Carvalho Chehab 이(가) 쓴 글:
Hi Greg,
Those are the backports meant to solve CVE-2017-13166 on Kernel 3.18.
It contains two v4l2-ctrls fixes that are required to avoid crashes at the test application.
I wrote two patches myself for Kernel 3.18 in order to solve some issues specific for Kernel 3.18 with aren't needed upstream. one is actually a one-line change backport. The other one makes sure that both 32-bits and 64-bits version of some ioctl calls will return the same value for a reserved field.
I noticed an extra bug while testing it, but the bug also hits upstream, and should be backported all the way down all stable/LTS versions. So, I'll send it the usual way, after merging upsream.
Really thanks for doing this. :) There would be many users who use Linux-3.18 for their products yet.
Anytime!
Please let me know if you find any issues with those backports.
Regards, Mauro
This is a note to let you know that I've just added the patch titled
media: media/v4l2-ctrls: volatiles should not generate CH_VALUE
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:35 -0300 Subject: media: media/v4l2-ctrls: volatiles should not generate CH_VALUE To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Ricardo Ribalda ricardo.ribalda@gmail.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@osg.samsung.com, Mauro Carvalho Chehab mchehab@s-opensource.com Message-ID: 1663cf48e2eb96405c5d6d874020aa9925ee217f.1522260310.git.mchehab@s-opensource.com
From: Ricardo Ribalda ricardo.ribalda@gmail.com
Volatile controls should not generate CH_VALUE events.
Set has_changed to false to prevent this happening.
Signed-off-by: Ricardo Ribalda Delgado ricardo.ribalda@gmail.com Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Signed-off-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-ctrls.c | 9 +++++++++ 1 file changed, 9 insertions(+)
--- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1619,6 +1619,15 @@ static int cluster_changed(struct v4l2_c
if (ctrl == NULL) continue; + /* + * Set has_changed to false to avoid generating + * the event V4L2_EVENT_CTRL_CH_VALUE + */ + if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { + ctrl->has_changed = false; + continue; + } + for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++) ctrl_changed = !ctrl->type_ops->equal(ctrl, idx, ctrl->p_cur, ctrl->p_new);
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:29 -0300 Subject: media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Daniel Mentz danielmentz@google.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@s-opensource.com, Sasha Levin alexander.levin@microsoft.com Message-ID: 63c220c11ade842157669d03bdaf10b84a6d91a9.1522260310.git.mchehab@s-opensource.com
From: Daniel Mentz danielmentz@google.com
commit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream.
Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output overlays.") added the field global_alpha to struct v4l2_window but did not update the compat layer accordingly. This change adds global_alpha to struct v4l2_window32 and copies the value for global_alpha back and forth.
Signed-off-by: Daniel Mentz danielmentz@google.com Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -45,6 +45,7 @@ struct v4l2_window32 { compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; compat_caddr_t bitmap; + __u8 global_alpha; };
static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) @@ -53,7 +54,8 @@ static int get_v4l2_window32(struct v4l2 copy_from_user(&kp->w, &up->w, sizeof(up->w)) || get_user(kp->field, &up->field) || get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount)) + get_user(kp->clipcount, &up->clipcount) || + get_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; @@ -86,7 +88,8 @@ static int put_v4l2_window32(struct v4l2 if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || put_user(kp->field, &up->field) || put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount)) + put_user(kp->clipcount, &up->clipcount) || + put_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; return 0; }
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32: initialize a reserved field
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:37 -0300 Subject: media: v4l2-compat-ioctl32: initialize a reserved field To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Mauro Carvalho Chehab mchehab@s-opensource.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org Message-ID: d8a647b26822fb0a86f6ee7dff4d6eb1e85e1398.1522260310.git.mchehab@s-opensource.com
From: Mauro Carvalho Chehab mchehab@s-opensource.com
The get_v4l2_create32() function is missing a logic with would be cleaning a reserved field, causing v4l2-compliance to complain:
Buffer ioctls (Input 0): fail: v4l2-test-buffers.cpp(506): check_0(crbufs.reserved, sizeof(crbufs.reserved)) test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: FAIL
Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -247,7 +247,8 @@ static int get_v4l2_create32(struct v4l2 { if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_in_user(kp, up, - offsetof(struct v4l2_create_buffers32, format))) + offsetof(struct v4l2_create_buffers32, format)) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; return __get_v4l2_format32(&kp->format, &up->format, aux_buf, aux_space);
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32: use compat_u64 for video standard
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:36 -0300 Subject: media: v4l2-compat-ioctl32: use compat_u64 for video standard To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Mauro Carvalho Chehab mchehab@s-opensource.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org Message-ID: 2ba9505436180b463d47d6da4ce5e059b383938e.1522260310.git.mchehab@s-opensource.com
From: Mauro Carvalho Chehab mchehab@s-opensource.com
Instead of using the "v4l2_std_id" typedef, use compat_u64, as otherwise it fails to properly handle some ioctls.
Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -686,7 +686,7 @@ struct v4l2_input32 { __u32 type; /* Type of input */ __u32 audioset; /* Associated audios (bitfield) */ __u32 tuner; /* Associated tuner */ - v4l2_std_id std; + compat_u64 std; __u32 status; __u32 capabilities; __u32 reserved[3];
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32.c: avoid sizeof(type)
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:25 -0300 Subject: media: v4l2-compat-ioctl32.c: avoid sizeof(type) To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Mauro Carvalho Chehab mchehab@s-opensource.com, Sasha Levin alexander.levin@microsoft.com Message-ID: b2ea40bb0147ce21cf35781d842cba0d60f7e07f.1522260310.git.mchehab@s-opensource.com
From: Hans Verkuil hans.verkuil@cisco.com
commit 333b1e9f96ce05f7498b581509bb30cde03018bf upstream.
Instead of doing sizeof(struct foo) use sizeof(*up). There even were cases where 4 * sizeof(__u32) was used instead of sizeof(kp->reserved), which is very dangerous when the size of the reserved array changes.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 80 ++++++++++++-------------- 1 file changed, 38 insertions(+), 42 deletions(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -47,7 +47,7 @@ struct v4l2_window32 {
static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(&kp->w, &up->w, sizeof(up->w)) || get_user(kp->field, &up->field) || get_user(kp->chromakey, &up->chromakey) || @@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2 if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); kp->clips = kclips; while (--n >= 0) { if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) @@ -152,14 +152,14 @@ static int __get_v4l2_format32(struct v4
static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32))) + if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; return __get_v4l2_format32(kp, up); }
static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) return -EFAULT; return __get_v4l2_format32(&kp->format, &up->format); @@ -196,17 +196,17 @@ static int __put_v4l2_format32(struct v4
static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || - put_user(kp->type, &up->type)) + if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; return __put_v4l2_format32(kp, up); }
static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || - copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) - return -EFAULT; + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + return -EFAULT; return __put_v4l2_format32(&kp->format, &up->format); }
@@ -222,7 +222,7 @@ struct v4l2_standard32 { static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->index, &up->index)) return -EFAULT; return 0; @@ -230,13 +230,13 @@ static int get_v4l2_standard32(struct v4
static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->index, &up->index) || copy_to_user(up->id, &kp->id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, 24) || + copy_to_user(up->name, kp->name, sizeof(up->name)) || copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return 0; } @@ -284,7 +284,7 @@ static int get_v4l2_plane32(struct v4l2_
if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(&up->data_offset, &up32->data_offset, - sizeof(__u32))) + sizeof(up->data_offset))) return -EFAULT;
if (memory == V4L2_MEMORY_USERPTR) { @@ -294,11 +294,11 @@ static int get_v4l2_plane32(struct v4l2_ if (put_user((unsigned long)up_pln, &up->m.userptr)) return -EFAULT; } else if (memory == V4L2_MEMORY_DMABUF) { - if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int))) + if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd))) return -EFAULT; } else { if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, - sizeof(__u32))) + sizeof(up32->m.mem_offset))) return -EFAULT; }
@@ -310,19 +310,19 @@ static int put_v4l2_plane32(struct v4l2_ { if (copy_in_user(up32, up, 2 * sizeof(__u32)) || copy_in_user(&up32->data_offset, &up->data_offset, - sizeof(__u32))) + sizeof(up->data_offset))) return -EFAULT;
/* For MMAP, driver might've set up the offset, so copy it back. * USERPTR stays the same (was userspace-provided), so no copying. */ if (memory == V4L2_MEMORY_MMAP) if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, - sizeof(__u32))) + sizeof(up->m.mem_offset))) return -EFAULT; /* For DMABUF, driver might've set up the fd, so copy it back. */ if (memory == V4L2_MEMORY_DMABUF) if (copy_in_user(&up32->m.fd, &up->m.fd, - sizeof(int))) + sizeof(up->m.fd))) return -EFAULT;
return 0; @@ -336,7 +336,7 @@ static int get_v4l2_buffer32(struct v4l2 int num_planes; int ret;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->index, &up->index) || get_user(kp->type, &up->type) || get_user(kp->flags, &up->flags) || @@ -348,8 +348,7 @@ static int get_v4l2_buffer32(struct v4l2 if (get_user(kp->bytesused, &up->bytesused) || get_user(kp->field, &up->field) || get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, - &up->timestamp.tv_usec)) + get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec)) return -EFAULT;
if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { @@ -366,13 +365,12 @@ static int get_v4l2_buffer32(struct v4l2
uplane32 = compat_ptr(p); if (!access_ok(VERIFY_READ, uplane32, - num_planes * sizeof(struct v4l2_plane32))) + num_planes * sizeof(*uplane32))) return -EFAULT;
/* We don't really care if userspace decides to kill itself * by passing a very big num_planes value */ - uplane = compat_alloc_user_space(num_planes * - sizeof(struct v4l2_plane)); + uplane = compat_alloc_user_space(num_planes * sizeof(*uplane)); kp->m.planes = (__force struct v4l2_plane *)uplane;
while (--num_planes >= 0) { @@ -420,7 +418,7 @@ static int put_v4l2_buffer32(struct v4l2 int num_planes; int ret;
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->index, &up->index) || put_user(kp->type, &up->type) || put_user(kp->flags, &up->flags) || @@ -431,7 +429,7 @@ static int put_v4l2_buffer32(struct v4l2 put_user(kp->field, &up->field) || put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || + copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || put_user(kp->sequence, &up->sequence) || put_user(kp->reserved2, &up->reserved2) || put_user(kp->reserved, &up->reserved) || @@ -499,7 +497,7 @@ static int get_v4l2_framebuffer32(struct { u32 tmp;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(tmp, &up->base) || get_user(kp->capability, &up->capability) || get_user(kp->flags, &up->flags) || @@ -513,7 +511,7 @@ static int put_v4l2_framebuffer32(struct { u32 tmp = (u32)((unsigned long)kp->base);
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(tmp, &up->base) || put_user(kp->capability, &up->capability) || put_user(kp->flags, &up->flags) || @@ -537,14 +535,14 @@ struct v4l2_input32 { Otherwise it is identical to the 32-bit version. */ static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) { - if (copy_from_user(kp, up, sizeof(struct v4l2_input32))) + if (copy_from_user(kp, up, sizeof(*up))) return -EFAULT; return 0; }
static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) { - if (copy_to_user(up, kp, sizeof(struct v4l2_input32))) + if (copy_to_user(up, kp, sizeof(*up))) return -EFAULT; return 0; } @@ -592,7 +590,7 @@ static int get_v4l2_ext_controls32(struc int n; compat_caddr_t p;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->ctrl_class, &up->ctrl_class) || get_user(kp->count, &up->count) || get_user(kp->error_idx, &up->error_idx) || @@ -606,10 +604,9 @@ static int get_v4l2_ext_controls32(struc if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_READ, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols))) return -EFAULT; - kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); + kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols)); kp->controls = (__force struct v4l2_ext_control *)kcontrols; while (--n >= 0) { u32 id; @@ -641,7 +638,7 @@ static int put_v4l2_ext_controls32(struc int n = kp->count; compat_caddr_t p;
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->ctrl_class, &up->ctrl_class) || put_user(kp->count, &up->count) || put_user(kp->error_idx, &up->error_idx) || @@ -653,8 +650,7 @@ static int put_v4l2_ext_controls32(struc if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_WRITE, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols))) return -EFAULT;
while (--n >= 0) { @@ -690,7 +686,7 @@ struct v4l2_event32 {
static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->type, &up->type) || copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || put_user(kp->pending, &up->pending) || @@ -698,7 +694,7 @@ static int put_v4l2_event32(struct v4l2_ put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || put_user(kp->id, &up->id) || - copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return 0; } @@ -715,7 +711,7 @@ static int get_v4l2_edid32(struct v4l2_e { u32 tmp;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->pad, &up->pad) || get_user(kp->start_block, &up->start_block) || get_user(kp->blocks, &up->blocks) || @@ -730,7 +726,7 @@ static int put_v4l2_edid32(struct v4l2_e { u32 tmp = (u32)((unsigned long)kp->edid);
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->pad, &up->pad) || put_user(kp->start_block, &up->start_block) || put_user(kp->blocks, &up->blocks) ||
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:30 -0300 Subject: media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Mauro Carvalho Chehab mchehab@s-opensource.com, Sasha Levin alexander.levin@microsoft.com Message-ID: b203ca17a23bf02398ef39e8f123d30b74df3523.1522260310.git.mchehab@s-opensource.com
From: Hans Verkuil hans.verkuil@cisco.com
commit a751be5b142ef6bcbbb96d9899516f4d9c8d0ef4 upstream.
put_v4l2_window32() didn't copy back the clip list to userspace. Drivers can update the clip rectangles, so this should be done.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 +++++++++++++++++--------- 1 file changed, 40 insertions(+), 19 deletions(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -50,6 +50,11 @@ struct v4l2_window32 {
static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { + struct v4l2_clip32 __user *uclips; + struct v4l2_clip __user *kclips; + compat_caddr_t p; + u32 n; + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(&kp->w, &up->w, sizeof(up->w)) || get_user(kp->field, &up->field) || @@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2 return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; - if (kp->clipcount) { - struct v4l2_clip32 __user *uclips; - struct v4l2_clip __user *kclips; - int n = kp->clipcount; - compat_caddr_t p; + if (!kp->clipcount) { + kp->clips = NULL; + return 0; + }
- if (get_user(p, &up->clips)) + n = kp->clipcount; + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (n--) { + if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) return -EFAULT; - uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(*kclips)); - kp->clips = kclips; - while (--n >= 0) { - if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, &kclips->next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else - kp->clips = NULL; + if (put_user(n ? kclips + 1 : NULL, &kclips->next)) + return -EFAULT; + uclips++; + kclips++; + } return 0; }
static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { + struct v4l2_clip __user *kclips = kp->clips; + struct v4l2_clip32 __user *uclips; + u32 n = kp->clipcount; + compat_caddr_t p; + if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || put_user(kp->field, &up->field) || put_user(kp->chromakey, &up->chromakey) || put_user(kp->clipcount, &up->clipcount) || put_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; + + if (!kp->clipcount) + return 0; + + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); + while (n--) { + if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) + return -EFAULT; + uclips++; + kclips++; + } return 0; }
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:26 -0300 Subject: media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Mauro Carvalho Chehab mchehab@s-opensource.com, Sasha Levin alexander.levin@microsoft.com Message-ID: 6e6f38fc8542cf41fffcd3067026c4f015564544.1522260310.git.mchehab@s-opensource.com
From: Hans Verkuil hans.verkuil@cisco.com
commit 8ed5a59dcb47a6f76034ee760b36e089f3e82529 upstream.
The struct v4l2_plane32 should set m.userptr as well. The same happens in v4l2_buffer32 and v4l2-compliance tests for this.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 47 +++++++++++++++----------- 1 file changed, 28 insertions(+), 19 deletions(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -287,19 +287,24 @@ static int get_v4l2_plane32(struct v4l2_ sizeof(up->data_offset))) return -EFAULT;
- if (memory == V4L2_MEMORY_USERPTR) { + switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: + if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, + sizeof(up32->m.mem_offset))) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: if (get_user(p, &up32->m.userptr)) return -EFAULT; up_pln = compat_ptr(p); if (put_user((unsigned long)up_pln, &up->m.userptr)) return -EFAULT; - } else if (memory == V4L2_MEMORY_DMABUF) { + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd))) return -EFAULT; - } else { - if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, - sizeof(up32->m.mem_offset))) - return -EFAULT; + break; }
return 0; @@ -308,22 +313,32 @@ static int get_v4l2_plane32(struct v4l2_ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { + unsigned long p; + if (copy_in_user(up32, up, 2 * sizeof(__u32)) || copy_in_user(&up32->data_offset, &up->data_offset, sizeof(up->data_offset))) return -EFAULT;
- /* For MMAP, driver might've set up the offset, so copy it back. - * USERPTR stays the same (was userspace-provided), so no copying. */ - if (memory == V4L2_MEMORY_MMAP) + switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, sizeof(up->m.mem_offset))) return -EFAULT; - /* For DMABUF, driver might've set up the fd, so copy it back. */ - if (memory == V4L2_MEMORY_DMABUF) + break; + case V4L2_MEMORY_USERPTR: + if (get_user(p, &up->m.userptr) || + put_user((compat_ulong_t)ptr_to_compat((__force void *)p), + &up32->m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd))) return -EFAULT; + break; + }
return 0; } @@ -383,6 +398,7 @@ static int get_v4l2_buffer32(struct v4l2 } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (get_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; @@ -396,10 +412,6 @@ static int get_v4l2_buffer32(struct v4l2 kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (get_user(kp->m.fd, &up->m.fd)) return -EFAULT; @@ -456,6 +468,7 @@ static int put_v4l2_buffer32(struct v4l2 } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (put_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; @@ -463,10 +476,6 @@ static int put_v4l2_buffer32(struct v4l2 if (put_user(kp->m.userptr, &up->m.userptr)) return -EFAULT; break; - case V4L2_MEMORY_OVERLAY: - if (put_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (put_user(kp->m.fd, &up->m.fd)) return -EFAULT;
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:32 -0300 Subject: media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Mauro Carvalho Chehab mchehab@s-opensource.com, Sasha Levin alexander.levin@microsoft.com Message-ID: 9d0bb62c2dc7caee1fd2b9199fc1a22ec8479395.1522260310.git.mchehab@s-opensource.com
From: Hans Verkuil hans.verkuil@cisco.com
commit d83a8243aaefe62ace433e4384a4f077bed86acb upstream.
Some ioctls need to copy back the result even if the ioctl returned an error. However, don't do this for the error code -ENOTTY. It makes no sense in that cases.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 +++ 1 file changed, 3 insertions(+)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -943,6 +943,9 @@ static long do_video_ioctl(struct file * set_fs(old_fs); }
+ if (err == -ENOTTY) + return err; + /* Special case: even after an error we need to put the results back for these ioctls since the error_idx will contain information on which control failed. */
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:31 -0300 Subject: media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Mauro Carvalho Chehab mchehab@s-opensource.com, Sasha Levin alexander.levin@microsoft.com Message-ID: 8f000de7f9babd3f104eacbd7e79fbd72372c9d1.1522260310.git.mchehab@s-opensource.com
From: Hans Verkuil hans.verkuil@cisco.com
commit 169f24ca68bf0f247d111aef07af00dd3a02ae88 upstream.
There is nothing wrong with using an unknown buffer type. So stop spamming the kernel log whenever this happens. The kernel will just return -EINVAL to signal this.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 ---- 1 file changed, 4 deletions(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -170,8 +170,6 @@ static int __get_v4l2_format32(struct v4 return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } @@ -214,8 +212,6 @@ static int __put_v4l2_format32(struct v4 return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced, sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } }
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:27 -0300 Subject: media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Mauro Carvalho Chehab mchehab@s-opensource.com, Sasha Levin alexander.levin@microsoft.com Message-ID: 63df92f6981785c5e31c1d8e796e827344cc75f3.1522260310.git.mchehab@s-opensource.com
From: Hans Verkuil hans.verkuil@cisco.com
commit b8c601e8af2d08f733d74defa8465303391bb930 upstream.
ctrl_is_pointer just hardcoded two known string controls, but that caused problems when using e.g. custom controls that use a pointer for the payload.
Reimplement this function: it now finds the v4l2_ctrl (if the driver uses the control framework) or it calls vidioc_query_ext_ctrl (if the driver implements that directly).
In both cases it can now check if the control is a pointer control or not.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 +++++++++++++++++--------- 1 file changed, 39 insertions(+), 20 deletions(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -18,6 +18,8 @@ #include <linux/videodev2.h> #include <linux/v4l2-subdev.h> #include <media/v4l2-dev.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ctrls.h> #include <media/v4l2-ioctl.h>
static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -575,24 +577,39 @@ struct v4l2_ext_control32 { }; } __attribute__ ((packed));
-/* The following function really belong in v4l2-common, but that causes - a circular dependency between modules. We need to think about this, but - for now this will do. */ - -/* Return non-zero if this control is a pointer type. Currently only - type STRING is a pointer type. */ -static inline int ctrl_is_pointer(u32 id) -{ - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; +/* Return true if this control is a pointer type. */ +static inline bool ctrl_is_pointer(struct file *file, u32 id) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_fh *fh = NULL; + struct v4l2_ctrl_handler *hdl = NULL; + struct v4l2_query_ext_ctrl qec = { id }; + const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; + + if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) + fh = file->private_data; + + if (fh && fh->ctrl_handler) + hdl = fh->ctrl_handler; + else if (vdev->ctrl_handler) + hdl = vdev->ctrl_handler; + + if (hdl) { + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id); + + return ctrl && ctrl->is_ptr; } + + if (!ops->vidioc_query_ext_ctrl) + return false; + + return !ops->vidioc_query_ext_ctrl(file, fh, &qec) && + (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); }
-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int get_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; @@ -624,7 +641,7 @@ static int get_v4l2_ext_controls32(struc return -EFAULT; if (get_user(id, &kcontrols->id)) return -EFAULT; - if (ctrl_is_pointer(id)) { + if (ctrl_is_pointer(file, id)) { void __user *s;
if (get_user(p, &ucontrols->string)) @@ -639,7 +656,9 @@ static int get_v4l2_ext_controls32(struc return 0; }
-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int put_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols = @@ -671,7 +690,7 @@ static int put_v4l2_ext_controls32(struc /* Do not modify the pointer when copying a pointer control. The contents of the pointer was changed, not the pointer itself. */ - if (ctrl_is_pointer(id)) + if (ctrl_is_pointer(file, id)) size -= sizeof(ucontrols->value64); if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; @@ -884,7 +903,7 @@ static long do_video_ioctl(struct file * case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(&karg.v2ecs, up); + err = get_v4l2_ext_controls32(file, &karg.v2ecs, up); compatible_arg = 0; break; case VIDIOC_DQEVENT: @@ -911,7 +930,7 @@ static long do_video_ioctl(struct file * case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - if (put_v4l2_ext_controls32(&karg.v2ecs, up)) + if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) err = -EFAULT; break; }
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:28 -0300 Subject: media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Hans Verkuil hansverk@cisco.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@s-opensource.com, Sasha Levin alexander.levin@microsoft.com Message-ID: 39d6997be9988f81bce42a00115b062aac7b0a51.1522260310.git.mchehab@s-opensource.com
From: Hans Verkuil hansverk@cisco.com
commit 273caa260035c03d89ad63d72d8cd3d9e5c5e3f1 upstream.
If the device is of type VFL_TYPE_SUBDEV then vdev->ioctl_ops is NULL so the 'if (!ops->vidioc_query_ext_ctrl)' check would crash. Add a test for !ops to the condition.
All sub-devices that have controls will use the control framework, so they do not have an equivalent to ops->vidioc_query_ext_ctrl. Returning false if ops is NULL is the correct thing to do here.
Fixes: b8c601e8af ("v4l2-compat-ioctl32.c: fix ctrl_is_pointer")
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Reported-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -600,7 +600,7 @@ static inline bool ctrl_is_pointer(struc return ctrl && ctrl->is_ptr; }
- if (!ops->vidioc_query_ext_ctrl) + if (!ops || !ops->vidioc_query_ext_ctrl) return false;
return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:24 -0300 Subject: media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Mauro Carvalho Chehab mchehab@s-opensource.com, Sasha Levin alexander.levin@microsoft.com Message-ID: eba66edbe4ca94e61e342683ee5e225f376d754c.1522260310.git.mchehab@s-opensource.com
From: Hans Verkuil hans.verkuil@cisco.com
commit 486c521510c44a04cd756a9267e7d1e271c8a4ba upstream.
These helper functions do not really help. Move the code to the __get/put_v4l2_format32 functions.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 84 ++++---------------------- 1 file changed, 16 insertions(+), 68 deletions(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -89,64 +89,6 @@ static int put_v4l2_window32(struct v4l2 return 0; }
-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - struct v4l2_format32 { __u32 type; /* enum v4l2_buf_type */ union { @@ -184,20 +126,23 @@ static int __get_v4l2_format32(struct v4 switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + return copy_from_user(&kp->fmt.pix, &up->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp, - &up->fmt.pix_mp); + return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); + return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); + return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", kp->type); @@ -225,20 +170,23 @@ static int __put_v4l2_format32(struct v4 switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + return copy_to_user(&up->fmt.pix, &kp->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp, - &up->fmt.pix_mp); + return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); + return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); + return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", kp->type);
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:33 -0300 Subject: media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Daniel Mentz danielmentz@google.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@s-opensource.com, Sasha Levin alexander.levin@microsoft.com Message-ID: 10af8cdf1226db8dfc7e85673ee3a7a17ba969f2.1522260310.git.mchehab@s-opensource.com
From: Daniel Mentz danielmentz@google.com
commit a1dfb4c48cc1e64eeb7800a27c66a6f7e88d075a upstream.
The 32-bit compat v4l2 ioctl handling is implemented based on its 64-bit equivalent. It converts 32-bit data structures into its 64-bit equivalents and needs to provide the data to the 64-bit ioctl in user space memory which is commonly allocated using compat_alloc_user_space().
However, due to how that function is implemented, it can only be called a single time for every syscall invocation.
Supposedly to avoid this limitation, the existing code uses a mix of memory from the kernel stack and memory allocated through compat_alloc_user_space().
Under normal circumstances, this would not work, because the 64-bit ioctl expects all pointers to point to user space memory. As a workaround, set_fs(KERNEL_DS) is called to temporarily disable this extra safety check and allow kernel pointers. However, this might introduce a security vulnerability: The result of the 32-bit to 64-bit conversion is writeable by user space because the output buffer has been allocated via compat_alloc_user_space(). A malicious user space process could then manipulate pointers inside this output buffer, and due to the previous set_fs(KERNEL_DS) call, functions like get_user() or put_user() no longer prevent kernel memory access.
The new approach is to pre-calculate the total amount of user space memory that is needed, allocate it using compat_alloc_user_space() and then divide up the allocated memory to accommodate all data structures that need to be converted.
An alternative approach would have been to retain the union type karg that they allocated on the kernel stack in do_video_ioctl(), copy all data from user space into karg and then back to user space. However, we decided against this approach because it does not align with other compat syscall implementations. Instead, we tried to replicate the get_user/put_user pairs as found in other places in the kernel:
if (get_user(clipcount, &up->clipcount) || put_user(clipcount, &kp->clipcount)) return -EFAULT;
Notes from hans.verkuil@cisco.com:
This patch was taken from: https://github.com/LineageOS/android_kernel_samsung_apq8084/commit/97b733953...
Clearly nobody could be bothered to upstream this patch or at minimum tell us :-( We only heard about this a week ago.
This patch was rebased and cleaned up. Compared to the original I also swapped the order of the convert_in_user arguments so that they matched copy_in_user. It was hard to review otherwise. I also replaced the ALLOC_USER_SPACE/ALLOC_AND_GET by a normal function.
Fixes: 6b5a9492ca ("v4l: introduce string control support.")
Signed-off-by: Daniel Mentz danielmentz@google.com Co-developed-by: Hans Verkuil hans.verkuil@cisco.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 757 ++++++++++++++++---------- 1 file changed, 491 insertions(+), 266 deletions(-)
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -22,6 +22,14 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-ioctl.h>
+/* Use the same argument order as copy_in_user */ +#define assign_in_user(to, from) \ +({ \ + typeof(*from) __assign_tmp; \ + \ + get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \ +}) + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = -ENOIOCTLCMD; @@ -35,12 +43,12 @@ static long native_ioctl(struct file *fi
struct v4l2_clip32 { struct v4l2_rect c; - compat_caddr_t next; + compat_caddr_t next; };
struct v4l2_window32 { struct v4l2_rect w; - __u32 field; /* enum v4l2_field */ + __u32 field; /* enum v4l2_field */ __u32 chromakey; compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; @@ -48,37 +56,41 @@ struct v4l2_window32 { __u8 global_alpha; };
-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +static int get_v4l2_window32(struct v4l2_window __user *kp, + struct v4l2_window32 __user *up, + void __user *aux_buf, u32 aux_space) { struct v4l2_clip32 __user *uclips; struct v4l2_clip __user *kclips; compat_caddr_t p; - u32 n; + u32 clipcount;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - copy_from_user(&kp->w, &up->w, sizeof(up->w)) || - get_user(kp->field, &up->field) || - get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount) || - get_user(kp->global_alpha, &up->global_alpha)) + copy_in_user(&kp->w, &up->w, sizeof(up->w)) || + assign_in_user(&kp->field, &up->field) || + assign_in_user(&kp->chromakey, &up->chromakey) || + assign_in_user(&kp->global_alpha, &up->global_alpha) || + get_user(clipcount, &up->clipcount) || + put_user(clipcount, &kp->clipcount)) return -EFAULT; - if (kp->clipcount > 2048) + if (clipcount > 2048) return -EINVAL; - if (!kp->clipcount) { - kp->clips = NULL; - return 0; - } + if (!clipcount) + return put_user(NULL, &kp->clips);
- n = kp->clipcount; if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(*kclips)); - kp->clips = kclips; - while (n--) { + if (aux_space < clipcount * sizeof(*kclips)) + return -EFAULT; + kclips = aux_buf; + if (put_user(kclips, &kp->clips)) + return -EFAULT; + + while (clipcount--) { if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, &kclips->next)) + if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next)) return -EFAULT; uclips++; kclips++; @@ -86,27 +98,28 @@ static int get_v4l2_window32(struct v4l2 return 0; }
-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +static int put_v4l2_window32(struct v4l2_window __user *kp, + struct v4l2_window32 __user *up) { struct v4l2_clip __user *kclips = kp->clips; struct v4l2_clip32 __user *uclips; - u32 n = kp->clipcount; compat_caddr_t p; + u32 clipcount;
- if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || - put_user(kp->field, &up->field) || - put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount) || - put_user(kp->global_alpha, &up->global_alpha)) + if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) || + assign_in_user(&up->field, &kp->field) || + assign_in_user(&up->chromakey, &kp->chromakey) || + assign_in_user(&up->global_alpha, &kp->global_alpha) || + get_user(clipcount, &kp->clipcount) || + put_user(clipcount, &up->clipcount)) return -EFAULT; - - if (!kp->clipcount) + if (!clipcount) return 0;
if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); - while (n--) { + while (clipcount--) { if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) return -EFAULT; uclips++; @@ -144,90 +157,150 @@ struct v4l2_create_buffers32 { __u32 reserved[8]; };
-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) +{ + u32 type; + + if (get_user(type, &up->type)) + return -EFAULT; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { + u32 clipcount; + + if (get_user(clipcount, &up->fmt.win.clipcount)) + return -EFAULT; + if (clipcount > 2048) + return -EINVAL; + *size = clipcount * sizeof(struct v4l2_clip); + return 0; + } + default: + *size = 0; + return 0; + } +} + +static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) { - if (get_user(kp->type, &up->type)) + if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; + return __bufsize_v4l2_format(up, size); +}
- switch (kp->type) { +static int __get_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up, + void __user *aux_buf, u32 aux_space) +{ + u32 type; + + if (get_user(type, &up->type) || put_user(type, &kp->type)) + return -EFAULT; + + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return copy_from_user(&kp->fmt.pix, &up->fmt.pix, - sizeof(kp->fmt.pix)) ? -EFAULT : 0; + return copy_in_user(&kp->fmt.pix, &up->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, - sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); + return get_v4l2_window32(&kp->fmt.win, &up->fmt.win, + aux_buf, aux_space); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi, - sizeof(kp->fmt.vbi)) ? -EFAULT : 0; + return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, - sizeof(kp->fmt.sliced)) ? -EFAULT : 0; + return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: return -EINVAL; } }
-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int get_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up, + void __user *aux_buf, u32 aux_space) { if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; - return __get_v4l2_format32(kp, up); + return __get_v4l2_format32(kp, up, aux_buf, aux_space); }
-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up, + u32 *size) +{ + if (!access_ok(VERIFY_READ, up, sizeof(*up))) + return -EFAULT; + return __bufsize_v4l2_format(&up->format, size); +} + +static int get_v4l2_create32(struct v4l2_create_buffers __user *kp, + struct v4l2_create_buffers32 __user *up, + void __user *aux_buf, u32 aux_space) { if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) + copy_in_user(kp, up, + offsetof(struct v4l2_create_buffers32, format))) return -EFAULT; - return __get_v4l2_format32(&kp->format, &up->format); + return __get_v4l2_format32(&kp->format, &up->format, + aux_buf, aux_space); }
-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int __put_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up) { - switch (kp->type) { + u32 type; + + if (get_user(type, &kp->type)) + return -EFAULT; + + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return copy_to_user(&up->fmt.pix, &kp->fmt.pix, - sizeof(kp->fmt.pix)) ? -EFAULT : 0; + return copy_in_user(&up->fmt.pix, &kp->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, - sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi, - sizeof(kp->fmt.vbi)) ? -EFAULT : 0; + return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced, - sizeof(kp->fmt.sliced)) ? -EFAULT : 0; + return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: return -EINVAL; } }
-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int put_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; return __put_v4l2_format32(kp, up); }
-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +static int put_v4l2_create32(struct v4l2_create_buffers __user *kp, + struct v4l2_create_buffers32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || - copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + copy_in_user(up, kp, + offsetof(struct v4l2_create_buffers32, format)) || + copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return __put_v4l2_format32(&kp->format, &up->format); } @@ -241,24 +314,27 @@ struct v4l2_standard32 { __u32 reserved[4]; };
-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +static int get_v4l2_standard32(struct v4l2_standard __user *kp, + struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->index, &up->index)) + assign_in_user(&kp->index, &up->index)) return -EFAULT; return 0; }
-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +static int put_v4l2_standard32(struct v4l2_standard __user *kp, + struct v4l2_standard32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->index, &up->index) || - copy_to_user(up->id, &kp->id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, sizeof(up->name)) || - copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + assign_in_user(&up->index, &kp->index) || + copy_in_user(&up->id, &kp->id, sizeof(up->id)) || + copy_in_user(up->name, kp->name, sizeof(up->name)) || + copy_in_user(&up->frameperiod, &kp->frameperiod, + sizeof(up->frameperiod)) || + assign_in_user(&up->framelines, &kp->framelines) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } @@ -298,11 +374,11 @@ struct v4l2_buffer32 { __u32 reserved; };
-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, +static int get_v4l2_plane32(struct v4l2_plane __user *up, + struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { - void __user *up_pln; - compat_long_t p; + compat_ulong_t p;
if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(&up->data_offset, &up32->data_offset, @@ -317,10 +393,8 @@ static int get_v4l2_plane32(struct v4l2_ return -EFAULT; break; case V4L2_MEMORY_USERPTR: - if (get_user(p, &up32->m.userptr)) - return -EFAULT; - up_pln = compat_ptr(p); - if (put_user((unsigned long)up_pln, &up->m.userptr)) + if (get_user(p, &up32->m.userptr) || + put_user((unsigned long)compat_ptr(p), &up->m.userptr)) return -EFAULT; break; case V4L2_MEMORY_DMABUF: @@ -332,7 +406,8 @@ static int get_v4l2_plane32(struct v4l2_ return 0; }
-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, +static int put_v4l2_plane32(struct v4l2_plane __user *up, + struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { unsigned long p; @@ -356,8 +431,7 @@ static int put_v4l2_plane32(struct v4l2_ return -EFAULT; break; case V4L2_MEMORY_DMABUF: - if (copy_in_user(&up32->m.fd, &up->m.fd, - sizeof(up->m.fd))) + if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd))) return -EFAULT; break; } @@ -365,37 +439,75 @@ static int put_v4l2_plane32(struct v4l2_ return 0; }
-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size) { + u32 type; + u32 length; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(type, &up->type) || + get_user(length, &up->length)) + return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + if (length > VIDEO_MAX_PLANES) + return -EINVAL; + + /* + * We don't really care if userspace decides to kill itself + * by passing a very big length value + */ + *size = length * sizeof(struct v4l2_plane); + } else { + *size = 0; + } + return 0; +} + +static int get_v4l2_buffer32(struct v4l2_buffer __user *kp, + struct v4l2_buffer32 __user *up, + void __user *aux_buf, u32 aux_space) +{ + u32 type; + u32 length; + enum v4l2_memory memory; struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; - int num_planes; int ret;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->index, &up->index) || - get_user(kp->type, &up->type) || - get_user(kp->flags, &up->flags) || - get_user(kp->memory, &up->memory) || - get_user(kp->length, &up->length)) - return -EFAULT; - - if (V4L2_TYPE_IS_OUTPUT(kp->type)) - if (get_user(kp->bytesused, &up->bytesused) || - get_user(kp->field, &up->field) || - get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec)) + assign_in_user(&kp->index, &up->index) || + get_user(type, &up->type) || + put_user(type, &kp->type) || + assign_in_user(&kp->flags, &up->flags) || + get_user(memory, &up->memory) || + put_user(memory, &kp->memory) || + get_user(length, &up->length) || + put_user(length, &kp->length)) + return -EFAULT; + + if (V4L2_TYPE_IS_OUTPUT(type)) + if (assign_in_user(&kp->bytesused, &up->bytesused) || + assign_in_user(&kp->field, &up->field) || + assign_in_user(&kp->timestamp.tv_sec, + &up->timestamp.tv_sec) || + assign_in_user(&kp->timestamp.tv_usec, + &up->timestamp.tv_usec)) return -EFAULT;
- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + u32 num_planes = length; + if (num_planes == 0) { - kp->m.planes = NULL; - /* num_planes == 0 is legal, e.g. when userspace doesn't - * need planes array on DQBUF*/ - return 0; + /* + * num_planes == 0 is legal, e.g. when userspace doesn't + * need planes array on DQBUF + */ + return put_user(NULL, &kp->m.planes); } + if (num_planes > VIDEO_MAX_PLANES) + return -EINVAL;
if (get_user(p, &up->m.planes)) return -EFAULT; @@ -405,37 +517,43 @@ static int get_v4l2_buffer32(struct v4l2 num_planes * sizeof(*uplane32))) return -EFAULT;
- /* We don't really care if userspace decides to kill itself - * by passing a very big num_planes value */ - uplane = compat_alloc_user_space(num_planes * sizeof(*uplane)); - kp->m.planes = (__force struct v4l2_plane *)uplane; + /* + * We don't really care if userspace decides to kill itself + * by passing a very big num_planes value + */ + if (aux_space < num_planes * sizeof(*uplane)) + return -EFAULT; + + uplane = aux_buf; + if (put_user((__force struct v4l2_plane *)uplane, + &kp->m.planes)) + return -EFAULT;
- while (--num_planes >= 0) { - ret = get_v4l2_plane32(uplane, uplane32, kp->memory); + while (num_planes--) { + ret = get_v4l2_plane32(uplane, uplane32, memory); if (ret) return ret; - ++uplane; - ++uplane32; + uplane++; + uplane32++; } } else { - switch (kp->memory) { + switch (memory) { case V4L2_MEMORY_MMAP: case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, &up->m.offset)) + if (assign_in_user(&kp->m.offset, &up->m.offset)) return -EFAULT; break; - case V4L2_MEMORY_USERPTR: - { - compat_long_t tmp; + case V4L2_MEMORY_USERPTR: { + compat_ulong_t userptr;
- if (get_user(tmp, &up->m.userptr)) - return -EFAULT; - - kp->m.userptr = (unsigned long)compat_ptr(tmp); - } + if (get_user(userptr, &up->m.userptr) || + put_user((unsigned long)compat_ptr(userptr), + &kp->m.userptr)) + return -EFAULT; break; + } case V4L2_MEMORY_DMABUF: - if (get_user(kp->m.fd, &up->m.fd)) + if (assign_in_user(&kp->m.fd, &up->m.fd)) return -EFAULT; break; } @@ -444,62 +562,70 @@ static int get_v4l2_buffer32(struct v4l2 return 0; }
-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +static int put_v4l2_buffer32(struct v4l2_buffer __user *kp, + struct v4l2_buffer32 __user *up) { + u32 type; + u32 length; + enum v4l2_memory memory; struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; - int num_planes; int ret;
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->index, &up->index) || - put_user(kp->type, &up->type) || - put_user(kp->flags, &up->flags) || - put_user(kp->memory, &up->memory)) - return -EFAULT; - - if (put_user(kp->bytesused, &up->bytesused) || - put_user(kp->field, &up->field) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->reserved2, &up->reserved2) || - put_user(kp->reserved, &up->reserved) || - put_user(kp->length, &up->length)) + assign_in_user(&up->index, &kp->index) || + get_user(type, &kp->type) || + put_user(type, &up->type) || + assign_in_user(&up->flags, &kp->flags) || + get_user(memory, &kp->memory) || + put_user(memory, &up->memory)) + return -EFAULT; + + if (assign_in_user(&up->bytesused, &kp->bytesused) || + assign_in_user(&up->field, &kp->field) || + assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || + assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) || + copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || + assign_in_user(&up->sequence, &kp->sequence) || + assign_in_user(&up->reserved2, &kp->reserved2) || + assign_in_user(&up->reserved, &kp->reserved) || + get_user(length, &kp->length) || + put_user(length, &up->length)) return -EFAULT;
- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + u32 num_planes = length; + if (num_planes == 0) return 0;
- uplane = (__force struct v4l2_plane __user *)kp->m.planes; + if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes))) + return -EFAULT; if (get_user(p, &up->m.planes)) return -EFAULT; uplane32 = compat_ptr(p);
- while (--num_planes >= 0) { - ret = put_v4l2_plane32(uplane, uplane32, kp->memory); + while (num_planes--) { + ret = put_v4l2_plane32(uplane, uplane32, memory); if (ret) return ret; ++uplane; ++uplane32; } } else { - switch (kp->memory) { + switch (memory) { case V4L2_MEMORY_MMAP: case V4L2_MEMORY_OVERLAY: - if (put_user(kp->m.offset, &up->m.offset)) + if (assign_in_user(&up->m.offset, &kp->m.offset)) return -EFAULT; break; case V4L2_MEMORY_USERPTR: - if (put_user(kp->m.userptr, &up->m.userptr)) + if (assign_in_user(&up->m.userptr, &kp->m.userptr)) return -EFAULT; break; case V4L2_MEMORY_DMABUF: - if (put_user(kp->m.fd, &up->m.fd)) + if (assign_in_user(&up->m.fd, &kp->m.fd)) return -EFAULT; break; } @@ -511,7 +637,7 @@ static int put_v4l2_buffer32(struct v4l2 struct v4l2_framebuffer32 { __u32 capability; __u32 flags; - compat_caddr_t base; + compat_caddr_t base; struct { __u32 width; __u32 height; @@ -524,29 +650,32 @@ struct v4l2_framebuffer32 { } fmt; };
-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, + struct v4l2_framebuffer32 __user *up) { - u32 tmp; + compat_caddr_t tmp;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(tmp, &up->base) || - get_user(kp->capability, &up->capability) || - get_user(kp->flags, &up->flags) || - copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) + put_user((__force void *)compat_ptr(tmp), &kp->base) || + assign_in_user(&kp->capability, &up->capability) || + assign_in_user(&kp->flags, &up->flags) || + copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt))) return -EFAULT; - kp->base = (__force void *)compat_ptr(tmp); return 0; }
-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, + struct v4l2_framebuffer32 __user *up) { - u32 tmp = (u32)((unsigned long)kp->base); + void *base;
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(tmp, &up->base) || - put_user(kp->capability, &up->capability) || - put_user(kp->flags, &up->flags) || - copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) + get_user(base, &kp->base) || + put_user(ptr_to_compat(base), &up->base) || + assign_in_user(&up->capability, &kp->capability) || + assign_in_user(&up->flags, &kp->flags) || + copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt))) return -EFAULT; return 0; } @@ -559,21 +688,26 @@ struct v4l2_input32 { __u32 tuner; /* Associated tuner */ v4l2_std_id std; __u32 status; - __u32 reserved[4]; -} __attribute__ ((packed)); + __u32 capabilities; + __u32 reserved[3]; +};
-/* 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 *kp, struct v4l2_input32 __user *up) +/* + * 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 *kp, + struct v4l2_input32 __user *up) { - if (copy_from_user(kp, up, sizeof(*up))) + if (copy_in_user(kp, up, sizeof(*up))) return -EFAULT; return 0; }
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) +static inline int put_v4l2_input32(struct v4l2_input __user *kp, + struct v4l2_input32 __user *up) { - if (copy_to_user(up, kp, sizeof(*up))) + if (copy_in_user(up, kp, sizeof(*up))) return -EFAULT; return 0; } @@ -627,40 +761,64 @@ static inline bool ctrl_is_pointer(struc (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); }
+static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up, + u32 *size) +{ + u32 count; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(count, &up->count)) + return -EFAULT; + if (count > V4L2_CID_MAX_CTRLS) + return -EINVAL; + *size = count * sizeof(struct v4l2_ext_control); + return 0; +} + static int get_v4l2_ext_controls32(struct file *file, - struct v4l2_ext_controls *kp, - struct v4l2_ext_controls32 __user *up) + struct v4l2_ext_controls __user *kp, + struct v4l2_ext_controls32 __user *up, + void __user *aux_buf, u32 aux_space) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; - int n; + u32 count; + u32 n; compat_caddr_t p;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->ctrl_class, &up->ctrl_class) || - get_user(kp->count, &up->count) || - get_user(kp->error_idx, &up->error_idx) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) - return -EFAULT; - n = kp->count; - if (n == 0) { - kp->controls = NULL; - return 0; - } + assign_in_user(&kp->ctrl_class, &up->ctrl_class) || + get_user(count, &up->count) || + put_user(count, &kp->count) || + assign_in_user(&kp->error_idx, &up->error_idx) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + return -EFAULT; + + if (count == 0) + return put_user(NULL, &kp->controls); + if (count > V4L2_CID_MAX_CTRLS) + return -EINVAL; if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols))) + if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols))) + return -EFAULT; + if (aux_space < count * sizeof(*kcontrols)) return -EFAULT; - kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols)); - kp->controls = (__force struct v4l2_ext_control *)kcontrols; - while (--n >= 0) { + kcontrols = aux_buf; + if (put_user((__force struct v4l2_ext_control *)kcontrols, + &kp->controls)) + return -EFAULT; + + for (n = 0; n < count; n++) { u32 id;
if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) return -EFAULT; + if (get_user(id, &kcontrols->id)) return -EFAULT; + if (ctrl_is_pointer(file, id)) { void __user *s;
@@ -677,43 +835,54 @@ static int get_v4l2_ext_controls32(struc }
static int put_v4l2_ext_controls32(struct file *file, - struct v4l2_ext_controls *kp, + struct v4l2_ext_controls __user *kp, struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control __user *kcontrols = - (__force struct v4l2_ext_control __user *)kp->controls; - int n = kp->count; + struct v4l2_ext_control __user *kcontrols; + u32 count; + u32 n; compat_caddr_t p;
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->ctrl_class, &up->ctrl_class) || - put_user(kp->count, &up->count) || - put_user(kp->error_idx, &up->error_idx) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + assign_in_user(&up->ctrl_class, &kp->ctrl_class) || + get_user(count, &kp->count) || + put_user(count, &up->count) || + assign_in_user(&up->error_idx, &kp->error_idx) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) || + get_user(kcontrols, &kp->controls)) return -EFAULT; - if (!kp->count) - return 0;
+ if (!count) + return 0; if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols))) + if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols))) return -EFAULT;
- while (--n >= 0) { - unsigned size = sizeof(*ucontrols); + for (n = 0; n < count; n++) { + unsigned int size = sizeof(*ucontrols); u32 id;
- if (get_user(id, &kcontrols->id)) + if (get_user(id, &kcontrols->id) || + put_user(id, &ucontrols->id) || + assign_in_user(&ucontrols->size, &kcontrols->size) || + copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2, + sizeof(ucontrols->reserved2))) return -EFAULT; - /* Do not modify the pointer when copying a pointer control. - The contents of the pointer was changed, not the pointer - itself. */ + + /* + * Do not modify the pointer when copying a pointer control. + * The contents of the pointer was changed, not the pointer + * itself. + */ if (ctrl_is_pointer(file, id)) size -= sizeof(ucontrols->value64); + if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; + ucontrols++; kcontrols++; } @@ -732,17 +901,18 @@ struct v4l2_event32 { __u32 reserved[8]; };
-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) +static int put_v4l2_event32(struct v4l2_event __user *kp, + struct v4l2_event32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->type, &up->type) || - copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || - put_user(kp->pending, &up->pending) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || - put_user(kp->id, &up->id) || - copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + assign_in_user(&up->type, &kp->type) || + copy_in_user(&up->u, &kp->u, sizeof(kp->u)) || + assign_in_user(&up->pending, &kp->pending) || + assign_in_user(&up->sequence, &kp->sequence) || + assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || + assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) || + assign_in_user(&up->id, &kp->id) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } @@ -755,31 +925,34 @@ struct v4l2_edid32 { compat_caddr_t edid; };
-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) +static int get_v4l2_edid32(struct v4l2_edid __user *kp, + struct v4l2_edid32 __user *up) { - u32 tmp; + compat_uptr_t tmp;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->pad, &up->pad) || - get_user(kp->start_block, &up->start_block) || - get_user(kp->blocks, &up->blocks) || + assign_in_user(&kp->pad, &up->pad) || + assign_in_user(&kp->start_block, &up->start_block) || + assign_in_user(&kp->blocks, &up->blocks) || get_user(tmp, &up->edid) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + put_user(compat_ptr(tmp), &kp->edid) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - kp->edid = (__force u8 *)compat_ptr(tmp); return 0; }
-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) +static int put_v4l2_edid32(struct v4l2_edid __user *kp, + struct v4l2_edid32 __user *up) { - u32 tmp = (u32)((unsigned long)kp->edid); + void *edid;
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->pad, &up->pad) || - put_user(kp->start_block, &up->start_block) || - put_user(kp->blocks, &up->blocks) || - put_user(tmp, &up->edid) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + assign_in_user(&up->pad, &kp->pad) || + assign_in_user(&up->start_block, &kp->start_block) || + assign_in_user(&up->blocks, &kp->blocks) || + get_user(edid, &kp->edid) || + put_user(ptr_to_compat(edid), &up->edid) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } @@ -796,7 +969,7 @@ static int put_v4l2_edid32(struct v4l2_e #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) #define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32) #define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32) -#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) +#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) @@ -812,22 +985,23 @@ static int put_v4l2_edid32(struct v4l2_e #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32) #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
+static int alloc_userspace(unsigned int size, u32 aux_space, + void __user **up_native) +{ + *up_native = compat_alloc_user_space(size + aux_space); + if (!*up_native) + return -ENOMEM; + if (clear_user(*up_native, size)) + return -EFAULT; + return 0; +} + static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - union { - struct v4l2_format v2f; - struct v4l2_buffer v2b; - struct v4l2_framebuffer v2fb; - struct v4l2_input v2i; - struct v4l2_standard v2s; - struct v4l2_ext_controls v2ecs; - struct v4l2_event v2ev; - struct v4l2_create_buffers v2crt; - struct v4l2_edid v2edid; - unsigned long vx; - int vi; - } karg; void __user *up = compat_ptr(arg); + void __user *up_native = NULL; + void __user *aux_buf; + u32 aux_space; int compatible_arg = 1; long err = 0;
@@ -866,30 +1040,52 @@ static long do_video_ioctl(struct file * case VIDIOC_STREAMOFF: case VIDIOC_S_INPUT: case VIDIOC_S_OUTPUT: - err = get_user(karg.vi, (s32 __user *)up); + err = alloc_userspace(sizeof(unsigned int), 0, &up_native); + if (!err && assign_in_user((unsigned int __user *)up_native, + (compat_uint_t __user *)up)) + err = -EFAULT; compatible_arg = 0; break;
case VIDIOC_G_INPUT: case VIDIOC_G_OUTPUT: + err = alloc_userspace(sizeof(unsigned int), 0, &up_native); compatible_arg = 0; break;
case VIDIOC_G_EDID: case VIDIOC_S_EDID: - err = get_v4l2_edid32(&karg.v2edid, up); + err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native); + if (!err) + err = get_v4l2_edid32(up_native, up); compatible_arg = 0; break;
case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: - err = get_v4l2_format32(&karg.v2f, up); + err = bufsize_v4l2_format(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_format), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_format); + err = get_v4l2_format32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break;
case VIDIOC_CREATE_BUFS: - err = get_v4l2_create32(&karg.v2crt, up); + err = bufsize_v4l2_create(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_create_buffers), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_create_buffers); + err = get_v4l2_create32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break;
@@ -897,36 +1093,63 @@ static long do_video_ioctl(struct file * case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: - err = get_v4l2_buffer32(&karg.v2b, up); + err = bufsize_v4l2_buffer(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_buffer), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_buffer); + err = get_v4l2_buffer32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break;
case VIDIOC_S_FBUF: - err = get_v4l2_framebuffer32(&karg.v2fb, up); + err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, + &up_native); + if (!err) + err = get_v4l2_framebuffer32(up_native, up); compatible_arg = 0; break;
case VIDIOC_G_FBUF: + err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, + &up_native); compatible_arg = 0; break;
case VIDIOC_ENUMSTD: - err = get_v4l2_standard32(&karg.v2s, up); + err = alloc_userspace(sizeof(struct v4l2_standard), 0, + &up_native); + if (!err) + err = get_v4l2_standard32(up_native, up); compatible_arg = 0; break;
case VIDIOC_ENUMINPUT: - err = get_v4l2_input32(&karg.v2i, up); + err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native); + if (!err) + err = get_v4l2_input32(up_native, up); compatible_arg = 0; break;
case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(file, &karg.v2ecs, up); + err = bufsize_v4l2_ext_controls(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_ext_controls), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_ext_controls); + err = get_v4l2_ext_controls32(file, up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break; case VIDIOC_DQEVENT: + err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native); compatible_arg = 0; break; } @@ -935,25 +1158,26 @@ static long do_video_ioctl(struct file *
if (compatible_arg) err = native_ioctl(file, cmd, (unsigned long)up); - else { - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - err = native_ioctl(file, cmd, (unsigned long)&karg); - set_fs(old_fs); - } + else + err = native_ioctl(file, cmd, (unsigned long)up_native);
if (err == -ENOTTY) return err;
- /* Special case: even after an error we need to put the - results back for these ioctls since the error_idx will - contain information on which control failed. */ + /* + * Special case: even after an error we need to put the + * results back for these ioctls since the error_idx will + * contain information on which control failed. + */ switch (cmd) { case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) + if (put_v4l2_ext_controls32(file, up_native, up)) + err = -EFAULT; + break; + case VIDIOC_S_EDID: + if (put_v4l2_edid32(up_native, up)) err = -EFAULT; break; } @@ -965,45 +1189,46 @@ static long do_video_ioctl(struct file * case VIDIOC_S_OUTPUT: case VIDIOC_G_INPUT: case VIDIOC_G_OUTPUT: - err = put_user(((s32)karg.vi), (s32 __user *)up); + if (assign_in_user((compat_uint_t __user *)up, + ((unsigned int __user *)up_native))) + err = -EFAULT; break;
case VIDIOC_G_FBUF: - err = put_v4l2_framebuffer32(&karg.v2fb, up); + err = put_v4l2_framebuffer32(up_native, up); break;
case VIDIOC_DQEVENT: - err = put_v4l2_event32(&karg.v2ev, up); + err = put_v4l2_event32(up_native, up); break;
case VIDIOC_G_EDID: - case VIDIOC_S_EDID: - err = put_v4l2_edid32(&karg.v2edid, up); + err = put_v4l2_edid32(up_native, up); break;
case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: - err = put_v4l2_format32(&karg.v2f, up); + err = put_v4l2_format32(up_native, up); break;
case VIDIOC_CREATE_BUFS: - err = put_v4l2_create32(&karg.v2crt, up); + err = put_v4l2_create32(up_native, up); break;
case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: - err = put_v4l2_buffer32(&karg.v2b, up); + err = put_v4l2_buffer32(up_native, up); break;
case VIDIOC_ENUMSTD: - err = put_v4l2_standard32(&karg.v2s, up); + err = put_v4l2_standard32(up_native, up); break;
case VIDIOC_ENUMINPUT: - err = put_v4l2_input32(&karg.v2i, up); + err = put_v4l2_input32(up_native, up); break; } return err;
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
This is a note to let you know that I've just added the patch titled
media: v4l2-ctrls: fix sparse warning
to the 3.18-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: media-v4l2-ctrls-fix-sparse-warning.patch and it can be found in the queue-3.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From foo@baz Wed Apr 4 17:30:18 CEST 2018
From: Mauro Carvalho Chehab mchehab@s-opensource.com Date: Wed, 28 Mar 2018 15:12:34 -0300 Subject: media: v4l2-ctrls: fix sparse warning To: Linux Media Mailing List linux-media@vger.kernel.org, stable@vger.kernel.org Cc: Hans Verkuil hans.verkuil@cisco.com, Mauro Carvalho Chehab mchehab@infradead.org, Linux Kernel Mailing List linux-kernel@vger.kernel.org, Mauro Carvalho Chehab mchehab@osg.samsung.com, Mauro Carvalho Chehab mchehab@s-opensource.com Message-ID: d53d22eb0ea4cdbcb2e7f02d789a01892d8c36cf.1522260310.git.mchehab@s-opensource.com
From: Hans Verkuil hans.verkuil@cisco.com
The warning is simple:
drivers/media/v4l2-core/v4l2-ctrls.c:1685:15: warning: incorrect type in assignment (different address spaces)
but the fix isn't.
The core problem was that the conversion from user to kernelspace was done at too low a level and that needed to be moved up. That made it possible to drop pointers to v4l2_ext_control from set_ctrl and validate_new and clean up this sparse warning because those functions now always operate on kernelspace pointers.
Signed-off-by: Hans Verkuil hans.verkuil@cisco.com Signed-off-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/media/v4l2-core/v4l2-ctrls.c | 87 ++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 35 deletions(-)
--- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1668,10 +1668,8 @@ static int check_range(enum v4l2_ctrl_ty }
/* Validate a new control */ -static int validate_new(const struct v4l2_ctrl *ctrl, - struct v4l2_ext_control *c) +static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) { - union v4l2_ctrl_ptr ptr; unsigned idx; int err = 0;
@@ -1684,19 +1682,14 @@ static int validate_new(const struct v4l case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BUTTON: case V4L2_CTRL_TYPE_CTRL_CLASS: - ptr.p_s32 = &c->value; - return ctrl->type_ops->validate(ctrl, 0, ptr); - case V4L2_CTRL_TYPE_INTEGER64: - ptr.p_s64 = &c->value64; - return ctrl->type_ops->validate(ctrl, 0, ptr); + return ctrl->type_ops->validate(ctrl, 0, p_new); default: break; } } - ptr.p = c->ptr; - for (idx = 0; !err && idx < c->size / ctrl->elem_size; idx++) - err = ctrl->type_ops->validate(ctrl, idx, ptr); + for (idx = 0; !err && idx < ctrl->elems; idx++) + err = ctrl->type_ops->validate(ctrl, idx, p_new); return err; }
@@ -3020,6 +3013,7 @@ static int validate_ctrls(struct v4l2_ex cs->error_idx = cs->count; for (i = 0; i < cs->count; i++) { struct v4l2_ctrl *ctrl = helpers[i].ctrl; + union v4l2_ctrl_ptr p_new;
cs->error_idx = i;
@@ -3033,7 +3027,17 @@ static int validate_ctrls(struct v4l2_ex best-effort to avoid that. */ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) return -EBUSY; - ret = validate_new(ctrl, &cs->controls[i]); + /* + * Skip validation for now if the payload needs to be copied + * from userspace into kernelspace. We'll validate those later. + */ + if (ctrl->is_ptr) + continue; + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + p_new.p_s64 = &cs->controls[i].value64; + else + p_new.p_s32 = &cs->controls[i].value; + ret = validate_new(ctrl, p_new); if (ret) return ret; } @@ -3128,7 +3132,11 @@ static int try_set_ext_ctrls(struct v4l2 /* Copy the new caller-supplied control values. user_to_new() sets 'is_new' to 1. */ do { - ret = user_to_new(cs->controls + idx, helpers[idx].ctrl); + struct v4l2_ctrl *ctrl = helpers[idx].ctrl; + + ret = user_to_new(cs->controls + idx, ctrl); + if (!ret && ctrl->is_ptr) + ret = validate_new(ctrl, ctrl->p_new); idx = helpers[idx].next; } while (!ret && idx);
@@ -3178,10 +3186,10 @@ int v4l2_subdev_s_ext_ctrls(struct v4l2_ EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
/* Helper function for VIDIOC_S_CTRL compatibility */ -static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, - struct v4l2_ext_control *c, u32 ch_flags) +static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) { struct v4l2_ctrl *master = ctrl->cluster[0]; + int ret; int i;
/* Reset the 'is_new' flags of the cluster */ @@ -3189,8 +3197,9 @@ static int set_ctrl(struct v4l2_fh *fh, if (master->cluster[i]) master->cluster[i]->is_new = 0;
- if (c) - user_to_new(c, ctrl); + ret = validate_new(ctrl, ctrl->p_new); + if (ret) + return ret;
/* For autoclusters with volatiles that are switched from auto to manual mode we have to update the current volatile values since @@ -3207,15 +3216,14 @@ static int set_ctrl(struct v4l2_fh *fh, static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c) { - int ret = validate_new(ctrl, c); + int ret;
- if (!ret) { - v4l2_ctrl_lock(ctrl); - ret = set_ctrl(fh, ctrl, c, 0); - if (!ret) - cur_to_user(c, ctrl); - v4l2_ctrl_unlock(ctrl); - } + v4l2_ctrl_lock(ctrl); + user_to_new(c, ctrl); + ret = set_ctrl(fh, ctrl, 0); + if (!ret) + cur_to_user(c, ctrl); + v4l2_ctrl_unlock(ctrl); return ret; }
@@ -3223,7 +3231,7 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, stru struct v4l2_control *control) { struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); - struct v4l2_ext_control c; + struct v4l2_ext_control c = { control->id }; int ret;
if (ctrl == NULL || !ctrl->is_int) @@ -3252,7 +3260,7 @@ int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl /* It's a driver bug if this happens. */ WARN_ON(!ctrl->is_int); ctrl->val = val; - return set_ctrl(NULL, ctrl, NULL, 0); + return set_ctrl(NULL, ctrl, 0); } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl);
@@ -3263,7 +3271,7 @@ int __v4l2_ctrl_s_ctrl_int64(struct v4l2 /* It's a driver bug if this happens. */ WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64); *ctrl->p_new.p_s64 = val; - return set_ctrl(NULL, ctrl, NULL, 0); + return set_ctrl(NULL, ctrl, 0); } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64);
@@ -3274,7 +3282,7 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l /* It's a driver bug if this happens. */ WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING); strlcpy(ctrl->p_new.p_char, s, ctrl->maximum + 1); - return set_ctrl(NULL, ctrl, NULL, 0); + return set_ctrl(NULL, ctrl, 0); } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
@@ -3297,8 +3305,8 @@ EXPORT_SYMBOL(v4l2_ctrl_notify); int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, s64 min, s64 max, u64 step, s64 def) { + bool changed; int ret; - struct v4l2_ext_control c;
lockdep_assert_held(ctrl->handler->lock);
@@ -3325,11 +3333,20 @@ int __v4l2_ctrl_modify_range(struct v4l2 ctrl->maximum = max; ctrl->step = step; ctrl->default_value = def; - c.value = *ctrl->p_cur.p_s32; - if (validate_new(ctrl, &c)) - c.value = def; - if (c.value != *ctrl->p_cur.p_s32) - ret = set_ctrl(NULL, ctrl, &c, V4L2_EVENT_CTRL_CH_RANGE); + cur_to_new(ctrl); + if (validate_new(ctrl, ctrl->p_new)) { + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + *ctrl->p_new.p_s64 = def; + else + *ctrl->p_new.p_s32 = def; + } + + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64; + else + changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32; + if (changed) + ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); else send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); return ret;
Patches currently in stable-queue which might be from mchehab@s-opensource.com are
queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch queue-3.18/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch queue-3.18/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch
On Wed, Mar 28, 2018 at 03:12:19PM -0300, Mauro Carvalho Chehab wrote:
Hi Greg,
Those are the backports meant to solve CVE-2017-13166 on Kernel 3.18.
It contains two v4l2-ctrls fixes that are required to avoid crashes at the test application.
I wrote two patches myself for Kernel 3.18 in order to solve some issues specific for Kernel 3.18 with aren't needed upstream. one is actually a one-line change backport. The other one makes sure that both 32-bits and 64-bits version of some ioctl calls will return the same value for a reserved field.
I noticed an extra bug while testing it, but the bug also hits upstream, and should be backported all the way down all stable/LTS versions. So, I'll send it the usual way, after merging upsream.
I've queued these all up now, thanks.
greg k-h
linux-stable-mirror@lists.linaro.org