From: Greg Kroah-Hartman Date: Wed, 4 Apr 2018 15:32:37 +0000 (+0200) Subject: 3.18-stable patches X-Git-Tag: v3.18.103~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=acec1a87b870a6610387bc39c77e84ac8372a185;p=thirdparty%2Fkernel%2Fstable-queue.git 3.18-stable patches added patches: media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch media-v4l2-compat-ioctl32.c-fix-the-indentation.patch media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch media-v4l2-ctrls-fix-sparse-warning.patch --- diff --git a/queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch b/queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch new file mode 100644 index 00000000000..624843ea603 --- /dev/null +++ b/queue-3.18/media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch @@ -0,0 +1,41 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +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 , stable@vger.kernel.org +Cc: Ricardo Ribalda , Mauro Carvalho Chehab , Linux Kernel Mailing List , Hans Verkuil , Mauro Carvalho Chehab , Mauro Carvalho Chehab +Message-ID: <1663cf48e2eb96405c5d6d874020aa9925ee217f.1522260310.git.mchehab@s-opensource.com> + +From: Ricardo Ribalda + +Volatile controls should not generate CH_VALUE events. + +Set has_changed to false to prevent this happening. + +Signed-off-by: Ricardo Ribalda Delgado +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch b/queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch new file mode 100644 index 00000000000..5d8cbb8ad7e --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch @@ -0,0 +1,57 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +Date: Wed, 28 Mar 2018 15:12:29 -0300 +Subject: media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha +To: Linux Media Mailing List , stable@vger.kernel.org +Cc: Daniel Mentz , Mauro Carvalho Chehab , Linux Kernel Mailing List , Hans Verkuil , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <63c220c11ade842157669d03bdaf10b84a6d91a9.1522260310.git.mchehab@s-opensource.com> + +From: Daniel Mentz + +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 +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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; + } diff --git a/queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch b/queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch new file mode 100644 index 00000000000..dee4adc5b74 --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch @@ -0,0 +1,36 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +Date: Wed, 28 Mar 2018 15:12:37 -0300 +Subject: media: v4l2-compat-ioctl32: initialize a reserved field +To: Linux Media Mailing List , stable@vger.kernel.org +Cc: Mauro Carvalho Chehab , Mauro Carvalho Chehab , Linux Kernel Mailing List +Message-ID: + +From: Mauro Carvalho Chehab + +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch b/queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch new file mode 100644 index 00000000000..34938805cda --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch @@ -0,0 +1,30 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +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 , stable@vger.kernel.org +Cc: Mauro Carvalho Chehab , Mauro Carvalho Chehab , Linux Kernel Mailing List +Message-ID: <2ba9505436180b463d47d6da4ce5e059b383938e.1522260310.git.mchehab@s-opensource.com> + +From: Mauro Carvalho Chehab + +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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]; diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch new file mode 100644 index 00000000000..53687d1b8a1 --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch @@ -0,0 +1,33 @@ +From 3ee6d040719ae09110e5cdf24d5386abe5d1b776 Mon Sep 17 00:00:00 2001 +From: Hans Verkuil +Date: Wed, 24 Jan 2018 08:37:04 -0500 +Subject: media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Cc: # for v4.15 and up +Signed-off-by: Sasha Levin +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1 + + 1 file changed, 1 insertion(+) + +--- 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 * + err = put_v4l2_create32(&karg.v2crt, up); + break; + ++ case VIDIOC_PREPARE_BUF: + case VIDIOC_QUERYBUF: + case VIDIOC_QBUF: + case VIDIOC_DQBUF: diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch new file mode 100644 index 00000000000..7c12482402d --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch @@ -0,0 +1,323 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +Date: Wed, 28 Mar 2018 15:12:25 -0300 +Subject: media: v4l2-compat-ioctl32.c: avoid sizeof(type) +To: Linux Media Mailing List , stable@vger.kernel.org +Cc: Hans Verkuil , Mauro Carvalho Chehab , Linux Kernel Mailing List , Mauro Carvalho Chehab , Sasha Levin +Message-ID: + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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) || diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch new file mode 100644 index 00000000000..424947af038 --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch @@ -0,0 +1,112 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +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 , stable@vger.kernel.org +Cc: Hans Verkuil , Mauro Carvalho Chehab , Linux Kernel Mailing List , Mauro Carvalho Chehab , Sasha Levin +Message-ID: + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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; + } + diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch new file mode 100644 index 00000000000..2645bd4ed54 --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch @@ -0,0 +1,133 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +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 , stable@vger.kernel.org +Cc: Hans Verkuil , Mauro Carvalho Chehab , Linux Kernel Mailing List , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <6e6f38fc8542cf41fffcd3067026c4f015564544.1522260310.git.mchehab@s-opensource.com> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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; diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch new file mode 100644 index 00000000000..d488901b66f --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch @@ -0,0 +1,37 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +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 , stable@vger.kernel.org +Cc: Hans Verkuil , Mauro Carvalho Chehab , Linux Kernel Mailing List , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <9d0bb62c2dc7caee1fd2b9199fc1a22ec8479395.1522260310.git.mchehab@s-opensource.com> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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. */ diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch new file mode 100644 index 00000000000..4d59d4058a1 --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch @@ -0,0 +1,45 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +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 , stable@vger.kernel.org +Cc: Hans Verkuil , Mauro Carvalho Chehab , Linux Kernel Mailing List , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <8f000de7f9babd3f104eacbd7e79fbd72372c9d1.1522260310.git.mchehab@s-opensource.com> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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; + } + } diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch new file mode 100644 index 00000000000..6b85af3ff28 --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch @@ -0,0 +1,145 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +Date: Wed, 28 Mar 2018 15:12:27 -0300 +Subject: media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer +To: Linux Media Mailing List , stable@vger.kernel.org +Cc: Hans Verkuil , Mauro Carvalho Chehab , Linux Kernel Mailing List , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <63df92f6981785c5e31c1d8e796e827344cc75f3.1522260310.git.mchehab@s-opensource.com> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include ++#include + #include + + 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; + } diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch new file mode 100644 index 00000000000..c7a26eab9bb --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch @@ -0,0 +1,445 @@ +From b7b957d429f601d6d1942122b339474f31191d75 Mon Sep 17 00:00:00 2001 +From: Hans Verkuil +Date: Wed, 24 Jan 2018 04:35:48 -0500 +Subject: media: v4l2-compat-ioctl32.c: fix the indentation + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Cc: # for v4.15 and up +Signed-off-by: Sasha Levin +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 216 +++++++++++++------------- + 1 file changed, 108 insertions(+), 108 deletions(-) + +--- 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 + 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(st + } + + 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(st + } + + 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 v4 + 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 v4 + 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 v4 + { + /* 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 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)) || +- 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_ + 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_ + } + + 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 + 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 + + 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 + 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 + 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 + 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 + 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(struc + } + + 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(struc + 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(struc + 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(struc + 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(struc + 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_e + 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_e + 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; + } + diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch new file mode 100644 index 00000000000..9b2264c0d7e --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch @@ -0,0 +1,44 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +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 , stable@vger.kernel.org +Cc: Hans Verkuil , Mauro Carvalho Chehab , Linux Kernel Mailing List , Hans Verkuil , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <39d6997be9988f81bce42a00115b062aac7b0a51.1522260310.git.mchehab@s-opensource.com> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Reported-by: Laurent Pinchart +Reviewed-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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) && diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch new file mode 100644 index 00000000000..40382b810f2 --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch @@ -0,0 +1,150 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +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 , stable@vger.kernel.org +Cc: Hans Verkuil , Mauro Carvalho Chehab , Linux Kernel Mailing List , Mauro Carvalho Chehab , Sasha Levin +Message-ID: + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch b/queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch new file mode 100644 index 00000000000..48e2c28d4b3 --- /dev/null +++ b/queue-3.18/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch @@ -0,0 +1,1317 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +Date: Wed, 28 Mar 2018 15:12:33 -0300 +Subject: media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic +To: Linux Media Mailing List , stable@vger.kernel.org +Cc: Daniel Mentz , Mauro Carvalho Chehab , Linux Kernel Mailing List , Hans Verkuil , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <10af8cdf1226db8dfc7e85673ee3a7a17ba969f2.1522260310.git.mchehab@s-opensource.com> + +From: Daniel Mentz + +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/97b733953c06e4f0398ade18850f0817778255f7 + +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 +Co-developed-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + ++/* 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; diff --git a/queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch b/queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch new file mode 100644 index 00000000000..8debc5774d6 --- /dev/null +++ b/queue-3.18/media-v4l2-ctrls-fix-sparse-warning.patch @@ -0,0 +1,227 @@ +From foo@baz Wed Apr 4 17:30:18 CEST 2018 +From: Mauro Carvalho Chehab +Date: Wed, 28 Mar 2018 15:12:34 -0300 +Subject: media: v4l2-ctrls: fix sparse warning +To: Linux Media Mailing List , stable@vger.kernel.org +Cc: Hans Verkuil , Mauro Carvalho Chehab , Linux Kernel Mailing List , Mauro Carvalho Chehab , Mauro Carvalho Chehab +Message-ID: + +From: Hans Verkuil + +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 +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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; diff --git a/queue-3.18/series b/queue-3.18/series index 1f8be5947bf..a1aba0c8312 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -56,3 +56,19 @@ bluetooth-fix-missing-encryption-refresh-on-security-request.patch scsi-virtio_scsi-always-read-vpd-pages-for-multiqueue-too.patch media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch +media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch +media-v4l2-compat-ioctl32.c-fix-the-indentation.patch +media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch +media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch +media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch +media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch +media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch +media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch +media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch +media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch +media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch +media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch +media-v4l2-ctrls-fix-sparse-warning.patch +media-media-v4l2-ctrls-volatiles-should-not-generate-ch_value.patch +media-v4l2-compat-ioctl32-use-compat_u64-for-video-standard.patch +media-v4l2-compat-ioctl32-initialize-a-reserved-field.patch