--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:35 -0300
+Subject: media: media/v4l2-ctrls: volatiles should not generate CH_VALUE
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Ricardo Ribalda <ricardo.ribalda@gmail.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@osg.samsung.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <1663cf48e2eb96405c5d6d874020aa9925ee217f.1522260310.git.mchehab@s-opensource.com>
+
+From: Ricardo Ribalda <ricardo.ribalda@gmail.com>
+
+Volatile controls should not generate CH_VALUE events.
+
+Set has_changed to false to prevent this happening.
+
+Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-ctrls.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/media/v4l2-core/v4l2-ctrls.c
++++ b/drivers/media/v4l2-core/v4l2-ctrls.c
+@@ -1619,6 +1619,15 @@ static int cluster_changed(struct v4l2_c
+
+ if (ctrl == NULL)
+ continue;
++ /*
++ * Set has_changed to false to avoid generating
++ * the event V4L2_EVENT_CTRL_CH_VALUE
++ */
++ if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
++ ctrl->has_changed = false;
++ continue;
++ }
++
+ for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
+ ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
+ ctrl->p_cur, ctrl->p_new);
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:29 -0300
+Subject: media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Daniel Mentz <danielmentz@google.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>, Sasha Levin <alexander.levin@microsoft.com>
+Message-ID: <63c220c11ade842157669d03bdaf10b84a6d91a9.1522260310.git.mchehab@s-opensource.com>
+
+From: Daniel Mentz <danielmentz@google.com>
+
+commit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream.
+
+Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output
+overlays.") added the field global_alpha to struct v4l2_window but did
+not update the compat layer accordingly. This change adds global_alpha
+to struct v4l2_window32 and copies the value for global_alpha back and
+forth.
+
+Signed-off-by: Daniel Mentz <danielmentz@google.com>
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -45,6 +45,7 @@ struct v4l2_window32 {
+ compat_caddr_t clips; /* actually struct v4l2_clip32 * */
+ __u32 clipcount;
+ compat_caddr_t bitmap;
++ __u8 global_alpha;
+ };
+
+ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+@@ -53,7 +54,8 @@ static int get_v4l2_window32(struct v4l2
+ copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
+ get_user(kp->field, &up->field) ||
+ get_user(kp->chromakey, &up->chromakey) ||
+- get_user(kp->clipcount, &up->clipcount))
++ get_user(kp->clipcount, &up->clipcount) ||
++ get_user(kp->global_alpha, &up->global_alpha))
+ return -EFAULT;
+ if (kp->clipcount > 2048)
+ return -EINVAL;
+@@ -86,7 +88,8 @@ static int put_v4l2_window32(struct v4l2
+ if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
+ put_user(kp->field, &up->field) ||
+ put_user(kp->chromakey, &up->chromakey) ||
+- put_user(kp->clipcount, &up->clipcount))
++ put_user(kp->clipcount, &up->clipcount) ||
++ put_user(kp->global_alpha, &up->global_alpha))
+ return -EFAULT;
+ return 0;
+ }
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:37 -0300
+Subject: media: v4l2-compat-ioctl32: initialize a reserved field
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Mauro Carvalho Chehab <mchehab@s-opensource.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
+Message-ID: <d8a647b26822fb0a86f6ee7dff4d6eb1e85e1398.1522260310.git.mchehab@s-opensource.com>
+
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+
+The get_v4l2_create32() function is missing a logic with
+would be cleaning a reserved field, causing v4l2-compliance
+to complain:
+
+ Buffer ioctls (Input 0):
+ fail: v4l2-test-buffers.cpp(506): check_0(crbufs.reserved, sizeof(crbufs.reserved))
+ test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: FAIL
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -247,7 +247,8 @@ static int get_v4l2_create32(struct v4l2
+ {
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ copy_in_user(kp, up,
+- offsetof(struct v4l2_create_buffers32, format)))
++ offsetof(struct v4l2_create_buffers32, format)) ||
++ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+ return -EFAULT;
+ return __get_v4l2_format32(&kp->format, &up->format,
+ aux_buf, aux_space);
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:36 -0300
+Subject: media: v4l2-compat-ioctl32: use compat_u64 for video standard
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Mauro Carvalho Chehab <mchehab@s-opensource.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
+Message-ID: <2ba9505436180b463d47d6da4ce5e059b383938e.1522260310.git.mchehab@s-opensource.com>
+
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+
+Instead of using the "v4l2_std_id" typedef, use compat_u64,
+as otherwise it fails to properly handle some ioctls.
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -686,7 +686,7 @@ struct v4l2_input32 {
+ __u32 type; /* Type of input */
+ __u32 audioset; /* Associated audios (bitfield) */
+ __u32 tuner; /* Associated tuner */
+- v4l2_std_id std;
++ compat_u64 std;
+ __u32 status;
+ __u32 capabilities;
+ __u32 reserved[3];
--- /dev/null
+From 3ee6d040719ae09110e5cdf24d5386abe5d1b776 Mon Sep 17 00:00:00 2001
+From: Hans Verkuil <hans.verkuil@cisco.com>
+Date: Wed, 24 Jan 2018 08:37:04 -0500
+Subject: media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 3ee6d040719ae09110e5cdf24d5386abe5d1b776 upstream.
+
+The result of the VIDIOC_PREPARE_BUF ioctl was never copied back
+to userspace since it was missing in the switch.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Cc: <stable@vger.kernel.org> # for v4.15 and up
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 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:
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:25 -0300
+Subject: media: v4l2-compat-ioctl32.c: avoid sizeof(type)
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Mauro Carvalho Chehab <mchehab@s-opensource.com>, Sasha Levin <alexander.levin@microsoft.com>
+Message-ID: <b2ea40bb0147ce21cf35781d842cba0d60f7e07f.1522260310.git.mchehab@s-opensource.com>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 333b1e9f96ce05f7498b581509bb30cde03018bf upstream.
+
+Instead of doing sizeof(struct foo) use sizeof(*up). There even were
+cases where 4 * sizeof(__u32) was used instead of sizeof(kp->reserved),
+which is very dangerous when the size of the reserved array changes.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 80 ++++++++++++--------------
+ 1 file changed, 38 insertions(+), 42 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -47,7 +47,7 @@ struct v4l2_window32 {
+
+ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+ {
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
+ get_user(kp->field, &up->field) ||
+ get_user(kp->chromakey, &up->chromakey) ||
+@@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2
+ if (get_user(p, &up->clips))
+ return -EFAULT;
+ uclips = compat_ptr(p);
+- kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
++ kclips = compat_alloc_user_space(n * sizeof(*kclips));
+ kp->clips = kclips;
+ while (--n >= 0) {
+ if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+@@ -152,14 +152,14 @@ static int __get_v4l2_format32(struct v4
+
+ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+ {
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)))
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+ return -EFAULT;
+ return __get_v4l2_format32(kp, up);
+ }
+
+ static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+ {
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
+ return -EFAULT;
+ return __get_v4l2_format32(&kp->format, &up->format);
+@@ -196,17 +196,17 @@ static int __put_v4l2_format32(struct v4
+
+ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+ {
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
+- put_user(kp->type, &up->type))
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
+ return -EFAULT;
+ return __put_v4l2_format32(kp, up);
+ }
+
+ static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+ {
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
+- copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt)))
+- return -EFAULT;
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
++ copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) ||
++ copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
++ return -EFAULT;
+ return __put_v4l2_format32(&kp->format, &up->format);
+ }
+
+@@ -222,7 +222,7 @@ struct v4l2_standard32 {
+ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+ {
+ /* other fields are not set by the user, nor used by the driver */
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ get_user(kp->index, &up->index))
+ return -EFAULT;
+ return 0;
+@@ -230,13 +230,13 @@ static int get_v4l2_standard32(struct v4
+
+ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+ {
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ put_user(kp->index, &up->index) ||
+ copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
+- copy_to_user(up->name, kp->name, 24) ||
++ copy_to_user(up->name, kp->name, sizeof(up->name)) ||
+ copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
+ put_user(kp->framelines, &up->framelines) ||
+- copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
++ copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+ return -EFAULT;
+ return 0;
+ }
+@@ -284,7 +284,7 @@ static int get_v4l2_plane32(struct v4l2_
+
+ if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
+ copy_in_user(&up->data_offset, &up32->data_offset,
+- sizeof(__u32)))
++ sizeof(up->data_offset)))
+ return -EFAULT;
+
+ if (memory == V4L2_MEMORY_USERPTR) {
+@@ -294,11 +294,11 @@ static int get_v4l2_plane32(struct v4l2_
+ if (put_user((unsigned long)up_pln, &up->m.userptr))
+ return -EFAULT;
+ } else if (memory == V4L2_MEMORY_DMABUF) {
+- if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int)))
++ if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
+ return -EFAULT;
+ } else {
+ if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+- sizeof(__u32)))
++ sizeof(up32->m.mem_offset)))
+ return -EFAULT;
+ }
+
+@@ -310,19 +310,19 @@ static int put_v4l2_plane32(struct v4l2_
+ {
+ if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
+ copy_in_user(&up32->data_offset, &up->data_offset,
+- sizeof(__u32)))
++ sizeof(up->data_offset)))
+ return -EFAULT;
+
+ /* For MMAP, driver might've set up the offset, so copy it back.
+ * USERPTR stays the same (was userspace-provided), so no copying. */
+ if (memory == V4L2_MEMORY_MMAP)
+ if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
+- sizeof(__u32)))
++ sizeof(up->m.mem_offset)))
+ return -EFAULT;
+ /* For DMABUF, driver might've set up the fd, so copy it back. */
+ if (memory == V4L2_MEMORY_DMABUF)
+ if (copy_in_user(&up32->m.fd, &up->m.fd,
+- sizeof(int)))
++ sizeof(up->m.fd)))
+ return -EFAULT;
+
+ return 0;
+@@ -336,7 +336,7 @@ static int get_v4l2_buffer32(struct v4l2
+ int num_planes;
+ int ret;
+
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ get_user(kp->index, &up->index) ||
+ get_user(kp->type, &up->type) ||
+ get_user(kp->flags, &up->flags) ||
+@@ -348,8 +348,7 @@ static int get_v4l2_buffer32(struct v4l2
+ if (get_user(kp->bytesused, &up->bytesused) ||
+ get_user(kp->field, &up->field) ||
+ get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+- get_user(kp->timestamp.tv_usec,
+- &up->timestamp.tv_usec))
++ get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec))
+ return -EFAULT;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+@@ -366,13 +365,12 @@ static int get_v4l2_buffer32(struct v4l2
+
+ uplane32 = compat_ptr(p);
+ if (!access_ok(VERIFY_READ, uplane32,
+- num_planes * sizeof(struct v4l2_plane32)))
++ num_planes * sizeof(*uplane32)))
+ return -EFAULT;
+
+ /* We don't really care if userspace decides to kill itself
+ * by passing a very big num_planes value */
+- uplane = compat_alloc_user_space(num_planes *
+- sizeof(struct v4l2_plane));
++ uplane = compat_alloc_user_space(num_planes * sizeof(*uplane));
+ kp->m.planes = (__force struct v4l2_plane *)uplane;
+
+ while (--num_planes >= 0) {
+@@ -420,7 +418,7 @@ static int put_v4l2_buffer32(struct v4l2
+ int num_planes;
+ int ret;
+
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ put_user(kp->index, &up->index) ||
+ put_user(kp->type, &up->type) ||
+ put_user(kp->flags, &up->flags) ||
+@@ -431,7 +429,7 @@ static int put_v4l2_buffer32(struct v4l2
+ put_user(kp->field, &up->field) ||
+ put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+ put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
+- copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
++ copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
+ put_user(kp->sequence, &up->sequence) ||
+ put_user(kp->reserved2, &up->reserved2) ||
+ put_user(kp->reserved, &up->reserved) ||
+@@ -499,7 +497,7 @@ static int get_v4l2_framebuffer32(struct
+ {
+ u32 tmp;
+
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ get_user(tmp, &up->base) ||
+ get_user(kp->capability, &up->capability) ||
+ get_user(kp->flags, &up->flags) ||
+@@ -513,7 +511,7 @@ static int put_v4l2_framebuffer32(struct
+ {
+ u32 tmp = (u32)((unsigned long)kp->base);
+
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ put_user(tmp, &up->base) ||
+ put_user(kp->capability, &up->capability) ||
+ put_user(kp->flags, &up->flags) ||
+@@ -537,14 +535,14 @@ struct v4l2_input32 {
+ Otherwise it is identical to the 32-bit version. */
+ static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+ {
+- if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
++ if (copy_from_user(kp, up, sizeof(*up)))
+ return -EFAULT;
+ return 0;
+ }
+
+ static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+ {
+- if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
++ if (copy_to_user(up, kp, sizeof(*up)))
+ return -EFAULT;
+ return 0;
+ }
+@@ -592,7 +590,7 @@ static int get_v4l2_ext_controls32(struc
+ int n;
+ compat_caddr_t p;
+
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ get_user(kp->ctrl_class, &up->ctrl_class) ||
+ get_user(kp->count, &up->count) ||
+ get_user(kp->error_idx, &up->error_idx) ||
+@@ -606,10 +604,9 @@ static int get_v4l2_ext_controls32(struc
+ if (get_user(p, &up->controls))
+ return -EFAULT;
+ ucontrols = compat_ptr(p);
+- if (!access_ok(VERIFY_READ, ucontrols,
+- n * sizeof(struct v4l2_ext_control32)))
++ if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols)))
+ return -EFAULT;
+- kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
++ kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols));
+ kp->controls = (__force struct v4l2_ext_control *)kcontrols;
+ while (--n >= 0) {
+ u32 id;
+@@ -641,7 +638,7 @@ static int put_v4l2_ext_controls32(struc
+ int n = kp->count;
+ compat_caddr_t p;
+
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ put_user(kp->ctrl_class, &up->ctrl_class) ||
+ put_user(kp->count, &up->count) ||
+ put_user(kp->error_idx, &up->error_idx) ||
+@@ -653,8 +650,7 @@ static int put_v4l2_ext_controls32(struc
+ if (get_user(p, &up->controls))
+ return -EFAULT;
+ ucontrols = compat_ptr(p);
+- if (!access_ok(VERIFY_WRITE, ucontrols,
+- n * sizeof(struct v4l2_ext_control32)))
++ if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols)))
+ return -EFAULT;
+
+ while (--n >= 0) {
+@@ -690,7 +686,7 @@ struct v4l2_event32 {
+
+ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
+ {
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ put_user(kp->type, &up->type) ||
+ copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
+ put_user(kp->pending, &up->pending) ||
+@@ -698,7 +694,7 @@ static int put_v4l2_event32(struct v4l2_
+ put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+ put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) ||
+ put_user(kp->id, &up->id) ||
+- copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
++ copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+ return -EFAULT;
+ return 0;
+ }
+@@ -715,7 +711,7 @@ static int get_v4l2_edid32(struct v4l2_e
+ {
+ u32 tmp;
+
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ get_user(kp->pad, &up->pad) ||
+ get_user(kp->start_block, &up->start_block) ||
+ get_user(kp->blocks, &up->blocks) ||
+@@ -730,7 +726,7 @@ static int put_v4l2_edid32(struct v4l2_e
+ {
+ u32 tmp = (u32)((unsigned long)kp->edid);
+
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ put_user(kp->pad, &up->pad) ||
+ put_user(kp->start_block, &up->start_block) ||
+ put_user(kp->blocks, &up->blocks) ||
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:30 -0300
+Subject: media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Mauro Carvalho Chehab <mchehab@s-opensource.com>, Sasha Levin <alexander.levin@microsoft.com>
+Message-ID: <b203ca17a23bf02398ef39e8f123d30b74df3523.1522260310.git.mchehab@s-opensource.com>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit a751be5b142ef6bcbbb96d9899516f4d9c8d0ef4 upstream.
+
+put_v4l2_window32() didn't copy back the clip list to userspace.
+Drivers can update the clip rectangles, so this should be done.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 +++++++++++++++++---------
+ 1 file changed, 40 insertions(+), 19 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -50,6 +50,11 @@ struct v4l2_window32 {
+
+ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+ {
++ struct v4l2_clip32 __user *uclips;
++ struct v4l2_clip __user *kclips;
++ compat_caddr_t p;
++ u32 n;
++
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
+ get_user(kp->field, &up->field) ||
+@@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2
+ return -EFAULT;
+ if (kp->clipcount > 2048)
+ return -EINVAL;
+- if (kp->clipcount) {
+- struct v4l2_clip32 __user *uclips;
+- struct v4l2_clip __user *kclips;
+- int n = kp->clipcount;
+- compat_caddr_t p;
++ if (!kp->clipcount) {
++ kp->clips = NULL;
++ return 0;
++ }
+
+- if (get_user(p, &up->clips))
++ n = kp->clipcount;
++ if (get_user(p, &up->clips))
++ return -EFAULT;
++ uclips = compat_ptr(p);
++ kclips = compat_alloc_user_space(n * sizeof(*kclips));
++ kp->clips = kclips;
++ while (n--) {
++ if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+ return -EFAULT;
+- uclips = compat_ptr(p);
+- kclips = compat_alloc_user_space(n * sizeof(*kclips));
+- kp->clips = kclips;
+- while (--n >= 0) {
+- if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+- return -EFAULT;
+- if (put_user(n ? kclips + 1 : NULL, &kclips->next))
+- return -EFAULT;
+- uclips += 1;
+- kclips += 1;
+- }
+- } else
+- kp->clips = NULL;
++ if (put_user(n ? kclips + 1 : NULL, &kclips->next))
++ return -EFAULT;
++ uclips++;
++ kclips++;
++ }
+ return 0;
+ }
+
+ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+ {
++ struct v4l2_clip __user *kclips = kp->clips;
++ struct v4l2_clip32 __user *uclips;
++ u32 n = kp->clipcount;
++ compat_caddr_t p;
++
+ if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
+ put_user(kp->field, &up->field) ||
+ put_user(kp->chromakey, &up->chromakey) ||
+ put_user(kp->clipcount, &up->clipcount) ||
+ put_user(kp->global_alpha, &up->global_alpha))
+ return -EFAULT;
++
++ if (!kp->clipcount)
++ return 0;
++
++ if (get_user(p, &up->clips))
++ return -EFAULT;
++ uclips = compat_ptr(p);
++ while (n--) {
++ if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
++ return -EFAULT;
++ uclips++;
++ kclips++;
++ }
+ return 0;
+ }
+
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:26 -0300
+Subject: media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Mauro Carvalho Chehab <mchehab@s-opensource.com>, Sasha Levin <alexander.levin@microsoft.com>
+Message-ID: <6e6f38fc8542cf41fffcd3067026c4f015564544.1522260310.git.mchehab@s-opensource.com>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 8ed5a59dcb47a6f76034ee760b36e089f3e82529 upstream.
+
+The struct v4l2_plane32 should set m.userptr as well. The same
+happens in v4l2_buffer32 and v4l2-compliance tests for this.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 47 +++++++++++++++-----------
+ 1 file changed, 28 insertions(+), 19 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -287,19 +287,24 @@ static int get_v4l2_plane32(struct v4l2_
+ sizeof(up->data_offset)))
+ return -EFAULT;
+
+- if (memory == V4L2_MEMORY_USERPTR) {
++ switch (memory) {
++ case V4L2_MEMORY_MMAP:
++ case V4L2_MEMORY_OVERLAY:
++ if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
++ sizeof(up32->m.mem_offset)))
++ return -EFAULT;
++ break;
++ case V4L2_MEMORY_USERPTR:
+ if (get_user(p, &up32->m.userptr))
+ return -EFAULT;
+ up_pln = compat_ptr(p);
+ if (put_user((unsigned long)up_pln, &up->m.userptr))
+ return -EFAULT;
+- } else if (memory == V4L2_MEMORY_DMABUF) {
++ break;
++ case V4L2_MEMORY_DMABUF:
+ if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
+ return -EFAULT;
+- } else {
+- if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+- sizeof(up32->m.mem_offset)))
+- return -EFAULT;
++ break;
+ }
+
+ return 0;
+@@ -308,22 +313,32 @@ static int get_v4l2_plane32(struct v4l2_
+ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
+ enum v4l2_memory memory)
+ {
++ unsigned long p;
++
+ if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
+ copy_in_user(&up32->data_offset, &up->data_offset,
+ sizeof(up->data_offset)))
+ return -EFAULT;
+
+- /* For MMAP, driver might've set up the offset, so copy it back.
+- * USERPTR stays the same (was userspace-provided), so no copying. */
+- if (memory == V4L2_MEMORY_MMAP)
++ switch (memory) {
++ case V4L2_MEMORY_MMAP:
++ case V4L2_MEMORY_OVERLAY:
+ if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
+ sizeof(up->m.mem_offset)))
+ return -EFAULT;
+- /* For DMABUF, driver might've set up the fd, so copy it back. */
+- if (memory == V4L2_MEMORY_DMABUF)
++ break;
++ case V4L2_MEMORY_USERPTR:
++ if (get_user(p, &up->m.userptr) ||
++ put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
++ &up32->m.userptr))
++ return -EFAULT;
++ break;
++ case V4L2_MEMORY_DMABUF:
+ if (copy_in_user(&up32->m.fd, &up->m.fd,
+ sizeof(up->m.fd)))
+ return -EFAULT;
++ break;
++ }
+
+ return 0;
+ }
+@@ -383,6 +398,7 @@ static int get_v4l2_buffer32(struct v4l2
+ } else {
+ switch (kp->memory) {
+ case V4L2_MEMORY_MMAP:
++ case V4L2_MEMORY_OVERLAY:
+ if (get_user(kp->m.offset, &up->m.offset))
+ return -EFAULT;
+ break;
+@@ -396,10 +412,6 @@ static int get_v4l2_buffer32(struct v4l2
+ kp->m.userptr = (unsigned long)compat_ptr(tmp);
+ }
+ break;
+- case V4L2_MEMORY_OVERLAY:
+- if (get_user(kp->m.offset, &up->m.offset))
+- return -EFAULT;
+- break;
+ case V4L2_MEMORY_DMABUF:
+ if (get_user(kp->m.fd, &up->m.fd))
+ return -EFAULT;
+@@ -456,6 +468,7 @@ static int put_v4l2_buffer32(struct v4l2
+ } else {
+ switch (kp->memory) {
+ case V4L2_MEMORY_MMAP:
++ case V4L2_MEMORY_OVERLAY:
+ if (put_user(kp->m.offset, &up->m.offset))
+ return -EFAULT;
+ break;
+@@ -463,10 +476,6 @@ static int put_v4l2_buffer32(struct v4l2
+ if (put_user(kp->m.userptr, &up->m.userptr))
+ return -EFAULT;
+ break;
+- case V4L2_MEMORY_OVERLAY:
+- if (put_user(kp->m.offset, &up->m.offset))
+- return -EFAULT;
+- break;
+ case V4L2_MEMORY_DMABUF:
+ if (put_user(kp->m.fd, &up->m.fd))
+ return -EFAULT;
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:32 -0300
+Subject: media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Mauro Carvalho Chehab <mchehab@s-opensource.com>, Sasha Levin <alexander.levin@microsoft.com>
+Message-ID: <9d0bb62c2dc7caee1fd2b9199fc1a22ec8479395.1522260310.git.mchehab@s-opensource.com>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit d83a8243aaefe62ace433e4384a4f077bed86acb upstream.
+
+Some ioctls need to copy back the result even if the ioctl returned
+an error. However, don't do this for the error code -ENOTTY.
+It makes no sense in that cases.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -943,6 +943,9 @@ static long do_video_ioctl(struct file *
+ set_fs(old_fs);
+ }
+
++ if (err == -ENOTTY)
++ return err;
++
+ /* Special case: even after an error we need to put the
+ results back for these ioctls since the error_idx will
+ contain information on which control failed. */
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:31 -0300
+Subject: media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Mauro Carvalho Chehab <mchehab@s-opensource.com>, Sasha Levin <alexander.levin@microsoft.com>
+Message-ID: <8f000de7f9babd3f104eacbd7e79fbd72372c9d1.1522260310.git.mchehab@s-opensource.com>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 169f24ca68bf0f247d111aef07af00dd3a02ae88 upstream.
+
+There is nothing wrong with using an unknown buffer type. So
+stop spamming the kernel log whenever this happens. The kernel
+will just return -EINVAL to signal this.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -170,8 +170,6 @@ static int __get_v4l2_format32(struct v4
+ return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced,
+ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+ default:
+- printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+- kp->type);
+ return -EINVAL;
+ }
+ }
+@@ -214,8 +212,6 @@ static int __put_v4l2_format32(struct v4
+ return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced,
+ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+ default:
+- printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+- kp->type);
+ return -EINVAL;
+ }
+ }
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:27 -0300
+Subject: media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Mauro Carvalho Chehab <mchehab@s-opensource.com>, Sasha Levin <alexander.levin@microsoft.com>
+Message-ID: <63df92f6981785c5e31c1d8e796e827344cc75f3.1522260310.git.mchehab@s-opensource.com>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit b8c601e8af2d08f733d74defa8465303391bb930 upstream.
+
+ctrl_is_pointer just hardcoded two known string controls, but that
+caused problems when using e.g. custom controls that use a pointer
+for the payload.
+
+Reimplement this function: it now finds the v4l2_ctrl (if the driver
+uses the control framework) or it calls vidioc_query_ext_ctrl (if the
+driver implements that directly).
+
+In both cases it can now check if the control is a pointer control
+or not.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 +++++++++++++++++---------
+ 1 file changed, 39 insertions(+), 20 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -18,6 +18,8 @@
+ #include <linux/videodev2.h>
+ #include <linux/v4l2-subdev.h>
+ #include <media/v4l2-dev.h>
++#include <media/v4l2-fh.h>
++#include <media/v4l2-ctrls.h>
+ #include <media/v4l2-ioctl.h>
+
+ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+@@ -575,24 +577,39 @@ struct v4l2_ext_control32 {
+ };
+ } __attribute__ ((packed));
+
+-/* The following function really belong in v4l2-common, but that causes
+- a circular dependency between modules. We need to think about this, but
+- for now this will do. */
+-
+-/* Return non-zero if this control is a pointer type. Currently only
+- type STRING is a pointer type. */
+-static inline int ctrl_is_pointer(u32 id)
+-{
+- switch (id) {
+- case V4L2_CID_RDS_TX_PS_NAME:
+- case V4L2_CID_RDS_TX_RADIO_TEXT:
+- return 1;
+- default:
+- return 0;
++/* Return true if this control is a pointer type. */
++static inline bool ctrl_is_pointer(struct file *file, u32 id)
++{
++ struct video_device *vdev = video_devdata(file);
++ struct v4l2_fh *fh = NULL;
++ struct v4l2_ctrl_handler *hdl = NULL;
++ struct v4l2_query_ext_ctrl qec = { id };
++ const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
++
++ if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
++ fh = file->private_data;
++
++ if (fh && fh->ctrl_handler)
++ hdl = fh->ctrl_handler;
++ else if (vdev->ctrl_handler)
++ hdl = vdev->ctrl_handler;
++
++ if (hdl) {
++ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
++
++ return ctrl && ctrl->is_ptr;
+ }
++
++ if (!ops->vidioc_query_ext_ctrl)
++ return false;
++
++ return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
++ (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
+ }
+
+-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
++static int get_v4l2_ext_controls32(struct file *file,
++ struct v4l2_ext_controls *kp,
++ struct v4l2_ext_controls32 __user *up)
+ {
+ struct v4l2_ext_control32 __user *ucontrols;
+ struct v4l2_ext_control __user *kcontrols;
+@@ -624,7 +641,7 @@ static int get_v4l2_ext_controls32(struc
+ return -EFAULT;
+ if (get_user(id, &kcontrols->id))
+ return -EFAULT;
+- if (ctrl_is_pointer(id)) {
++ if (ctrl_is_pointer(file, id)) {
+ void __user *s;
+
+ if (get_user(p, &ucontrols->string))
+@@ -639,7 +656,9 @@ static int get_v4l2_ext_controls32(struc
+ return 0;
+ }
+
+-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
++static int put_v4l2_ext_controls32(struct file *file,
++ struct v4l2_ext_controls *kp,
++ struct v4l2_ext_controls32 __user *up)
+ {
+ struct v4l2_ext_control32 __user *ucontrols;
+ struct v4l2_ext_control __user *kcontrols =
+@@ -671,7 +690,7 @@ static int put_v4l2_ext_controls32(struc
+ /* Do not modify the pointer when copying a pointer control.
+ The contents of the pointer was changed, not the pointer
+ itself. */
+- if (ctrl_is_pointer(id))
++ if (ctrl_is_pointer(file, id))
+ size -= sizeof(ucontrols->value64);
+ if (copy_in_user(ucontrols, kcontrols, size))
+ return -EFAULT;
+@@ -884,7 +903,7 @@ static long do_video_ioctl(struct file *
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+- err = get_v4l2_ext_controls32(&karg.v2ecs, up);
++ err = get_v4l2_ext_controls32(file, &karg.v2ecs, up);
+ compatible_arg = 0;
+ break;
+ case VIDIOC_DQEVENT:
+@@ -911,7 +930,7 @@ static long do_video_ioctl(struct file *
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+- if (put_v4l2_ext_controls32(&karg.v2ecs, up))
++ if (put_v4l2_ext_controls32(file, &karg.v2ecs, up))
+ err = -EFAULT;
+ break;
+ }
--- /dev/null
+From b7b957d429f601d6d1942122b339474f31191d75 Mon Sep 17 00:00:00 2001
+From: Hans Verkuil <hans.verkuil@cisco.com>
+Date: Wed, 24 Jan 2018 04:35:48 -0500
+Subject: media: v4l2-compat-ioctl32.c: fix the indentation
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit b7b957d429f601d6d1942122b339474f31191d75 upstream.
+
+The indentation of this source is all over the place. Fix this.
+This patch only changes whitespace.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Cc: <stable@vger.kernel.org> # for v4.15 and up
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 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;
+ }
+
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:28 -0300
+Subject: media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Hans Verkuil <hansverk@cisco.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>, Sasha Levin <alexander.levin@microsoft.com>
+Message-ID: <39d6997be9988f81bce42a00115b062aac7b0a51.1522260310.git.mchehab@s-opensource.com>
+
+From: Hans Verkuil <hansverk@cisco.com>
+
+commit 273caa260035c03d89ad63d72d8cd3d9e5c5e3f1 upstream.
+
+If the device is of type VFL_TYPE_SUBDEV then vdev->ioctl_ops
+is NULL so the 'if (!ops->vidioc_query_ext_ctrl)' check would crash.
+Add a test for !ops to the condition.
+
+All sub-devices that have controls will use the control framework,
+so they do not have an equivalent to ops->vidioc_query_ext_ctrl.
+Returning false if ops is NULL is the correct thing to do here.
+
+Fixes: b8c601e8af ("v4l2-compat-ioctl32.c: fix ctrl_is_pointer")
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Reported-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -600,7 +600,7 @@ static inline bool ctrl_is_pointer(struc
+ return ctrl && ctrl->is_ptr;
+ }
+
+- if (!ops->vidioc_query_ext_ctrl)
++ if (!ops || !ops->vidioc_query_ext_ctrl)
+ return false;
+
+ return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:24 -0300
+Subject: media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Mauro Carvalho Chehab <mchehab@s-opensource.com>, Sasha Levin <alexander.levin@microsoft.com>
+Message-ID: <eba66edbe4ca94e61e342683ee5e225f376d754c.1522260310.git.mchehab@s-opensource.com>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 486c521510c44a04cd756a9267e7d1e271c8a4ba upstream.
+
+These helper functions do not really help. Move the code to the
+__get/put_v4l2_format32 functions.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 84 ++++----------------------
+ 1 file changed, 16 insertions(+), 68 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -89,64 +89,6 @@ static int put_v4l2_window32(struct v4l2
+ return 0;
+ }
+
+-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+-{
+- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+- struct v4l2_pix_format_mplane __user *up)
+-{
+- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+-{
+- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+- struct v4l2_pix_format_mplane __user *up)
+-{
+- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+-{
+- if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+-{
+- if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+-{
+- if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+-{
+- if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
+- return -EFAULT;
+- return 0;
+-}
+-
+ struct v4l2_format32 {
+ __u32 type; /* enum v4l2_buf_type */
+ union {
+@@ -184,20 +126,23 @@ static int __get_v4l2_format32(struct v4
+ switch (kp->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
++ return copy_from_user(&kp->fmt.pix, &up->fmt.pix,
++ sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+- return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+- &up->fmt.pix_mp);
++ return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
++ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+ return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+- return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
++ return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi,
++ sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+- return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
++ return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced,
++ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+ default:
+ printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+ kp->type);
+@@ -225,20 +170,23 @@ static int __put_v4l2_format32(struct v4
+ switch (kp->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
++ return copy_to_user(&up->fmt.pix, &kp->fmt.pix,
++ sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+- return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+- &up->fmt.pix_mp);
++ return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
++ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+ return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+- return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
++ return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi,
++ sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+- return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
++ return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced,
++ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+ default:
+ printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+ kp->type);
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:33 -0300
+Subject: media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Daniel Mentz <danielmentz@google.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>, Sasha Levin <alexander.levin@microsoft.com>
+Message-ID: <10af8cdf1226db8dfc7e85673ee3a7a17ba969f2.1522260310.git.mchehab@s-opensource.com>
+
+From: Daniel Mentz <danielmentz@google.com>
+
+commit a1dfb4c48cc1e64eeb7800a27c66a6f7e88d075a upstream.
+
+The 32-bit compat v4l2 ioctl handling is implemented based on its 64-bit
+equivalent. It converts 32-bit data structures into its 64-bit
+equivalents and needs to provide the data to the 64-bit ioctl in user
+space memory which is commonly allocated using
+compat_alloc_user_space().
+
+However, due to how that function is implemented, it can only be called
+a single time for every syscall invocation.
+
+Supposedly to avoid this limitation, the existing code uses a mix of
+memory from the kernel stack and memory allocated through
+compat_alloc_user_space().
+
+Under normal circumstances, this would not work, because the 64-bit
+ioctl expects all pointers to point to user space memory. As a
+workaround, set_fs(KERNEL_DS) is called to temporarily disable this
+extra safety check and allow kernel pointers. However, this might
+introduce a security vulnerability: The result of the 32-bit to 64-bit
+conversion is writeable by user space because the output buffer has been
+allocated via compat_alloc_user_space(). A malicious user space process
+could then manipulate pointers inside this output buffer, and due to the
+previous set_fs(KERNEL_DS) call, functions like get_user() or put_user()
+no longer prevent kernel memory access.
+
+The new approach is to pre-calculate the total amount of user space
+memory that is needed, allocate it using compat_alloc_user_space() and
+then divide up the allocated memory to accommodate all data structures
+that need to be converted.
+
+An alternative approach would have been to retain the union type karg
+that they allocated on the kernel stack in do_video_ioctl(), copy all
+data from user space into karg and then back to user space. However, we
+decided against this approach because it does not align with other
+compat syscall implementations. Instead, we tried to replicate the
+get_user/put_user pairs as found in other places in the kernel:
+
+ if (get_user(clipcount, &up->clipcount) ||
+ put_user(clipcount, &kp->clipcount)) return -EFAULT;
+
+Notes from hans.verkuil@cisco.com:
+
+This patch was taken from:
+ https://github.com/LineageOS/android_kernel_samsung_apq8084/commit/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 <danielmentz@google.com>
+Co-developed-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 757 ++++++++++++++++----------
+ 1 file changed, 491 insertions(+), 266 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -22,6 +22,14 @@
+ #include <media/v4l2-ctrls.h>
+ #include <media/v4l2-ioctl.h>
+
++/* Use the same argument order as copy_in_user */
++#define assign_in_user(to, from) \
++({ \
++ typeof(*from) __assign_tmp; \
++ \
++ get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \
++})
++
+ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+ long ret = -ENOIOCTLCMD;
+@@ -35,12 +43,12 @@ static long native_ioctl(struct file *fi
+
+ struct v4l2_clip32 {
+ struct v4l2_rect c;
+- compat_caddr_t next;
++ compat_caddr_t next;
+ };
+
+ struct v4l2_window32 {
+ struct v4l2_rect w;
+- __u32 field; /* enum v4l2_field */
++ __u32 field; /* enum v4l2_field */
+ __u32 chromakey;
+ compat_caddr_t clips; /* actually struct v4l2_clip32 * */
+ __u32 clipcount;
+@@ -48,37 +56,41 @@ struct v4l2_window32 {
+ __u8 global_alpha;
+ };
+
+-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
++static int get_v4l2_window32(struct v4l2_window __user *kp,
++ struct v4l2_window32 __user *up,
++ void __user *aux_buf, u32 aux_space)
+ {
+ struct v4l2_clip32 __user *uclips;
+ struct v4l2_clip __user *kclips;
+ compat_caddr_t p;
+- u32 n;
++ u32 clipcount;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+- copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
+- get_user(kp->field, &up->field) ||
+- get_user(kp->chromakey, &up->chromakey) ||
+- get_user(kp->clipcount, &up->clipcount) ||
+- get_user(kp->global_alpha, &up->global_alpha))
++ copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
++ assign_in_user(&kp->field, &up->field) ||
++ assign_in_user(&kp->chromakey, &up->chromakey) ||
++ assign_in_user(&kp->global_alpha, &up->global_alpha) ||
++ get_user(clipcount, &up->clipcount) ||
++ put_user(clipcount, &kp->clipcount))
+ return -EFAULT;
+- if (kp->clipcount > 2048)
++ if (clipcount > 2048)
+ return -EINVAL;
+- if (!kp->clipcount) {
+- kp->clips = NULL;
+- return 0;
+- }
++ if (!clipcount)
++ return put_user(NULL, &kp->clips);
+
+- n = kp->clipcount;
+ if (get_user(p, &up->clips))
+ return -EFAULT;
+ uclips = compat_ptr(p);
+- kclips = compat_alloc_user_space(n * sizeof(*kclips));
+- kp->clips = kclips;
+- while (n--) {
++ if (aux_space < clipcount * sizeof(*kclips))
++ return -EFAULT;
++ kclips = aux_buf;
++ if (put_user(kclips, &kp->clips))
++ return -EFAULT;
++
++ while (clipcount--) {
+ if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+ return -EFAULT;
+- if (put_user(n ? kclips + 1 : NULL, &kclips->next))
++ if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
+ return -EFAULT;
+ uclips++;
+ kclips++;
+@@ -86,27 +98,28 @@ static int get_v4l2_window32(struct v4l2
+ return 0;
+ }
+
+-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
++static int put_v4l2_window32(struct v4l2_window __user *kp,
++ struct v4l2_window32 __user *up)
+ {
+ struct v4l2_clip __user *kclips = kp->clips;
+ struct v4l2_clip32 __user *uclips;
+- u32 n = kp->clipcount;
+ compat_caddr_t p;
++ u32 clipcount;
+
+- if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
+- put_user(kp->field, &up->field) ||
+- put_user(kp->chromakey, &up->chromakey) ||
+- put_user(kp->clipcount, &up->clipcount) ||
+- put_user(kp->global_alpha, &up->global_alpha))
++ if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
++ assign_in_user(&up->field, &kp->field) ||
++ assign_in_user(&up->chromakey, &kp->chromakey) ||
++ assign_in_user(&up->global_alpha, &kp->global_alpha) ||
++ get_user(clipcount, &kp->clipcount) ||
++ put_user(clipcount, &up->clipcount))
+ return -EFAULT;
+-
+- if (!kp->clipcount)
++ if (!clipcount)
+ return 0;
+
+ if (get_user(p, &up->clips))
+ return -EFAULT;
+ uclips = compat_ptr(p);
+- while (n--) {
++ while (clipcount--) {
+ if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
+ return -EFAULT;
+ uclips++;
+@@ -144,90 +157,150 @@ struct v4l2_create_buffers32 {
+ __u32 reserved[8];
+ };
+
+-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
++{
++ u32 type;
++
++ if (get_user(type, &up->type))
++ return -EFAULT;
++
++ switch (type) {
++ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
++ u32 clipcount;
++
++ if (get_user(clipcount, &up->fmt.win.clipcount))
++ return -EFAULT;
++ if (clipcount > 2048)
++ return -EINVAL;
++ *size = clipcount * sizeof(struct v4l2_clip);
++ return 0;
++ }
++ default:
++ *size = 0;
++ return 0;
++ }
++}
++
++static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
+ {
+- if (get_user(kp->type, &up->type))
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+ return -EFAULT;
++ return __bufsize_v4l2_format(up, size);
++}
+
+- switch (kp->type) {
++static int __get_v4l2_format32(struct v4l2_format __user *kp,
++ struct v4l2_format32 __user *up,
++ void __user *aux_buf, u32 aux_space)
++{
++ u32 type;
++
++ if (get_user(type, &up->type) || put_user(type, &kp->type))
++ return -EFAULT;
++
++ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- return copy_from_user(&kp->fmt.pix, &up->fmt.pix,
+- sizeof(kp->fmt.pix)) ? -EFAULT : 0;
++ return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
++ sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+- return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
+- sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
++ return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
++ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+- return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
++ return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
++ aux_buf, aux_space);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+- return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi,
+- sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
++ return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
++ sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+- return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced,
+- sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
++ return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
++ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+ default:
+ return -EINVAL;
+ }
+ }
+
+-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int get_v4l2_format32(struct v4l2_format __user *kp,
++ struct v4l2_format32 __user *up,
++ void __user *aux_buf, u32 aux_space)
+ {
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+ return -EFAULT;
+- return __get_v4l2_format32(kp, up);
++ return __get_v4l2_format32(kp, up, aux_buf, aux_space);
+ }
+
+-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
++static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
++ u32 *size)
++{
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
++ return -EFAULT;
++ return __bufsize_v4l2_format(&up->format, size);
++}
++
++static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
++ struct v4l2_create_buffers32 __user *up,
++ void __user *aux_buf, u32 aux_space)
+ {
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+- copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
++ copy_in_user(kp, up,
++ offsetof(struct v4l2_create_buffers32, format)))
+ return -EFAULT;
+- return __get_v4l2_format32(&kp->format, &up->format);
++ return __get_v4l2_format32(&kp->format, &up->format,
++ aux_buf, aux_space);
+ }
+
+-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int __put_v4l2_format32(struct v4l2_format __user *kp,
++ struct v4l2_format32 __user *up)
+ {
+- switch (kp->type) {
++ u32 type;
++
++ if (get_user(type, &kp->type))
++ return -EFAULT;
++
++ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- return copy_to_user(&up->fmt.pix, &kp->fmt.pix,
+- sizeof(kp->fmt.pix)) ? -EFAULT : 0;
++ return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
++ sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+- return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
+- sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
++ return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
++ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+ return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+- return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi,
+- sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
++ return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
++ sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+- return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced,
+- sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
++ return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
++ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+ default:
+ return -EINVAL;
+ }
+ }
+
+-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int put_v4l2_format32(struct v4l2_format __user *kp,
++ struct v4l2_format32 __user *up)
+ {
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
+ return -EFAULT;
+ return __put_v4l2_format32(kp, up);
+ }
+
+-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
++static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
++ struct v4l2_create_buffers32 __user *up)
+ {
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+- copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) ||
+- copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
++ copy_in_user(up, kp,
++ offsetof(struct v4l2_create_buffers32, format)) ||
++ copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+ return -EFAULT;
+ return __put_v4l2_format32(&kp->format, &up->format);
+ }
+@@ -241,24 +314,27 @@ struct v4l2_standard32 {
+ __u32 reserved[4];
+ };
+
+-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
++static int get_v4l2_standard32(struct v4l2_standard __user *kp,
++ struct v4l2_standard32 __user *up)
+ {
+ /* other fields are not set by the user, nor used by the driver */
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+- get_user(kp->index, &up->index))
++ assign_in_user(&kp->index, &up->index))
+ return -EFAULT;
+ return 0;
+ }
+
+-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
++static int put_v4l2_standard32(struct v4l2_standard __user *kp,
++ struct v4l2_standard32 __user *up)
+ {
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+- put_user(kp->index, &up->index) ||
+- copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
+- copy_to_user(up->name, kp->name, sizeof(up->name)) ||
+- copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
+- put_user(kp->framelines, &up->framelines) ||
+- copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
++ assign_in_user(&up->index, &kp->index) ||
++ copy_in_user(&up->id, &kp->id, sizeof(up->id)) ||
++ copy_in_user(up->name, kp->name, sizeof(up->name)) ||
++ copy_in_user(&up->frameperiod, &kp->frameperiod,
++ sizeof(up->frameperiod)) ||
++ assign_in_user(&up->framelines, &kp->framelines) ||
++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ return -EFAULT;
+ return 0;
+ }
+@@ -298,11 +374,11 @@ struct v4l2_buffer32 {
+ __u32 reserved;
+ };
+
+-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
++static int get_v4l2_plane32(struct v4l2_plane __user *up,
++ struct v4l2_plane32 __user *up32,
+ enum v4l2_memory memory)
+ {
+- void __user *up_pln;
+- compat_long_t p;
++ compat_ulong_t p;
+
+ if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
+ copy_in_user(&up->data_offset, &up32->data_offset,
+@@ -317,10 +393,8 @@ static int get_v4l2_plane32(struct v4l2_
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_USERPTR:
+- if (get_user(p, &up32->m.userptr))
+- return -EFAULT;
+- up_pln = compat_ptr(p);
+- if (put_user((unsigned long)up_pln, &up->m.userptr))
++ if (get_user(p, &up32->m.userptr) ||
++ put_user((unsigned long)compat_ptr(p), &up->m.userptr))
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_DMABUF:
+@@ -332,7 +406,8 @@ static int get_v4l2_plane32(struct v4l2_
+ return 0;
+ }
+
+-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
++static int put_v4l2_plane32(struct v4l2_plane __user *up,
++ struct v4l2_plane32 __user *up32,
+ enum v4l2_memory memory)
+ {
+ unsigned long p;
+@@ -356,8 +431,7 @@ static int put_v4l2_plane32(struct v4l2_
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_DMABUF:
+- if (copy_in_user(&up32->m.fd, &up->m.fd,
+- sizeof(up->m.fd)))
++ if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd)))
+ return -EFAULT;
+ break;
+ }
+@@ -365,37 +439,75 @@ static int put_v4l2_plane32(struct v4l2_
+ return 0;
+ }
+
+-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
++static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
+ {
++ u32 type;
++ u32 length;
++
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ get_user(type, &up->type) ||
++ get_user(length, &up->length))
++ return -EFAULT;
++
++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
++ if (length > VIDEO_MAX_PLANES)
++ return -EINVAL;
++
++ /*
++ * We don't really care if userspace decides to kill itself
++ * by passing a very big length value
++ */
++ *size = length * sizeof(struct v4l2_plane);
++ } else {
++ *size = 0;
++ }
++ return 0;
++}
++
++static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
++ struct v4l2_buffer32 __user *up,
++ void __user *aux_buf, u32 aux_space)
++{
++ u32 type;
++ u32 length;
++ enum v4l2_memory memory;
+ struct v4l2_plane32 __user *uplane32;
+ struct v4l2_plane __user *uplane;
+ compat_caddr_t p;
+- int num_planes;
+ int ret;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+- get_user(kp->index, &up->index) ||
+- get_user(kp->type, &up->type) ||
+- get_user(kp->flags, &up->flags) ||
+- get_user(kp->memory, &up->memory) ||
+- get_user(kp->length, &up->length))
+- return -EFAULT;
+-
+- if (V4L2_TYPE_IS_OUTPUT(kp->type))
+- if (get_user(kp->bytesused, &up->bytesused) ||
+- get_user(kp->field, &up->field) ||
+- get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+- get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec))
++ assign_in_user(&kp->index, &up->index) ||
++ get_user(type, &up->type) ||
++ put_user(type, &kp->type) ||
++ assign_in_user(&kp->flags, &up->flags) ||
++ get_user(memory, &up->memory) ||
++ put_user(memory, &kp->memory) ||
++ get_user(length, &up->length) ||
++ put_user(length, &kp->length))
++ return -EFAULT;
++
++ if (V4L2_TYPE_IS_OUTPUT(type))
++ if (assign_in_user(&kp->bytesused, &up->bytesused) ||
++ assign_in_user(&kp->field, &up->field) ||
++ assign_in_user(&kp->timestamp.tv_sec,
++ &up->timestamp.tv_sec) ||
++ assign_in_user(&kp->timestamp.tv_usec,
++ &up->timestamp.tv_usec))
+ return -EFAULT;
+
+- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+- num_planes = kp->length;
++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
++ u32 num_planes = length;
++
+ if (num_planes == 0) {
+- kp->m.planes = NULL;
+- /* num_planes == 0 is legal, e.g. when userspace doesn't
+- * need planes array on DQBUF*/
+- return 0;
++ /*
++ * num_planes == 0 is legal, e.g. when userspace doesn't
++ * need planes array on DQBUF
++ */
++ return put_user(NULL, &kp->m.planes);
+ }
++ if (num_planes > VIDEO_MAX_PLANES)
++ return -EINVAL;
+
+ if (get_user(p, &up->m.planes))
+ return -EFAULT;
+@@ -405,37 +517,43 @@ static int get_v4l2_buffer32(struct v4l2
+ num_planes * sizeof(*uplane32)))
+ return -EFAULT;
+
+- /* We don't really care if userspace decides to kill itself
+- * by passing a very big num_planes value */
+- uplane = compat_alloc_user_space(num_planes * sizeof(*uplane));
+- kp->m.planes = (__force struct v4l2_plane *)uplane;
++ /*
++ * We don't really care if userspace decides to kill itself
++ * by passing a very big num_planes value
++ */
++ if (aux_space < num_planes * sizeof(*uplane))
++ return -EFAULT;
++
++ uplane = aux_buf;
++ if (put_user((__force struct v4l2_plane *)uplane,
++ &kp->m.planes))
++ return -EFAULT;
+
+- while (--num_planes >= 0) {
+- ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
++ while (num_planes--) {
++ ret = get_v4l2_plane32(uplane, uplane32, memory);
+ if (ret)
+ return ret;
+- ++uplane;
+- ++uplane32;
++ uplane++;
++ uplane32++;
+ }
+ } else {
+- switch (kp->memory) {
++ switch (memory) {
+ case V4L2_MEMORY_MMAP:
+ case V4L2_MEMORY_OVERLAY:
+- if (get_user(kp->m.offset, &up->m.offset))
++ if (assign_in_user(&kp->m.offset, &up->m.offset))
+ return -EFAULT;
+ break;
+- case V4L2_MEMORY_USERPTR:
+- {
+- compat_long_t tmp;
++ case V4L2_MEMORY_USERPTR: {
++ compat_ulong_t userptr;
+
+- if (get_user(tmp, &up->m.userptr))
+- return -EFAULT;
+-
+- kp->m.userptr = (unsigned long)compat_ptr(tmp);
+- }
++ if (get_user(userptr, &up->m.userptr) ||
++ put_user((unsigned long)compat_ptr(userptr),
++ &kp->m.userptr))
++ return -EFAULT;
+ break;
++ }
+ case V4L2_MEMORY_DMABUF:
+- if (get_user(kp->m.fd, &up->m.fd))
++ if (assign_in_user(&kp->m.fd, &up->m.fd))
+ return -EFAULT;
+ break;
+ }
+@@ -444,62 +562,70 @@ static int get_v4l2_buffer32(struct v4l2
+ return 0;
+ }
+
+-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
++static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
++ struct v4l2_buffer32 __user *up)
+ {
++ u32 type;
++ u32 length;
++ enum v4l2_memory memory;
+ struct v4l2_plane32 __user *uplane32;
+ struct v4l2_plane __user *uplane;
+ compat_caddr_t p;
+- int num_planes;
+ int ret;
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+- put_user(kp->index, &up->index) ||
+- put_user(kp->type, &up->type) ||
+- put_user(kp->flags, &up->flags) ||
+- put_user(kp->memory, &up->memory))
+- return -EFAULT;
+-
+- if (put_user(kp->bytesused, &up->bytesused) ||
+- put_user(kp->field, &up->field) ||
+- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+- put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
+- copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
+- put_user(kp->sequence, &up->sequence) ||
+- put_user(kp->reserved2, &up->reserved2) ||
+- put_user(kp->reserved, &up->reserved) ||
+- put_user(kp->length, &up->length))
++ assign_in_user(&up->index, &kp->index) ||
++ get_user(type, &kp->type) ||
++ put_user(type, &up->type) ||
++ assign_in_user(&up->flags, &kp->flags) ||
++ get_user(memory, &kp->memory) ||
++ put_user(memory, &up->memory))
++ return -EFAULT;
++
++ if (assign_in_user(&up->bytesused, &kp->bytesused) ||
++ assign_in_user(&up->field, &kp->field) ||
++ assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
++ assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
++ copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
++ assign_in_user(&up->sequence, &kp->sequence) ||
++ assign_in_user(&up->reserved2, &kp->reserved2) ||
++ assign_in_user(&up->reserved, &kp->reserved) ||
++ get_user(length, &kp->length) ||
++ put_user(length, &up->length))
+ return -EFAULT;
+
+- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+- num_planes = kp->length;
++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
++ u32 num_planes = length;
++
+ if (num_planes == 0)
+ return 0;
+
+- uplane = (__force struct v4l2_plane __user *)kp->m.planes;
++ if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
++ return -EFAULT;
+ if (get_user(p, &up->m.planes))
+ return -EFAULT;
+ uplane32 = compat_ptr(p);
+
+- while (--num_planes >= 0) {
+- ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
++ while (num_planes--) {
++ ret = put_v4l2_plane32(uplane, uplane32, memory);
+ if (ret)
+ return ret;
+ ++uplane;
+ ++uplane32;
+ }
+ } else {
+- switch (kp->memory) {
++ switch (memory) {
+ case V4L2_MEMORY_MMAP:
+ case V4L2_MEMORY_OVERLAY:
+- if (put_user(kp->m.offset, &up->m.offset))
++ if (assign_in_user(&up->m.offset, &kp->m.offset))
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_USERPTR:
+- if (put_user(kp->m.userptr, &up->m.userptr))
++ if (assign_in_user(&up->m.userptr, &kp->m.userptr))
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_DMABUF:
+- if (put_user(kp->m.fd, &up->m.fd))
++ if (assign_in_user(&up->m.fd, &kp->m.fd))
+ return -EFAULT;
+ break;
+ }
+@@ -511,7 +637,7 @@ static int put_v4l2_buffer32(struct v4l2
+ struct v4l2_framebuffer32 {
+ __u32 capability;
+ __u32 flags;
+- compat_caddr_t base;
++ compat_caddr_t base;
+ struct {
+ __u32 width;
+ __u32 height;
+@@ -524,29 +650,32 @@ struct v4l2_framebuffer32 {
+ } fmt;
+ };
+
+-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
++static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
++ struct v4l2_framebuffer32 __user *up)
+ {
+- u32 tmp;
++ compat_caddr_t tmp;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ get_user(tmp, &up->base) ||
+- get_user(kp->capability, &up->capability) ||
+- get_user(kp->flags, &up->flags) ||
+- copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
++ put_user((__force void *)compat_ptr(tmp), &kp->base) ||
++ assign_in_user(&kp->capability, &up->capability) ||
++ assign_in_user(&kp->flags, &up->flags) ||
++ copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
+ return -EFAULT;
+- kp->base = (__force void *)compat_ptr(tmp);
+ return 0;
+ }
+
+-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
++static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
++ struct v4l2_framebuffer32 __user *up)
+ {
+- u32 tmp = (u32)((unsigned long)kp->base);
++ void *base;
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+- put_user(tmp, &up->base) ||
+- put_user(kp->capability, &up->capability) ||
+- put_user(kp->flags, &up->flags) ||
+- copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
++ get_user(base, &kp->base) ||
++ put_user(ptr_to_compat(base), &up->base) ||
++ assign_in_user(&up->capability, &kp->capability) ||
++ assign_in_user(&up->flags, &kp->flags) ||
++ copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
+ return -EFAULT;
+ return 0;
+ }
+@@ -559,21 +688,26 @@ struct v4l2_input32 {
+ __u32 tuner; /* Associated tuner */
+ v4l2_std_id std;
+ __u32 status;
+- __u32 reserved[4];
+-} __attribute__ ((packed));
++ __u32 capabilities;
++ __u32 reserved[3];
++};
+
+-/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
+- Otherwise it is identical to the 32-bit version. */
+-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
++/*
++ * The 64-bit v4l2_input struct has extra padding at the end of the struct.
++ * Otherwise it is identical to the 32-bit version.
++ */
++static inline int get_v4l2_input32(struct v4l2_input __user *kp,
++ struct v4l2_input32 __user *up)
+ {
+- if (copy_from_user(kp, up, sizeof(*up)))
++ if (copy_in_user(kp, up, sizeof(*up)))
+ return -EFAULT;
+ return 0;
+ }
+
+-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
++static inline int put_v4l2_input32(struct v4l2_input __user *kp,
++ struct v4l2_input32 __user *up)
+ {
+- if (copy_to_user(up, kp, sizeof(*up)))
++ if (copy_in_user(up, kp, sizeof(*up)))
+ return -EFAULT;
+ return 0;
+ }
+@@ -627,40 +761,64 @@ static inline bool ctrl_is_pointer(struc
+ (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
+ }
+
++static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
++ u32 *size)
++{
++ u32 count;
++
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ get_user(count, &up->count))
++ return -EFAULT;
++ if (count > V4L2_CID_MAX_CTRLS)
++ return -EINVAL;
++ *size = count * sizeof(struct v4l2_ext_control);
++ return 0;
++}
++
+ static int get_v4l2_ext_controls32(struct file *file,
+- struct v4l2_ext_controls *kp,
+- struct v4l2_ext_controls32 __user *up)
++ struct v4l2_ext_controls __user *kp,
++ struct v4l2_ext_controls32 __user *up,
++ void __user *aux_buf, u32 aux_space)
+ {
+ struct v4l2_ext_control32 __user *ucontrols;
+ struct v4l2_ext_control __user *kcontrols;
+- int n;
++ u32 count;
++ u32 n;
+ compat_caddr_t p;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+- get_user(kp->ctrl_class, &up->ctrl_class) ||
+- get_user(kp->count, &up->count) ||
+- get_user(kp->error_idx, &up->error_idx) ||
+- copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+- return -EFAULT;
+- n = kp->count;
+- if (n == 0) {
+- kp->controls = NULL;
+- return 0;
+- }
++ assign_in_user(&kp->ctrl_class, &up->ctrl_class) ||
++ get_user(count, &up->count) ||
++ put_user(count, &kp->count) ||
++ assign_in_user(&kp->error_idx, &up->error_idx) ||
++ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
++ return -EFAULT;
++
++ if (count == 0)
++ return put_user(NULL, &kp->controls);
++ if (count > V4L2_CID_MAX_CTRLS)
++ return -EINVAL;
+ if (get_user(p, &up->controls))
+ return -EFAULT;
+ ucontrols = compat_ptr(p);
+- if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols)))
++ if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
++ return -EFAULT;
++ if (aux_space < count * sizeof(*kcontrols))
+ return -EFAULT;
+- kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols));
+- kp->controls = (__force struct v4l2_ext_control *)kcontrols;
+- while (--n >= 0) {
++ kcontrols = aux_buf;
++ if (put_user((__force struct v4l2_ext_control *)kcontrols,
++ &kp->controls))
++ return -EFAULT;
++
++ for (n = 0; n < count; n++) {
+ u32 id;
+
+ if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
+ return -EFAULT;
++
+ if (get_user(id, &kcontrols->id))
+ return -EFAULT;
++
+ if (ctrl_is_pointer(file, id)) {
+ void __user *s;
+
+@@ -677,43 +835,54 @@ static int get_v4l2_ext_controls32(struc
+ }
+
+ static int put_v4l2_ext_controls32(struct file *file,
+- struct v4l2_ext_controls *kp,
++ struct v4l2_ext_controls __user *kp,
+ struct v4l2_ext_controls32 __user *up)
+ {
+ struct v4l2_ext_control32 __user *ucontrols;
+- struct v4l2_ext_control __user *kcontrols =
+- (__force struct v4l2_ext_control __user *)kp->controls;
+- int n = kp->count;
++ struct v4l2_ext_control __user *kcontrols;
++ u32 count;
++ u32 n;
+ compat_caddr_t p;
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+- put_user(kp->ctrl_class, &up->ctrl_class) ||
+- put_user(kp->count, &up->count) ||
+- put_user(kp->error_idx, &up->error_idx) ||
+- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
++ assign_in_user(&up->ctrl_class, &kp->ctrl_class) ||
++ get_user(count, &kp->count) ||
++ put_user(count, &up->count) ||
++ assign_in_user(&up->error_idx, &kp->error_idx) ||
++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
++ get_user(kcontrols, &kp->controls))
+ return -EFAULT;
+- if (!kp->count)
+- return 0;
+
++ if (!count)
++ return 0;
+ if (get_user(p, &up->controls))
+ return -EFAULT;
+ ucontrols = compat_ptr(p);
+- if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols)))
++ if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
+ return -EFAULT;
+
+- while (--n >= 0) {
+- unsigned size = sizeof(*ucontrols);
++ for (n = 0; n < count; n++) {
++ unsigned int size = sizeof(*ucontrols);
+ u32 id;
+
+- if (get_user(id, &kcontrols->id))
++ if (get_user(id, &kcontrols->id) ||
++ put_user(id, &ucontrols->id) ||
++ assign_in_user(&ucontrols->size, &kcontrols->size) ||
++ copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
++ sizeof(ucontrols->reserved2)))
+ return -EFAULT;
+- /* Do not modify the pointer when copying a pointer control.
+- The contents of the pointer was changed, not the pointer
+- itself. */
++
++ /*
++ * Do not modify the pointer when copying a pointer control.
++ * The contents of the pointer was changed, not the pointer
++ * itself.
++ */
+ if (ctrl_is_pointer(file, id))
+ size -= sizeof(ucontrols->value64);
++
+ if (copy_in_user(ucontrols, kcontrols, size))
+ return -EFAULT;
++
+ ucontrols++;
+ kcontrols++;
+ }
+@@ -732,17 +901,18 @@ struct v4l2_event32 {
+ __u32 reserved[8];
+ };
+
+-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
++static int put_v4l2_event32(struct v4l2_event __user *kp,
++ struct v4l2_event32 __user *up)
+ {
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+- put_user(kp->type, &up->type) ||
+- copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
+- put_user(kp->pending, &up->pending) ||
+- put_user(kp->sequence, &up->sequence) ||
+- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+- put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) ||
+- put_user(kp->id, &up->id) ||
+- copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
++ assign_in_user(&up->type, &kp->type) ||
++ copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
++ assign_in_user(&up->pending, &kp->pending) ||
++ assign_in_user(&up->sequence, &kp->sequence) ||
++ assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
++ assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
++ assign_in_user(&up->id, &kp->id) ||
++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ return -EFAULT;
+ return 0;
+ }
+@@ -755,31 +925,34 @@ struct v4l2_edid32 {
+ compat_caddr_t edid;
+ };
+
+-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
++static int get_v4l2_edid32(struct v4l2_edid __user *kp,
++ struct v4l2_edid32 __user *up)
+ {
+- u32 tmp;
++ compat_uptr_t tmp;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+- get_user(kp->pad, &up->pad) ||
+- get_user(kp->start_block, &up->start_block) ||
+- get_user(kp->blocks, &up->blocks) ||
++ assign_in_user(&kp->pad, &up->pad) ||
++ assign_in_user(&kp->start_block, &up->start_block) ||
++ assign_in_user(&kp->blocks, &up->blocks) ||
+ get_user(tmp, &up->edid) ||
+- copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
++ put_user(compat_ptr(tmp), &kp->edid) ||
++ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+ return -EFAULT;
+- kp->edid = (__force u8 *)compat_ptr(tmp);
+ return 0;
+ }
+
+-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
++static int put_v4l2_edid32(struct v4l2_edid __user *kp,
++ struct v4l2_edid32 __user *up)
+ {
+- u32 tmp = (u32)((unsigned long)kp->edid);
++ void *edid;
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+- put_user(kp->pad, &up->pad) ||
+- put_user(kp->start_block, &up->start_block) ||
+- put_user(kp->blocks, &up->blocks) ||
+- put_user(tmp, &up->edid) ||
+- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
++ assign_in_user(&up->pad, &kp->pad) ||
++ assign_in_user(&up->start_block, &kp->start_block) ||
++ assign_in_user(&up->blocks, &kp->blocks) ||
++ get_user(edid, &kp->edid) ||
++ put_user(ptr_to_compat(edid), &up->edid) ||
++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ return -EFAULT;
+ return 0;
+ }
+@@ -796,7 +969,7 @@ static int put_v4l2_edid32(struct v4l2_e
+ #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
+ #define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32)
+ #define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32)
+-#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
++#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
+ #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
+ #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
+ #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
+@@ -812,22 +985,23 @@ static int put_v4l2_edid32(struct v4l2_e
+ #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32)
+ #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
+
++static int alloc_userspace(unsigned int size, u32 aux_space,
++ void __user **up_native)
++{
++ *up_native = compat_alloc_user_space(size + aux_space);
++ if (!*up_native)
++ return -ENOMEM;
++ if (clear_user(*up_native, size))
++ return -EFAULT;
++ return 0;
++}
++
+ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+- union {
+- struct v4l2_format v2f;
+- struct v4l2_buffer v2b;
+- struct v4l2_framebuffer v2fb;
+- struct v4l2_input v2i;
+- struct v4l2_standard v2s;
+- struct v4l2_ext_controls v2ecs;
+- struct v4l2_event v2ev;
+- struct v4l2_create_buffers v2crt;
+- struct v4l2_edid v2edid;
+- unsigned long vx;
+- int vi;
+- } karg;
+ void __user *up = compat_ptr(arg);
++ void __user *up_native = NULL;
++ void __user *aux_buf;
++ u32 aux_space;
+ int compatible_arg = 1;
+ long err = 0;
+
+@@ -866,30 +1040,52 @@ static long do_video_ioctl(struct file *
+ case VIDIOC_STREAMOFF:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_OUTPUT:
+- err = get_user(karg.vi, (s32 __user *)up);
++ err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
++ if (!err && assign_in_user((unsigned int __user *)up_native,
++ (compat_uint_t __user *)up))
++ err = -EFAULT;
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_INPUT:
+ case VIDIOC_G_OUTPUT:
++ err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_EDID:
+ case VIDIOC_S_EDID:
+- err = get_v4l2_edid32(&karg.v2edid, up);
++ err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native);
++ if (!err)
++ err = get_v4l2_edid32(up_native, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+- err = get_v4l2_format32(&karg.v2f, up);
++ err = bufsize_v4l2_format(up, &aux_space);
++ if (!err)
++ err = alloc_userspace(sizeof(struct v4l2_format),
++ aux_space, &up_native);
++ if (!err) {
++ aux_buf = up_native + sizeof(struct v4l2_format);
++ err = get_v4l2_format32(up_native, up,
++ aux_buf, aux_space);
++ }
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_CREATE_BUFS:
+- err = get_v4l2_create32(&karg.v2crt, up);
++ err = bufsize_v4l2_create(up, &aux_space);
++ if (!err)
++ err = alloc_userspace(sizeof(struct v4l2_create_buffers),
++ aux_space, &up_native);
++ if (!err) {
++ aux_buf = up_native + sizeof(struct v4l2_create_buffers);
++ err = get_v4l2_create32(up_native, up,
++ aux_buf, aux_space);
++ }
+ compatible_arg = 0;
+ break;
+
+@@ -897,36 +1093,63 @@ static long do_video_ioctl(struct file *
+ case VIDIOC_QUERYBUF:
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+- err = get_v4l2_buffer32(&karg.v2b, up);
++ err = bufsize_v4l2_buffer(up, &aux_space);
++ if (!err)
++ err = alloc_userspace(sizeof(struct v4l2_buffer),
++ aux_space, &up_native);
++ if (!err) {
++ aux_buf = up_native + sizeof(struct v4l2_buffer);
++ err = get_v4l2_buffer32(up_native, up,
++ aux_buf, aux_space);
++ }
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_S_FBUF:
+- err = get_v4l2_framebuffer32(&karg.v2fb, up);
++ err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
++ &up_native);
++ if (!err)
++ err = get_v4l2_framebuffer32(up_native, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_FBUF:
++ err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
++ &up_native);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_ENUMSTD:
+- err = get_v4l2_standard32(&karg.v2s, up);
++ err = alloc_userspace(sizeof(struct v4l2_standard), 0,
++ &up_native);
++ if (!err)
++ err = get_v4l2_standard32(up_native, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_ENUMINPUT:
+- err = get_v4l2_input32(&karg.v2i, up);
++ err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
++ if (!err)
++ err = get_v4l2_input32(up_native, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+- err = get_v4l2_ext_controls32(file, &karg.v2ecs, up);
++ err = bufsize_v4l2_ext_controls(up, &aux_space);
++ if (!err)
++ err = alloc_userspace(sizeof(struct v4l2_ext_controls),
++ aux_space, &up_native);
++ if (!err) {
++ aux_buf = up_native + sizeof(struct v4l2_ext_controls);
++ err = get_v4l2_ext_controls32(file, up_native, up,
++ aux_buf, aux_space);
++ }
+ compatible_arg = 0;
+ break;
+ case VIDIOC_DQEVENT:
++ err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
+ compatible_arg = 0;
+ break;
+ }
+@@ -935,25 +1158,26 @@ static long do_video_ioctl(struct file *
+
+ if (compatible_arg)
+ err = native_ioctl(file, cmd, (unsigned long)up);
+- else {
+- mm_segment_t old_fs = get_fs();
+-
+- set_fs(KERNEL_DS);
+- err = native_ioctl(file, cmd, (unsigned long)&karg);
+- set_fs(old_fs);
+- }
++ else
++ err = native_ioctl(file, cmd, (unsigned long)up_native);
+
+ if (err == -ENOTTY)
+ return err;
+
+- /* Special case: even after an error we need to put the
+- results back for these ioctls since the error_idx will
+- contain information on which control failed. */
++ /*
++ * Special case: even after an error we need to put the
++ * results back for these ioctls since the error_idx will
++ * contain information on which control failed.
++ */
+ switch (cmd) {
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+- if (put_v4l2_ext_controls32(file, &karg.v2ecs, up))
++ if (put_v4l2_ext_controls32(file, up_native, up))
++ err = -EFAULT;
++ break;
++ case VIDIOC_S_EDID:
++ if (put_v4l2_edid32(up_native, up))
+ err = -EFAULT;
+ break;
+ }
+@@ -965,45 +1189,46 @@ static long do_video_ioctl(struct file *
+ case VIDIOC_S_OUTPUT:
+ case VIDIOC_G_INPUT:
+ case VIDIOC_G_OUTPUT:
+- err = put_user(((s32)karg.vi), (s32 __user *)up);
++ if (assign_in_user((compat_uint_t __user *)up,
++ ((unsigned int __user *)up_native)))
++ err = -EFAULT;
+ break;
+
+ case VIDIOC_G_FBUF:
+- err = put_v4l2_framebuffer32(&karg.v2fb, up);
++ err = put_v4l2_framebuffer32(up_native, up);
+ break;
+
+ case VIDIOC_DQEVENT:
+- err = put_v4l2_event32(&karg.v2ev, up);
++ err = put_v4l2_event32(up_native, up);
+ break;
+
+ case VIDIOC_G_EDID:
+- case VIDIOC_S_EDID:
+- err = put_v4l2_edid32(&karg.v2edid, up);
++ err = put_v4l2_edid32(up_native, up);
+ break;
+
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+- err = put_v4l2_format32(&karg.v2f, up);
++ err = put_v4l2_format32(up_native, up);
+ break;
+
+ case VIDIOC_CREATE_BUFS:
+- err = put_v4l2_create32(&karg.v2crt, up);
++ err = put_v4l2_create32(up_native, up);
+ break;
+
+ case VIDIOC_PREPARE_BUF:
+ case VIDIOC_QUERYBUF:
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+- err = put_v4l2_buffer32(&karg.v2b, up);
++ err = put_v4l2_buffer32(up_native, up);
+ break;
+
+ case VIDIOC_ENUMSTD:
+- err = put_v4l2_standard32(&karg.v2s, up);
++ err = put_v4l2_standard32(up_native, up);
+ break;
+
+ case VIDIOC_ENUMINPUT:
+- err = put_v4l2_input32(&karg.v2i, up);
++ err = put_v4l2_input32(up_native, up);
+ break;
+ }
+ return err;
--- /dev/null
+From foo@baz Wed Apr 4 17:30:18 CEST 2018
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 28 Mar 2018 15:12:34 -0300
+Subject: media: v4l2-ctrls: fix sparse warning
+To: Linux Media Mailing List <linux-media@vger.kernel.org>, stable@vger.kernel.org
+Cc: Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@infradead.org>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, Mauro Carvalho Chehab <mchehab@osg.samsung.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <d53d22eb0ea4cdbcb2e7f02d789a01892d8c36cf.1522260310.git.mchehab@s-opensource.com>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+The warning is simple:
+
+drivers/media/v4l2-core/v4l2-ctrls.c:1685:15: warning: incorrect type in assignment (different address spaces)
+
+but the fix isn't.
+
+The core problem was that the conversion from user to kernelspace was
+done at too low a level and that needed to be moved up. That made it possible
+to drop pointers to v4l2_ext_control from set_ctrl and validate_new and
+clean up this sparse warning because those functions now always operate
+on kernelspace pointers.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-ctrls.c | 87 ++++++++++++++++++++---------------
+ 1 file changed, 52 insertions(+), 35 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-ctrls.c
++++ b/drivers/media/v4l2-core/v4l2-ctrls.c
+@@ -1668,10 +1668,8 @@ static int check_range(enum v4l2_ctrl_ty
+ }
+
+ /* Validate a new control */
+-static int validate_new(const struct v4l2_ctrl *ctrl,
+- struct v4l2_ext_control *c)
++static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
+ {
+- union v4l2_ctrl_ptr ptr;
+ unsigned idx;
+ int err = 0;
+
+@@ -1684,19 +1682,14 @@ static int validate_new(const struct v4l
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ case V4L2_CTRL_TYPE_BUTTON:
+ case V4L2_CTRL_TYPE_CTRL_CLASS:
+- ptr.p_s32 = &c->value;
+- return ctrl->type_ops->validate(ctrl, 0, ptr);
+-
+ case V4L2_CTRL_TYPE_INTEGER64:
+- ptr.p_s64 = &c->value64;
+- return ctrl->type_ops->validate(ctrl, 0, ptr);
++ return ctrl->type_ops->validate(ctrl, 0, p_new);
+ default:
+ break;
+ }
+ }
+- ptr.p = c->ptr;
+- for (idx = 0; !err && idx < c->size / ctrl->elem_size; idx++)
+- err = ctrl->type_ops->validate(ctrl, idx, ptr);
++ for (idx = 0; !err && idx < ctrl->elems; idx++)
++ err = ctrl->type_ops->validate(ctrl, idx, p_new);
+ return err;
+ }
+
+@@ -3020,6 +3013,7 @@ static int validate_ctrls(struct v4l2_ex
+ cs->error_idx = cs->count;
+ for (i = 0; i < cs->count; i++) {
+ struct v4l2_ctrl *ctrl = helpers[i].ctrl;
++ union v4l2_ctrl_ptr p_new;
+
+ cs->error_idx = i;
+
+@@ -3033,7 +3027,17 @@ static int validate_ctrls(struct v4l2_ex
+ best-effort to avoid that. */
+ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
+ return -EBUSY;
+- ret = validate_new(ctrl, &cs->controls[i]);
++ /*
++ * Skip validation for now if the payload needs to be copied
++ * from userspace into kernelspace. We'll validate those later.
++ */
++ if (ctrl->is_ptr)
++ continue;
++ if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
++ p_new.p_s64 = &cs->controls[i].value64;
++ else
++ p_new.p_s32 = &cs->controls[i].value;
++ ret = validate_new(ctrl, p_new);
+ if (ret)
+ return ret;
+ }
+@@ -3128,7 +3132,11 @@ static int try_set_ext_ctrls(struct v4l2
+ /* Copy the new caller-supplied control values.
+ user_to_new() sets 'is_new' to 1. */
+ do {
+- ret = user_to_new(cs->controls + idx, helpers[idx].ctrl);
++ struct v4l2_ctrl *ctrl = helpers[idx].ctrl;
++
++ ret = user_to_new(cs->controls + idx, ctrl);
++ if (!ret && ctrl->is_ptr)
++ ret = validate_new(ctrl, ctrl->p_new);
+ idx = helpers[idx].next;
+ } while (!ret && idx);
+
+@@ -3178,10 +3186,10 @@ int v4l2_subdev_s_ext_ctrls(struct v4l2_
+ EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
+
+ /* Helper function for VIDIOC_S_CTRL compatibility */
+-static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
+- struct v4l2_ext_control *c, u32 ch_flags)
++static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
+ {
+ struct v4l2_ctrl *master = ctrl->cluster[0];
++ int ret;
+ int i;
+
+ /* Reset the 'is_new' flags of the cluster */
+@@ -3189,8 +3197,9 @@ static int set_ctrl(struct v4l2_fh *fh,
+ if (master->cluster[i])
+ master->cluster[i]->is_new = 0;
+
+- if (c)
+- user_to_new(c, ctrl);
++ ret = validate_new(ctrl, ctrl->p_new);
++ if (ret)
++ return ret;
+
+ /* For autoclusters with volatiles that are switched from auto to
+ manual mode we have to update the current volatile values since
+@@ -3207,15 +3216,14 @@ static int set_ctrl(struct v4l2_fh *fh,
+ static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
+ struct v4l2_ext_control *c)
+ {
+- int ret = validate_new(ctrl, c);
++ int ret;
+
+- if (!ret) {
+- v4l2_ctrl_lock(ctrl);
+- ret = set_ctrl(fh, ctrl, c, 0);
+- if (!ret)
+- cur_to_user(c, ctrl);
+- v4l2_ctrl_unlock(ctrl);
+- }
++ v4l2_ctrl_lock(ctrl);
++ user_to_new(c, ctrl);
++ ret = set_ctrl(fh, ctrl, 0);
++ if (!ret)
++ cur_to_user(c, ctrl);
++ v4l2_ctrl_unlock(ctrl);
+ return ret;
+ }
+
+@@ -3223,7 +3231,7 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, stru
+ struct v4l2_control *control)
+ {
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+- struct v4l2_ext_control c;
++ struct v4l2_ext_control c = { control->id };
+ int ret;
+
+ if (ctrl == NULL || !ctrl->is_int)
+@@ -3252,7 +3260,7 @@ int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl
+ /* It's a driver bug if this happens. */
+ WARN_ON(!ctrl->is_int);
+ ctrl->val = val;
+- return set_ctrl(NULL, ctrl, NULL, 0);
++ return set_ctrl(NULL, ctrl, 0);
+ }
+ EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl);
+
+@@ -3263,7 +3271,7 @@ int __v4l2_ctrl_s_ctrl_int64(struct v4l2
+ /* It's a driver bug if this happens. */
+ WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
+ *ctrl->p_new.p_s64 = val;
+- return set_ctrl(NULL, ctrl, NULL, 0);
++ return set_ctrl(NULL, ctrl, 0);
+ }
+ EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64);
+
+@@ -3274,7 +3282,7 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l
+ /* It's a driver bug if this happens. */
+ WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING);
+ strlcpy(ctrl->p_new.p_char, s, ctrl->maximum + 1);
+- return set_ctrl(NULL, ctrl, NULL, 0);
++ return set_ctrl(NULL, ctrl, 0);
+ }
+ EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
+
+@@ -3297,8 +3305,8 @@ EXPORT_SYMBOL(v4l2_ctrl_notify);
+ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
+ s64 min, s64 max, u64 step, s64 def)
+ {
++ bool changed;
+ int ret;
+- struct v4l2_ext_control c;
+
+ lockdep_assert_held(ctrl->handler->lock);
+
+@@ -3325,11 +3333,20 @@ int __v4l2_ctrl_modify_range(struct v4l2
+ ctrl->maximum = max;
+ ctrl->step = step;
+ ctrl->default_value = def;
+- c.value = *ctrl->p_cur.p_s32;
+- if (validate_new(ctrl, &c))
+- c.value = def;
+- if (c.value != *ctrl->p_cur.p_s32)
+- ret = set_ctrl(NULL, ctrl, &c, V4L2_EVENT_CTRL_CH_RANGE);
++ cur_to_new(ctrl);
++ if (validate_new(ctrl, ctrl->p_new)) {
++ if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
++ *ctrl->p_new.p_s64 = def;
++ else
++ *ctrl->p_new.p_s32 = def;
++ }
++
++ if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
++ changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
++ else
++ changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
++ if (changed)
++ ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
+ else
+ send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
+ return ret;
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