]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 14 Feb 2018 19:56:06 +0000 (20:56 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 14 Feb 2018 19:56:06 +0000 (20:56 +0100)
added patches:
media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch
media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch
media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch
media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch
media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch
media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch
media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch
media-v4l2-compat-ioctl32.c-fix-the-indentation.patch
media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch
media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch
media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch
media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch
media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch

14 files changed:
queue-4.14/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch [new file with mode: 0644]
queue-4.14/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch [new file with mode: 0644]
queue-4.14/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch [new file with mode: 0644]
queue-4.14/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch [new file with mode: 0644]
queue-4.14/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch [new file with mode: 0644]
queue-4.14/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch [new file with mode: 0644]
queue-4.14/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch [new file with mode: 0644]
queue-4.14/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch [new file with mode: 0644]
queue-4.14/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch [new file with mode: 0644]
queue-4.14/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch [new file with mode: 0644]
queue-4.14/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch [new file with mode: 0644]
queue-4.14/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch [new file with mode: 0644]
queue-4.14/media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch
new file mode 100644 (file)
index 0000000..593b762
--- /dev/null
@@ -0,0 +1,33 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:24 +0100
+Subject: media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-4-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 3ee6d040719ae09110e5cdf24d5386abe5d1b776 upstream.
+
+The result of the VIDIOC_PREPARE_BUF ioctl was never copied back
+to userspace since it was missing in the switch.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: 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
+@@ -1052,6 +1052,7 @@ static long do_video_ioctl(struct file *
+               err = put_v4l2_create32(&karg.v2crt, up);
+               break;
++      case VIDIOC_PREPARE_BUF:
+       case VIDIOC_QUERYBUF:
+       case VIDIOC_QBUF:
+       case VIDIOC_DQBUF:
diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch
new file mode 100644 (file)
index 0000000..425ed1f
--- /dev/null
@@ -0,0 +1,324 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:27 +0100
+Subject: media: v4l2-compat-ioctl32.c: avoid sizeof(type)
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-7-hverkuil@xs4all.nl>
+
+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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |   79 +++++++++++---------------
+ 1 file changed, 36 insertions(+), 43 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -48,7 +48,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) ||
+@@ -66,7 +66,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)))
+@@ -164,14 +164,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);
+@@ -218,14 +218,14 @@ 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)))
++      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)) ||
++      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;
+@@ -244,7 +244,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;
+@@ -252,14 +252,14 @@ 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) ||
+           put_user(kp->id, &up->id) ||
+-          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;
+ }
+@@ -307,7 +307,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) {
+@@ -317,11 +317,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;
+       }
+@@ -333,19 +333,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;
+@@ -358,7 +358,7 @@ static int get_v4l2_buffer32(struct v4l2
+       compat_caddr_t p;
+       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) ||
+@@ -370,8 +370,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)) {
+@@ -391,13 +390,12 @@ static int get_v4l2_buffer32(struct v4l2
+               uplane32 = compat_ptr(p);
+               if (!access_ok(VERIFY_READ, uplane32,
+-                             kp->length * sizeof(struct v4l2_plane32)))
++                             kp->length * 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(kp->length *
+-                                               sizeof(struct v4l2_plane));
++              uplane = compat_alloc_user_space(kp->length * sizeof(*uplane));
+               kp->m.planes = (__force struct v4l2_plane *)uplane;
+               for (num_planes = 0; num_planes < kp->length; num_planes++) {
+@@ -445,7 +443,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) ||
+@@ -456,8 +454,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) ||
+@@ -525,7 +522,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) ||
+@@ -539,7 +536,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) ||
+@@ -564,14 +561,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;
+ }
+@@ -619,12 +616,11 @@ static int get_v4l2_ext_controls32(struc
+       unsigned 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->which, &up->which) ||
+           get_user(kp->count, &up->count) ||
+           get_user(kp->error_idx, &up->error_idx) ||
+-          copy_from_user(kp->reserved, up->reserved,
+-                         sizeof(kp->reserved)))
++          copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
+       if (kp->count == 0) {
+               kp->controls = NULL;
+@@ -635,11 +631,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,
+-                     kp->count * sizeof(struct v4l2_ext_control32)))
++      if (!access_ok(VERIFY_READ, ucontrols, kp->count * sizeof(*ucontrols)))
+               return -EFAULT;
+-      kcontrols = compat_alloc_user_space(kp->count *
+-                                          sizeof(struct v4l2_ext_control));
++      kcontrols = compat_alloc_user_space(kp->count * sizeof(*kcontrols));
+       kp->controls = (__force struct v4l2_ext_control *)kcontrols;
+       for (n = 0; n < kp->count; n++) {
+               u32 id;
+@@ -671,7 +665,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->which, &up->which) ||
+           put_user(kp->count, &up->count) ||
+           put_user(kp->error_idx, &up->error_idx) ||
+@@ -683,8 +677,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) {
+@@ -721,7 +714,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) ||
+@@ -729,7 +722,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;
+ }
+@@ -746,7 +739,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) ||
+@@ -761,7 +754,7 @@ static int put_v4l2_edid32(struct v4l2_e
+ {
+       u32 tmp = (u32)((unsigned long)kp->edid);
+-      if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
++      if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           put_user(kp->pad, &up->pad) ||
+           put_user(kp->start_block, &up->start_block) ||
+           put_user(kp->blocks, &up->blocks) ||
diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch
new file mode 100644 (file)
index 0000000..b67b782
--- /dev/null
@@ -0,0 +1,111 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:30 +0100
+Subject: media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-10-hverkuil@xs4all.nl>
+
+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: 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;
+ }
diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch
new file mode 100644 (file)
index 0000000..7848672
--- /dev/null
@@ -0,0 +1,132 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:28 +0100
+Subject: media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-8-hverkuil@xs4all.nl>
+
+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: 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
+@@ -310,19 +310,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;
+@@ -331,22 +336,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;
+ }
+@@ -408,6 +423,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;
+@@ -421,10 +437,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;
+@@ -481,6 +493,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;
+@@ -488,10 +501,6 @@ static int put_v4l2_buffer32(struct v4l2
+                       if (put_user(kp->m.userptr, &up->m.userptr))
+                               return -EFAULT;
+                       break;
+-              case V4L2_MEMORY_OVERLAY:
+-                      if (put_user(kp->m.offset, &up->m.offset))
+-                              return -EFAULT;
+-                      break;
+               case V4L2_MEMORY_DMABUF:
+                       if (put_user(kp->m.fd, &up->m.fd))
+                               return -EFAULT;
diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch
new file mode 100644 (file)
index 0000000..6ee0201
--- /dev/null
@@ -0,0 +1,36 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:32 +0100
+Subject: media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-12-hverkuil@xs4all.nl>
+
+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: 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
+@@ -968,6 +968,9 @@ static long do_video_ioctl(struct file *
+               set_fs(old_fs);
+       }
++      if (err == -ENOTTY)
++              return err;
++
+       /* Special case: even after an error we need to put the
+          results back for these ioctls since the error_idx will
+          contain information on which control failed. */
diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch
new file mode 100644 (file)
index 0000000..23f0252
--- /dev/null
@@ -0,0 +1,44 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:31 +0100
+Subject: media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-11-hverkuil@xs4all.nl>
+
+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: 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
+@@ -179,8 +179,6 @@ static int __get_v4l2_format32(struct v4
+               return copy_from_user(&kp->fmt.meta, &up->fmt.meta,
+                                     sizeof(kp->fmt.meta)) ? -EFAULT : 0;
+       default:
+-              pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+-                      kp->type);
+               return -EINVAL;
+       }
+ }
+@@ -233,8 +231,6 @@ static int __put_v4l2_format32(struct v4
+               return copy_to_user(&up->fmt.meta, &kp->fmt.meta,
+                                   sizeof(kp->fmt.meta)) ? -EFAULT : 0;
+       default:
+-              pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+-                      kp->type);
+               return -EINVAL;
+       }
+ }
diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch
new file mode 100644 (file)
index 0000000..831aed6
--- /dev/null
@@ -0,0 +1,144 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:29 +0100
+Subject: media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-9-hverkuil@xs4all.nl>
+
+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: 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)
+@@ -601,24 +603,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;
+@@ -651,7 +668,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))
+@@ -666,7 +683,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 =
+@@ -698,7 +717,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;
+@@ -912,7 +931,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:
+@@ -939,7 +958,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;
+       case VIDIOC_S_EDID:
diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch
new file mode 100644 (file)
index 0000000..9136c4c
--- /dev/null
@@ -0,0 +1,429 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:25 +0100
+Subject: media: v4l2-compat-ioctl32.c: fix the indentation
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-5-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit b7b957d429f601d6d1942122b339474f31191d75 upstream.
+
+The indentation of this source is all over the place. Fix this.
+This patch only changes whitespace.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |  212 +++++++++++++-------------
+ 1 file changed, 107 insertions(+), 105 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -49,12 +49,12 @@ 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) ||
+-              get_user(kp->global_alpha, &up->global_alpha))
+-                      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) ||
++          get_user(kp->global_alpha, &up->global_alpha))
++              return -EFAULT;
+       if (kp->clipcount > 2048)
+               return -EINVAL;
+       if (kp->clipcount) {
+@@ -84,11 +84,11 @@ 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) ||
+-              put_user(kp->global_alpha, &up->global_alpha))
+-                      return -EFAULT;
++          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;
+       return 0;
+ }
+@@ -100,7 +100,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;
+@@ -115,7 +115,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;
+@@ -238,7 +238,7 @@ static int __get_v4l2_format32(struct v4
+               return get_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta);
+       default:
+               pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+-                                                              kp->type);
++                      kp->type);
+               return -EINVAL;
+       }
+ }
+@@ -287,7 +287,7 @@ static int __put_v4l2_format32(struct v4
+               return put_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta);
+       default:
+               pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+-                                                              kp->type);
++                      kp->type);
+               return -EINVAL;
+       }
+ }
+@@ -321,7 +321,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;
+ }
+@@ -329,13 +329,14 @@ 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) ||
+-              put_user(kp->id, &up->id) ||
+-              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) ||
++          put_user(kp->id, &up->id) ||
++          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;
+ }
+@@ -375,14 +376,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) {
+@@ -396,7 +397,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;
+       }
+@@ -404,23 +405,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;
+@@ -434,19 +435,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)) {
+@@ -466,7 +467,7 @@ static int get_v4l2_buffer32(struct v4l2
+               uplane32 = compat_ptr(p);
+               if (!access_ok(VERIFY_READ, uplane32,
+-                              kp->length * sizeof(struct v4l2_plane32)))
++                             kp->length * sizeof(struct v4l2_plane32)))
+                       return -EFAULT;
+               /* We don't really care if userspace decides to kill itself
+@@ -490,12 +491,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:
+@@ -521,22 +522,23 @@ 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;
+@@ -600,11 +602,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;
+ }
+@@ -614,11 +616,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;
+ }
+@@ -694,12 +696,12 @@ 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->which, &up->which) ||
+-              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->which, &up->which) ||
++          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;
+       if (kp->count == 0) {
+               kp->controls = NULL;
+               return 0;
+@@ -710,7 +712,7 @@ static int get_v4l2_ext_controls32(struc
+               return -EFAULT;
+       ucontrols = compat_ptr(p);
+       if (!access_ok(VERIFY_READ, ucontrols,
+-                      kp->count * sizeof(struct v4l2_ext_control32)))
++                     kp->count * sizeof(struct v4l2_ext_control32)))
+               return -EFAULT;
+       kcontrols = compat_alloc_user_space(kp->count *
+                                           sizeof(struct v4l2_ext_control));
+@@ -746,11 +748,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->which, &up->which) ||
+-              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->which, &up->which) ||
++          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;
+@@ -758,7 +760,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) {
+@@ -796,15 +798,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;
+ }
+@@ -821,12 +823,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;
+ }
+@@ -836,12 +838,12 @@ static int put_v4l2_edid32(struct v4l2_e
+       u32 tmp = (u32)((unsigned long)kp->edid);
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
+-              put_user(kp->pad, &up->pad) ||
+-              put_user(kp->start_block, &up->start_block) ||
+-              put_user(kp->blocks, &up->blocks) ||
+-              put_user(tmp, &up->edid) ||
+-              copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+-                      return -EFAULT;
++          put_user(kp->pad, &up->pad) ||
++          put_user(kp->start_block, &up->start_block) ||
++          put_user(kp->blocks, &up->blocks) ||
++          put_user(tmp, &up->edid) ||
++          copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
++              return -EFAULT;
+       return 0;
+ }
diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch
new file mode 100644 (file)
index 0000000..60a56f1
--- /dev/null
@@ -0,0 +1,43 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:34 +0100
+Subject: media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-14-hverkuil@xs4all.nl>
+
+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: 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
+@@ -770,7 +770,7 @@ static inline bool ctrl_is_pointer(struc
+               return ctrl && ctrl->is_ptr;
+       }
+-      if (!ops->vidioc_query_ext_ctrl)
++      if (!ops || !ops->vidioc_query_ext_ctrl)
+               return false;
+       return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch
new file mode 100644 (file)
index 0000000..b7aacc5
--- /dev/null
@@ -0,0 +1,194 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:26 +0100
+Subject: media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-6-hverkuil@xs4all.nl>
+
+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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |  124 +++++---------------------
+ 1 file changed, 24 insertions(+), 100 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -92,92 +92,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;
+-}
+-
+-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+-{
+-      if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+-{
+-      if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int get_v4l2_meta_format(struct v4l2_meta_format *kp, struct v4l2_meta_format __user *up)
+-{
+-      if (copy_from_user(kp, up, sizeof(struct v4l2_meta_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int put_v4l2_meta_format(struct v4l2_meta_format *kp, struct v4l2_meta_format __user *up)
+-{
+-      if (copy_to_user(up, kp, sizeof(struct v4l2_meta_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+ struct v4l2_format32 {
+       __u32   type;   /* enum v4l2_buf_type */
+       union {
+@@ -217,25 +131,30 @@ 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;
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
++              return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr,
++                                    sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_META_CAPTURE:
+-              return get_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta);
++              return copy_from_user(&kp->fmt.meta, &up->fmt.meta,
++                                    sizeof(kp->fmt.meta)) ? -EFAULT : 0;
+       default:
+               pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+                       kp->type);
+@@ -266,25 +185,30 @@ 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;
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
++              return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr,
++                                  sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_META_CAPTURE:
+-              return put_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta);
++              return copy_to_user(&up->fmt.meta, &kp->fmt.meta,
++                                  sizeof(kp->fmt.meta)) ? -EFAULT : 0;
+       default:
+               pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+                       kp->type);
diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch
new file mode 100644 (file)
index 0000000..3325891
--- /dev/null
@@ -0,0 +1,1302 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Daniel Mentz <danielmentz@google.com>
+Date: Wed, 14 Feb 2018 12:44:33 +0100
+Subject: media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Daniel Mentz <danielmentz@google.com>, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-13-hverkuil@xs4all.nl>
+
+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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |  752 ++++++++++++++++----------
+ 1 file changed, 483 insertions(+), 269 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;
+@@ -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++;
+@@ -146,107 +159,164 @@ 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 (!access_ok(VERIFY_READ, up, sizeof(*up)))
++              return -EFAULT;
++      return __bufsize_v4l2_format(up, size);
++}
++
++static int __get_v4l2_format32(struct v4l2_format __user *kp,
++                             struct v4l2_format32 __user *up,
++                             void __user *aux_buf, u32 aux_space)
+ {
+-      if (get_user(kp->type, &up->type))
++      u32 type;
++
++      if (get_user(type, &up->type) || put_user(type, &kp->type))
+               return -EFAULT;
+-      switch (kp->type) {
++      switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-              return copy_from_user(&kp->fmt.pix, &up->fmt.pix,
+-                                    sizeof(kp->fmt.pix)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
++                                  sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+-              return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
+-                                    sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
++                                  sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+-              return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
++              return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
++                                       aux_buf, aux_space);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+-              return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi,
+-                                    sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
++                                  sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+-              return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced,
+-                                    sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
++                                  sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr,
+-                                    sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr,
++                                  sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_META_CAPTURE:
+-              return copy_from_user(&kp->fmt.meta, &up->fmt.meta,
+-                                    sizeof(kp->fmt.meta)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.meta, &up->fmt.meta,
++                                  sizeof(kp->fmt.meta)) ? -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)
+ {
+-      if (put_user(kp->type, &up->type))
++      u32 type;
++
++      if (get_user(type, &kp->type))
+               return -EFAULT;
+-      switch (kp->type) {
++      switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-              return copy_to_user(&up->fmt.pix, &kp->fmt.pix,
++              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,
++              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,
++              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,
++              return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
+                                   sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr,
++              return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr,
+                                   sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_META_CAPTURE:
+-              return copy_to_user(&up->fmt.meta, &kp->fmt.meta,
++              return copy_in_user(&up->fmt.meta, &kp->fmt.meta,
+                                   sizeof(kp->fmt.meta)) ? -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);
+ }
+@@ -260,25 +330,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) ||
+-          put_user(kp->id, &up->id) ||
+-          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) ||
++          assign_in_user(&up->id, &kp->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;
+ }
+@@ -318,11 +390,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,
+@@ -337,10 +409,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:
+@@ -352,7 +422,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;
+@@ -376,8 +447,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;
+       }
+@@ -385,79 +455,121 @@ 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 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))
+-                      return -EFAULT;
+-
+-      if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+-              unsigned int num_planes;
+-
+-              if (kp->length == 0) {
+-                      kp->m.planes = NULL;
+-                      /* num_planes == 0 is legal, e.g. when userspace doesn't
+-                       * need planes array on DQBUF*/
+-                      return 0;
+-              } else if (kp->length > VIDEO_MAX_PLANES) {
+-                      return -EINVAL;
++          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(type)) {
++              u32 num_planes = length;
++
++              if (num_planes == 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;
+               uplane32 = compat_ptr(p);
+               if (!access_ok(VERIFY_READ, uplane32,
+-                             kp->length * sizeof(*uplane32)))
++                             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(kp->length * 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;
+-              for (num_planes = 0; num_planes < kp->length; num_planes++) {
+-                      ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
++              uplane = aux_buf;
++              if (put_user((__force struct v4l2_plane *)uplane,
++                           &kp->m.planes))
++                      return -EFAULT;
++
++              while (num_planes--) {
++                      ret = get_v4l2_plane32(uplane, uplane32, memory);
+                       if (ret)
+                               return ret;
+-                      ++uplane;
+-                      ++uplane32;
++                      uplane++;
++                      uplane32++;
+               }
+       } else {
+-              switch (kp->memory) {
++              switch (memory) {
+               case V4L2_MEMORY_MMAP:
+               case V4L2_MEMORY_OVERLAY:
+-                      if (get_user(kp->m.offset, &up->m.offset))
++                      if (assign_in_user(&kp->m.offset, &up->m.offset))
+                               return -EFAULT;
+                       break;
+-              case V4L2_MEMORY_USERPTR:
+-                      {
+-                              compat_long_t tmp;
++              case V4L2_MEMORY_USERPTR: {
++                      compat_ulong_t userptr;
+-                              if (get_user(tmp, &up->m.userptr))
+-                                      return -EFAULT;
+-
+-                              kp->m.userptr = (unsigned long)compat_ptr(tmp);
+-                      }
++                      if (get_user(userptr, &up->m.userptr) ||
++                          put_user((unsigned long)compat_ptr(userptr),
++                                   &kp->m.userptr))
++                              return -EFAULT;
+                       break;
++              }
+               case V4L2_MEMORY_DMABUF:
+-                      if (get_user(kp->m.fd, &up->m.fd))
++                      if (assign_in_user(&kp->m.fd, &up->m.fd))
+                               return -EFAULT;
+                       break;
+               }
+@@ -466,62 +578,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;
+               }
+@@ -546,29 +666,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;
+ }
+@@ -585,18 +708,22 @@ struct v4l2_input32 {
+       __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;
+ }
+@@ -650,41 +777,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;
+-      unsigned int n;
++      u32 count;
++      u32 n;
+       compat_caddr_t p;
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+-          get_user(kp->which, &up->which) ||
+-          get_user(kp->count, &up->count) ||
+-          get_user(kp->error_idx, &up->error_idx) ||
+-          copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
++          assign_in_user(&kp->which, &up->which) ||
++          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 (kp->count == 0) {
+-              kp->controls = NULL;
+-              return 0;
+-      } else if (kp->count > V4L2_CID_MAX_CTRLS) {
++
++      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, kp->count * sizeof(*ucontrols)))
++      if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
+               return -EFAULT;
+-      kcontrols = compat_alloc_user_space(kp->count * sizeof(*kcontrols));
+-      kp->controls = (__force struct v4l2_ext_control *)kcontrols;
+-      for (n = 0; n < kp->count; n++) {
++      if (aux_space < count * sizeof(*kcontrols))
++              return -EFAULT;
++      kcontrols = aux_buf;
++      if (put_user((__force struct v4l2_ext_control *)kcontrols,
++                   &kp->controls))
++              return -EFAULT;
++
++      for (n = 0; n < count; n++) {
+               u32 id;
+               if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
+                       return -EFAULT;
++
+               if (get_user(id, &kcontrols->id))
+                       return -EFAULT;
++
+               if (ctrl_is_pointer(file, id)) {
+                       void __user *s;
+@@ -701,43 +851,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->which, &up->which) ||
+-          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->which, &kp->which) ||
++          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++;
+       }
+@@ -757,17 +918,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;
+ }
+@@ -780,31 +942,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;
+ }
+@@ -837,22 +1002,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;
+@@ -891,30 +1057,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;
+@@ -922,36 +1110,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;
+       }
+@@ -960,29 +1175,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(&karg.v2edid, up))
++              if (put_v4l2_edid32(up_native, up))
+                       err = -EFAULT;
+               break;
+       }
+@@ -994,44 +1206,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:
+-              err = put_v4l2_edid32(&karg.v2edid, up);
++              err = put_v4l2_edid32(up_native, up);
+               break;
+       case VIDIOC_G_FMT:
+       case VIDIOC_S_FMT:
+       case VIDIOC_TRY_FMT:
+-              err = put_v4l2_format32(&karg.v2f, up);
++              err = put_v4l2_format32(up_native, up);
+               break;
+       case VIDIOC_CREATE_BUFS:
+-              err = put_v4l2_create32(&karg.v2crt, up);
++              err = put_v4l2_create32(up_native, up);
+               break;
+       case VIDIOC_PREPARE_BUF:
+       case VIDIOC_QUERYBUF:
+       case VIDIOC_QBUF:
+       case VIDIOC_DQBUF:
+-              err = put_v4l2_buffer32(&karg.v2b, up);
++              err = put_v4l2_buffer32(up_native, up);
+               break;
+       case VIDIOC_ENUMSTD:
+-              err = put_v4l2_standard32(&karg.v2s, up);
++              err = put_v4l2_standard32(up_native, up);
+               break;
+       case VIDIOC_ENUMINPUT:
+-              err = put_v4l2_input32(&karg.v2i, up);
++              err = put_v4l2_input32(up_native, up);
+               break;
+       }
+       return err;
diff --git a/queue-4.14/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch b/queue-4.14/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch
new file mode 100644 (file)
index 0000000..be9094f
--- /dev/null
@@ -0,0 +1,38 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:23 +0100
+Subject: media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-3-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 181a4a2d5a0a7b43cab08a70710d727e7764ccdd upstream.
+
+If the ioctl returned -ENOTTY, then don't bother copying
+back the result as there is no point.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-ioctl.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/v4l2-core/v4l2-ioctl.c
++++ b/drivers/media/v4l2-core/v4l2-ioctl.c
+@@ -2892,8 +2892,11 @@ video_usercopy(struct file *file, unsign
+       /* Handles IOCTL */
+       err = func(file, cmd, parg);
+-      if (err == -ENOIOCTLCMD)
++      if (err == -ENOTTY || err == -ENOIOCTLCMD) {
+               err = -ENOTTY;
++              goto out;
++      }
++
+       if (err == 0) {
+               if (cmd == VIDIOC_DQBUF)
+                       trace_v4l2_dqbuf(video_devdata(file)->minor, parg);
diff --git a/queue-4.14/media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch b/queue-4.14/media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch
new file mode 100644 (file)
index 0000000..a4f79d2
--- /dev/null
@@ -0,0 +1,394 @@
+From foo@baz Wed Feb 14 20:54:11 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:44:22 +0100
+Subject: media: v4l2-ioctl.c: use check_fmt for enum/g/s/try_fmt
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214114434.26842-2-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit b2469c814fbc8f1f19676dd4912717b798df511e upstream.
+
+Don't duplicate the buffer type checks in enum/g/s/try_fmt.
+The check_fmt function does that already.
+
+It is hard to keep the checks in sync for all these functions and
+in fact the check for VBI was wrong in the _fmt functions as it
+allowed SDR types as well. This caused a v4l2-compliance failure
+for /dev/swradio0 using vivid.
+
+This simplifies the code and keeps the check in one place and
+fixes the SDR/VBI bug.
+
+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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-ioctl.c |  140 +++++++++++++----------------------
+ 1 file changed, 54 insertions(+), 86 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-ioctl.c
++++ b/drivers/media/v4l2-core/v4l2-ioctl.c
+@@ -1308,52 +1308,50 @@ static int v4l_enum_fmt(const struct v4l
+                               struct file *file, void *fh, void *arg)
+ {
+       struct v4l2_fmtdesc *p = arg;
+-      struct video_device *vfd = video_devdata(file);
+-      bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+-      bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+-      bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
+-      bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
+-      bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
+-      int ret = -EINVAL;
++      int ret = check_fmt(file, p->type);
++
++      if (ret)
++              return ret;
++      ret = -EINVAL;
+       switch (p->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-              if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_enum_fmt_vid_cap))
++              if (unlikely(!ops->vidioc_enum_fmt_vid_cap))
+                       break;
+               ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_cap_mplane))
++              if (unlikely(!ops->vidioc_enum_fmt_vid_cap_mplane))
+                       break;
+               ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_overlay))
++              if (unlikely(!ops->vidioc_enum_fmt_vid_overlay))
+                       break;
+               ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, arg);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_enum_fmt_vid_out))
++              if (unlikely(!ops->vidioc_enum_fmt_vid_out))
+                       break;
+               ret = ops->vidioc_enum_fmt_vid_out(file, fh, arg);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_enum_fmt_vid_out_mplane))
++              if (unlikely(!ops->vidioc_enum_fmt_vid_out_mplane))
+                       break;
+               ret = ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg);
+               break;
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+-              if (unlikely(!is_rx || !is_sdr || !ops->vidioc_enum_fmt_sdr_cap))
++              if (unlikely(!ops->vidioc_enum_fmt_sdr_cap))
+                       break;
+               ret = ops->vidioc_enum_fmt_sdr_cap(file, fh, arg);
+               break;
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              if (unlikely(!is_tx || !is_sdr || !ops->vidioc_enum_fmt_sdr_out))
++              if (unlikely(!ops->vidioc_enum_fmt_sdr_out))
+                       break;
+               ret = ops->vidioc_enum_fmt_sdr_out(file, fh, arg);
+               break;
+       case V4L2_BUF_TYPE_META_CAPTURE:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_meta_cap))
++              if (unlikely(!ops->vidioc_enum_fmt_meta_cap))
+                       break;
+               ret = ops->vidioc_enum_fmt_meta_cap(file, fh, arg);
+               break;
+@@ -1367,13 +1365,10 @@ static int v4l_g_fmt(const struct v4l2_i
+                               struct file *file, void *fh, void *arg)
+ {
+       struct v4l2_format *p = arg;
+-      struct video_device *vfd = video_devdata(file);
+-      bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+-      bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+-      bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
+-      bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
+-      bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
+-      int ret;
++      int ret = check_fmt(file, p->type);
++
++      if (ret)
++              return ret;
+       /*
+        * fmt can't be cleared for these overlay types due to the 'clips'
+@@ -1401,7 +1396,7 @@ static int v4l_g_fmt(const struct v4l2_i
+       switch (p->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-              if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_g_fmt_vid_cap))
++              if (unlikely(!ops->vidioc_g_fmt_vid_cap))
+                       break;
+               p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+               ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg);
+@@ -1409,23 +1404,15 @@ static int v4l_g_fmt(const struct v4l2_i
+               p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+               return ret;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_cap_mplane))
+-                      break;
+               return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_overlay))
+-                      break;
+               return ops->vidioc_g_fmt_vid_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+-              if (unlikely(!is_rx || is_vid || !ops->vidioc_g_fmt_vbi_cap))
+-                      break;
+               return ops->vidioc_g_fmt_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+-              if (unlikely(!is_rx || is_vid || !ops->vidioc_g_fmt_sliced_vbi_cap))
+-                      break;
+               return ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out))
++              if (unlikely(!ops->vidioc_g_fmt_vid_out))
+                       break;
+               p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+               ret = ops->vidioc_g_fmt_vid_out(file, fh, arg);
+@@ -1433,32 +1420,18 @@ static int v4l_g_fmt(const struct v4l2_i
+               p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+               return ret;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_mplane))
+-                      break;
+               return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_overlay))
+-                      break;
+               return ops->vidioc_g_fmt_vid_out_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+-              if (unlikely(!is_tx || is_vid || !ops->vidioc_g_fmt_vbi_out))
+-                      break;
+               return ops->vidioc_g_fmt_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+-              if (unlikely(!is_tx || is_vid || !ops->vidioc_g_fmt_sliced_vbi_out))
+-                      break;
+               return ops->vidioc_g_fmt_sliced_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+-              if (unlikely(!is_rx || !is_sdr || !ops->vidioc_g_fmt_sdr_cap))
+-                      break;
+               return ops->vidioc_g_fmt_sdr_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              if (unlikely(!is_tx || !is_sdr || !ops->vidioc_g_fmt_sdr_out))
+-                      break;
+               return ops->vidioc_g_fmt_sdr_out(file, fh, arg);
+       case V4L2_BUF_TYPE_META_CAPTURE:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_meta_cap))
+-                      break;
+               return ops->vidioc_g_fmt_meta_cap(file, fh, arg);
+       }
+       return -EINVAL;
+@@ -1484,12 +1457,10 @@ static int v4l_s_fmt(const struct v4l2_i
+ {
+       struct v4l2_format *p = arg;
+       struct video_device *vfd = video_devdata(file);
+-      bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+-      bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+-      bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
+-      bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
+-      bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
+-      int ret;
++      int ret = check_fmt(file, p->type);
++
++      if (ret)
++              return ret;
+       ret = v4l_enable_media_source(vfd);
+       if (ret)
+@@ -1498,37 +1469,37 @@ static int v4l_s_fmt(const struct v4l2_i
+       switch (p->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-              if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_s_fmt_vid_cap))
++              if (unlikely(!ops->vidioc_s_fmt_vid_cap))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.pix);
+               ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg);
+               /* just in case the driver zeroed it again */
+               p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+-              if (is_tch)
++              if (vfd->vfl_type == VFL_TYPE_TOUCH)
+                       v4l_pix_format_touch(&p->fmt.pix);
+               return ret;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap_mplane))
++              if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+               return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_overlay))
++              if (unlikely(!ops->vidioc_s_fmt_vid_overlay))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.win);
+               return ops->vidioc_s_fmt_vid_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+-              if (unlikely(!is_rx || is_vid || !ops->vidioc_s_fmt_vbi_cap))
++              if (unlikely(!ops->vidioc_s_fmt_vbi_cap))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.vbi);
+               return ops->vidioc_s_fmt_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+-              if (unlikely(!is_rx || is_vid || !ops->vidioc_s_fmt_sliced_vbi_cap))
++              if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.sliced);
+               return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out))
++              if (unlikely(!ops->vidioc_s_fmt_vid_out))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.pix);
+               ret = ops->vidioc_s_fmt_vid_out(file, fh, arg);
+@@ -1536,37 +1507,37 @@ static int v4l_s_fmt(const struct v4l2_i
+               p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+               return ret;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_mplane))
++              if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+               return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_overlay))
++              if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.win);
+               return ops->vidioc_s_fmt_vid_out_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+-              if (unlikely(!is_tx || is_vid || !ops->vidioc_s_fmt_vbi_out))
++              if (unlikely(!ops->vidioc_s_fmt_vbi_out))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.vbi);
+               return ops->vidioc_s_fmt_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+-              if (unlikely(!is_tx || is_vid || !ops->vidioc_s_fmt_sliced_vbi_out))
++              if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.sliced);
+               return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+-              if (unlikely(!is_rx || !is_sdr || !ops->vidioc_s_fmt_sdr_cap))
++              if (unlikely(!ops->vidioc_s_fmt_sdr_cap))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.sdr);
+               return ops->vidioc_s_fmt_sdr_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              if (unlikely(!is_tx || !is_sdr || !ops->vidioc_s_fmt_sdr_out))
++              if (unlikely(!ops->vidioc_s_fmt_sdr_out))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.sdr);
+               return ops->vidioc_s_fmt_sdr_out(file, fh, arg);
+       case V4L2_BUF_TYPE_META_CAPTURE:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_meta_cap))
++              if (unlikely(!ops->vidioc_s_fmt_meta_cap))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.meta);
+               return ops->vidioc_s_fmt_meta_cap(file, fh, arg);
+@@ -1578,19 +1549,16 @@ static int v4l_try_fmt(const struct v4l2
+                               struct file *file, void *fh, void *arg)
+ {
+       struct v4l2_format *p = arg;
+-      struct video_device *vfd = video_devdata(file);
+-      bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+-      bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+-      bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
+-      bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
+-      bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
+-      int ret;
++      int ret = check_fmt(file, p->type);
++
++      if (ret)
++              return ret;
+       v4l_sanitize_format(p);
+       switch (p->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-              if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_try_fmt_vid_cap))
++              if (unlikely(!ops->vidioc_try_fmt_vid_cap))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.pix);
+               ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg);
+@@ -1598,27 +1566,27 @@ static int v4l_try_fmt(const struct v4l2
+               p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+               return ret;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_cap_mplane))
++              if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+               return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_overlay))
++              if (unlikely(!ops->vidioc_try_fmt_vid_overlay))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.win);
+               return ops->vidioc_try_fmt_vid_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+-              if (unlikely(!is_rx || is_vid || !ops->vidioc_try_fmt_vbi_cap))
++              if (unlikely(!ops->vidioc_try_fmt_vbi_cap))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.vbi);
+               return ops->vidioc_try_fmt_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+-              if (unlikely(!is_rx || is_vid || !ops->vidioc_try_fmt_sliced_vbi_cap))
++              if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.sliced);
+               return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out))
++              if (unlikely(!ops->vidioc_try_fmt_vid_out))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.pix);
+               ret = ops->vidioc_try_fmt_vid_out(file, fh, arg);
+@@ -1626,37 +1594,37 @@ static int v4l_try_fmt(const struct v4l2
+               p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+               return ret;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out_mplane))
++              if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+               return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+-              if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out_overlay))
++              if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.win);
+               return ops->vidioc_try_fmt_vid_out_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+-              if (unlikely(!is_tx || is_vid || !ops->vidioc_try_fmt_vbi_out))
++              if (unlikely(!ops->vidioc_try_fmt_vbi_out))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.vbi);
+               return ops->vidioc_try_fmt_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+-              if (unlikely(!is_tx || is_vid || !ops->vidioc_try_fmt_sliced_vbi_out))
++              if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.sliced);
+               return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+-              if (unlikely(!is_rx || !is_sdr || !ops->vidioc_try_fmt_sdr_cap))
++              if (unlikely(!ops->vidioc_try_fmt_sdr_cap))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.sdr);
+               return ops->vidioc_try_fmt_sdr_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              if (unlikely(!is_tx || !is_sdr || !ops->vidioc_try_fmt_sdr_out))
++              if (unlikely(!ops->vidioc_try_fmt_sdr_out))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.sdr);
+               return ops->vidioc_try_fmt_sdr_out(file, fh, arg);
+       case V4L2_BUF_TYPE_META_CAPTURE:
+-              if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_meta_cap))
++              if (unlikely(!ops->vidioc_try_fmt_meta_cap))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.meta);
+               return ops->vidioc_try_fmt_meta_cap(file, fh, arg);
index ea02f0f3ec648f068cd42fa07715eef9cb5a9955..15f5356a3fec198a0a78df56a23743759ad34ad6 100644 (file)
@@ -117,3 +117,16 @@ crypto-mcryptd-pass-through-absence-of-setkey.patch
 crypto-poly1305-remove-setkey-method.patch
 crypto-hash-annotate-algorithms-taking-optional-key.patch
 crypto-hash-prevent-using-keyed-hashes-without-setting-key.patch
+media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch
+media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.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-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-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch