From: Greg Kroah-Hartman Date: Thu, 15 Feb 2018 07:43:00 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v4.15.4~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=de5166a2d2ac67701df71ae4337de4923c77aa79;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch media-v4l2-compat-ioctl32.c-fix-the-indentation.patch media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch --- diff --git a/queue-4.9/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch b/queue-4.9/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch new file mode 100644 index 00000000000..727911af4d3 --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch @@ -0,0 +1,56 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:26 +0100 +Subject: media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Daniel Mentz , Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-10-hverkuil@xs4all.nl> + +From: Daniel Mentz + +commit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream. + +Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output +overlays.") added the field global_alpha to struct v4l2_window but did +not update the compat layer accordingly. This change adds global_alpha +to struct v4l2_window32 and copies the value for global_alpha back and +forth. + +Signed-off-by: Daniel Mentz +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -45,6 +45,7 @@ struct v4l2_window32 { + compat_caddr_t clips; /* actually struct v4l2_clip32 * */ + __u32 clipcount; + compat_caddr_t bitmap; ++ __u8 global_alpha; + }; + + static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +@@ -53,7 +54,8 @@ static int get_v4l2_window32(struct v4l2 + copy_from_user(&kp->w, &up->w, sizeof(up->w)) || + get_user(kp->field, &up->field) || + get_user(kp->chromakey, &up->chromakey) || +- get_user(kp->clipcount, &up->clipcount)) ++ get_user(kp->clipcount, &up->clipcount) || ++ get_user(kp->global_alpha, &up->global_alpha)) + return -EFAULT; + if (kp->clipcount > 2048) + return -EINVAL; +@@ -86,7 +88,8 @@ static int put_v4l2_window32(struct v4l2 + if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || + put_user(kp->field, &up->field) || + put_user(kp->chromakey, &up->chromakey) || +- put_user(kp->clipcount, &up->clipcount)) ++ put_user(kp->clipcount, &up->clipcount) || ++ put_user(kp->global_alpha, &up->global_alpha)) + return -EFAULT; + return 0; + } diff --git a/queue-4.9/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch new file mode 100644 index 00000000000..c4adbad2d79 --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch @@ -0,0 +1,33 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:19 +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 , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-3-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit 3ee6d040719ae09110e5cdf24d5386abe5d1b776 upstream. + +The result of the VIDIOC_PREPARE_BUF ioctl was never copied back +to userspace since it was missing in the switch. + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -1022,6 +1022,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.9/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch new file mode 100644 index 00000000000..53756ccb384 --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch @@ -0,0 +1,321 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:22 +0100 +Subject: media: v4l2-compat-ioctl32.c: avoid sizeof(type) +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-6-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit 333b1e9f96ce05f7498b581509bb30cde03018bf upstream. + +Instead of doing sizeof(struct foo) use sizeof(*up). There even were +cases where 4 * sizeof(__u32) was used instead of sizeof(kp->reserved), +which is very dangerous when the size of the reserved array changes. + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 77 ++++++++++++-------------- + 1 file changed, 36 insertions(+), 41 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -47,7 +47,7 @@ struct v4l2_window32 { + + static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) + { +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + copy_from_user(&kp->w, &up->w, sizeof(up->w)) || + get_user(kp->field, &up->field) || + get_user(kp->chromakey, &up->chromakey) || +@@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2 + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); +- kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); ++ kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (--n >= 0) { + if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) +@@ -157,14 +157,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); +@@ -208,14 +208,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; +@@ -234,7 +234,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; +@@ -242,13 +242,13 @@ static int get_v4l2_standard32(struct v4 + + static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) + { +- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + put_user(kp->index, &up->index) || + 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; + } +@@ -296,7 +296,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) { +@@ -306,11 +306,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; + } + +@@ -322,19 +322,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; +@@ -348,7 +348,7 @@ static int get_v4l2_buffer32(struct v4l2 + int num_planes; + int ret; + +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(kp->index, &up->index) || + get_user(kp->type, &up->type) || + get_user(kp->flags, &up->flags) || +@@ -360,8 +360,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)) { +@@ -378,13 +377,12 @@ static int get_v4l2_buffer32(struct v4l2 + + uplane32 = compat_ptr(p); + if (!access_ok(VERIFY_READ, uplane32, +- num_planes * sizeof(struct v4l2_plane32))) ++ num_planes * sizeof(*uplane32))) + return -EFAULT; + + /* We don't really care if userspace decides to kill itself + * by passing a very big num_planes value */ +- uplane = compat_alloc_user_space(num_planes * +- sizeof(struct v4l2_plane)); ++ uplane = compat_alloc_user_space(num_planes * sizeof(*uplane)); + kp->m.planes = (__force struct v4l2_plane *)uplane; + + while (--num_planes >= 0) { +@@ -432,7 +430,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) || +@@ -443,7 +441,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) || +@@ -511,7 +509,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) || +@@ -525,7 +523,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) || +@@ -549,14 +547,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; + } +@@ -604,12 +602,11 @@ static int get_v4l2_ext_controls32(struc + int n; + compat_caddr_t p; + +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(kp->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; + n = kp->count; + if (n == 0) { +@@ -619,10 +616,9 @@ static int get_v4l2_ext_controls32(struc + if (get_user(p, &up->controls)) + return -EFAULT; + ucontrols = compat_ptr(p); +- if (!access_ok(VERIFY_READ, ucontrols, +- n * sizeof(struct v4l2_ext_control32))) ++ if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols))) + return -EFAULT; +- kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); ++ kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols)); + kp->controls = (__force struct v4l2_ext_control *)kcontrols; + while (--n >= 0) { + u32 id; +@@ -654,7 +650,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) || +@@ -666,8 +662,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) { +@@ -704,7 +699,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) || +@@ -712,7 +707,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; + } +@@ -729,7 +724,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) || +@@ -744,7 +739,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.9/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch new file mode 100644 index 00000000000..dc1eb7df57e --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch @@ -0,0 +1,111 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:27 +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 , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-11-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit a751be5b142ef6bcbbb96d9899516f4d9c8d0ef4 upstream. + +put_v4l2_window32() didn't copy back the clip list to userspace. +Drivers can update the clip rectangles, so this should be done. + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 +++++++++++++++++--------- + 1 file changed, 40 insertions(+), 19 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -50,6 +50,11 @@ struct v4l2_window32 { + + static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) + { ++ struct v4l2_clip32 __user *uclips; ++ struct v4l2_clip __user *kclips; ++ compat_caddr_t p; ++ u32 n; ++ + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + copy_from_user(&kp->w, &up->w, sizeof(up->w)) || + get_user(kp->field, &up->field) || +@@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2 + return -EFAULT; + if (kp->clipcount > 2048) + return -EINVAL; +- if (kp->clipcount) { +- struct v4l2_clip32 __user *uclips; +- struct v4l2_clip __user *kclips; +- int n = kp->clipcount; +- compat_caddr_t p; ++ if (!kp->clipcount) { ++ kp->clips = NULL; ++ return 0; ++ } + +- if (get_user(p, &up->clips)) ++ n = kp->clipcount; ++ if (get_user(p, &up->clips)) ++ return -EFAULT; ++ uclips = compat_ptr(p); ++ kclips = compat_alloc_user_space(n * sizeof(*kclips)); ++ kp->clips = kclips; ++ while (n--) { ++ if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) + return -EFAULT; +- uclips = compat_ptr(p); +- kclips = compat_alloc_user_space(n * sizeof(*kclips)); +- kp->clips = kclips; +- while (--n >= 0) { +- if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) +- return -EFAULT; +- if (put_user(n ? kclips + 1 : NULL, &kclips->next)) +- return -EFAULT; +- uclips += 1; +- kclips += 1; +- } +- } else +- kp->clips = NULL; ++ if (put_user(n ? kclips + 1 : NULL, &kclips->next)) ++ return -EFAULT; ++ uclips++; ++ kclips++; ++ } + return 0; + } + + static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) + { ++ struct v4l2_clip __user *kclips = kp->clips; ++ struct v4l2_clip32 __user *uclips; ++ u32 n = kp->clipcount; ++ compat_caddr_t p; ++ + if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || + put_user(kp->field, &up->field) || + put_user(kp->chromakey, &up->chromakey) || + put_user(kp->clipcount, &up->clipcount) || + put_user(kp->global_alpha, &up->global_alpha)) + return -EFAULT; ++ ++ if (!kp->clipcount) ++ return 0; ++ ++ if (get_user(p, &up->clips)) ++ return -EFAULT; ++ uclips = compat_ptr(p); ++ while (n--) { ++ if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) ++ return -EFAULT; ++ uclips++; ++ kclips++; ++ } + return 0; + } + diff --git a/queue-4.9/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch new file mode 100644 index 00000000000..6ea877326a1 --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch @@ -0,0 +1,132 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:23 +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 , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-7-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit 8ed5a59dcb47a6f76034ee760b36e089f3e82529 upstream. + +The struct v4l2_plane32 should set m.userptr as well. The same +happens in v4l2_buffer32 and v4l2-compliance tests for this. + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 47 +++++++++++++++----------- + 1 file changed, 28 insertions(+), 19 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -299,19 +299,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; +@@ -320,22 +325,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; + } +@@ -395,6 +410,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; +@@ -408,10 +424,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; +@@ -468,6 +480,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; +@@ -475,10 +488,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.9/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch new file mode 100644 index 00000000000..b4a4f8b5e8d --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch @@ -0,0 +1,36 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:29 +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 , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-13-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit d83a8243aaefe62ace433e4384a4f077bed86acb upstream. + +Some ioctls need to copy back the result even if the ioctl returned +an error. However, don't do this for the error code -ENOTTY. +It makes no sense in that cases. + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -956,6 +956,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.9/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch new file mode 100644 index 00000000000..3a6d5a29c32 --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch @@ -0,0 +1,44 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:28 +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 , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-12-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit 169f24ca68bf0f247d111aef07af00dd3a02ae88 upstream. + +There is nothing wrong with using an unknown buffer type. So +stop spamming the kernel log whenever this happens. The kernel +will just return -EINVAL to signal this. + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -175,8 +175,6 @@ static int __get_v4l2_format32(struct v4 + return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr, + sizeof(kp->fmt.sdr)) ? -EFAULT : 0; + default: +- pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", +- kp->type); + return -EINVAL; + } + } +@@ -226,8 +224,6 @@ static int __put_v4l2_format32(struct v4 + return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr, + sizeof(kp->fmt.sdr)) ? -EFAULT : 0; + default: +- pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", +- kp->type); + return -EINVAL; + } + } diff --git a/queue-4.9/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch new file mode 100644 index 00000000000..302dd0af180 --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch @@ -0,0 +1,144 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:24 +0100 +Subject: media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-8-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit b8c601e8af2d08f733d74defa8465303391bb930 upstream. + +ctrl_is_pointer just hardcoded two known string controls, but that +caused problems when using e.g. custom controls that use a pointer +for the payload. + +Reimplement this function: it now finds the v4l2_ctrl (if the driver +uses the control framework) or it calls vidioc_query_ext_ctrl (if the +driver implements that directly). + +In both cases it can now check if the control is a pointer control +or not. + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 +++++++++++++++++--------- + 1 file changed, 39 insertions(+), 20 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -18,6 +18,8 @@ + #include + #include + #include ++#include ++#include + #include + + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +@@ -587,24 +589,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; +@@ -636,7 +653,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)) +@@ -651,7 +668,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 = +@@ -683,7 +702,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; +@@ -897,7 +916,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: +@@ -924,7 +943,7 @@ static long do_video_ioctl(struct file * + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: +- if (put_v4l2_ext_controls32(&karg.v2ecs, up)) ++ if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) + err = -EFAULT; + break; + } diff --git a/queue-4.9/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch new file mode 100644 index 00000000000..0845b033eed --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch @@ -0,0 +1,430 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:20 +0100 +Subject: media: v4l2-compat-ioctl32.c: fix the indentation +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-4-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit b7b957d429f601d6d1942122b339474f31191d75 upstream. + +The indentation of this source is all over the place. Fix this. +This patch only changes whitespace. + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 208 +++++++++++++------------- + 1 file changed, 104 insertions(+), 104 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -48,11 +48,11 @@ struct v4l2_window32 { + static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) + { + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || +- copy_from_user(&kp->w, &up->w, sizeof(up->w)) || +- get_user(kp->field, &up->field) || +- get_user(kp->chromakey, &up->chromakey) || +- get_user(kp->clipcount, &up->clipcount)) +- return -EFAULT; ++ copy_from_user(&kp->w, &up->w, sizeof(up->w)) || ++ get_user(kp->field, &up->field) || ++ get_user(kp->chromakey, &up->chromakey) || ++ get_user(kp->clipcount, &up->clipcount)) ++ return -EFAULT; + if (kp->clipcount > 2048) + return -EINVAL; + if (kp->clipcount) { +@@ -82,10 +82,10 @@ static int get_v4l2_window32(struct v4l2 + static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) + { + if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || +- put_user(kp->field, &up->field) || +- put_user(kp->chromakey, &up->chromakey) || +- put_user(kp->clipcount, &up->clipcount)) +- return -EFAULT; ++ put_user(kp->field, &up->field) || ++ put_user(kp->chromakey, &up->chromakey) || ++ put_user(kp->clipcount, &up->clipcount)) ++ return -EFAULT; + return 0; + } + +@@ -97,7 +97,7 @@ static inline int get_v4l2_pix_format(st + } + + static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, +- struct v4l2_pix_format_mplane __user *up) ++ struct v4l2_pix_format_mplane __user *up) + { + if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) + return -EFAULT; +@@ -112,7 +112,7 @@ static inline int put_v4l2_pix_format(st + } + + static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, +- struct v4l2_pix_format_mplane __user *up) ++ struct v4l2_pix_format_mplane __user *up) + { + if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) + return -EFAULT; +@@ -218,7 +218,7 @@ static int __get_v4l2_format32(struct v4 + return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); + default: + pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", +- kp->type); ++ kp->type); + return -EINVAL; + } + } +@@ -265,7 +265,7 @@ static int __put_v4l2_format32(struct v4 + return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); + default: + pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", +- kp->type); ++ kp->type); + return -EINVAL; + } + } +@@ -299,7 +299,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; + } +@@ -307,13 +307,13 @@ static int get_v4l2_standard32(struct v4 + static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) + { + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || +- put_user(kp->index, &up->index) || +- 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; + } + +@@ -353,14 +353,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) { +@@ -374,7 +374,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; + } + +@@ -382,23 +382,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; +@@ -413,19 +413,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)) { +@@ -442,13 +442,13 @@ static int get_v4l2_buffer32(struct v4l2 + + uplane32 = compat_ptr(p); + if (!access_ok(VERIFY_READ, uplane32, +- num_planes * sizeof(struct v4l2_plane32))) ++ num_planes * sizeof(struct v4l2_plane32))) + return -EFAULT; + + /* We don't really care if userspace decides to kill itself + * by passing a very big num_planes value */ + uplane = compat_alloc_user_space(num_planes * +- sizeof(struct v4l2_plane)); ++ sizeof(struct v4l2_plane)); + kp->m.planes = (__force struct v4l2_plane *)uplane; + + while (--num_planes >= 0) { +@@ -466,12 +466,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: +@@ -497,22 +497,22 @@ static int put_v4l2_buffer32(struct v4l2 + int ret; + + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || +- put_user(kp->index, &up->index) || +- put_user(kp->type, &up->type) || +- put_user(kp->flags, &up->flags) || +- put_user(kp->memory, &up->memory)) +- return -EFAULT; ++ put_user(kp->index, &up->index) || ++ put_user(kp->type, &up->type) || ++ put_user(kp->flags, &up->flags) || ++ put_user(kp->memory, &up->memory)) ++ return -EFAULT; + + if (put_user(kp->bytesused, &up->bytesused) || +- put_user(kp->field, &up->field) || +- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || +- put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || +- copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || +- put_user(kp->sequence, &up->sequence) || +- put_user(kp->reserved2, &up->reserved2) || +- put_user(kp->reserved, &up->reserved) || +- put_user(kp->length, &up->length)) +- return -EFAULT; ++ put_user(kp->field, &up->field) || ++ put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || ++ put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || ++ copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || ++ put_user(kp->sequence, &up->sequence) || ++ put_user(kp->reserved2, &up->reserved2) || ++ put_user(kp->reserved, &up->reserved) || ++ put_user(kp->length, &up->length)) ++ return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { + num_planes = kp->length; +@@ -576,11 +576,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; + } +@@ -590,11 +590,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; + } + +@@ -669,12 +669,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; + n = kp->count; + if (n == 0) { + kp->controls = NULL; +@@ -684,7 +684,7 @@ static int get_v4l2_ext_controls32(struc + return -EFAULT; + ucontrols = compat_ptr(p); + if (!access_ok(VERIFY_READ, ucontrols, +- n * sizeof(struct v4l2_ext_control32))) ++ n * sizeof(struct v4l2_ext_control32))) + return -EFAULT; + kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); + kp->controls = (__force struct v4l2_ext_control *)kcontrols; +@@ -719,11 +719,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; + +@@ -731,7 +731,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) { +@@ -769,15 +769,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; + } + +@@ -794,12 +794,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; + } +@@ -809,12 +809,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.9/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch new file mode 100644 index 00000000000..a9f8fe0523e --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch @@ -0,0 +1,43 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:25 +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 , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-9-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit 273caa260035c03d89ad63d72d8cd3d9e5c5e3f1 upstream. + +If the device is of type VFL_TYPE_SUBDEV then vdev->ioctl_ops +is NULL so the 'if (!ops->vidioc_query_ext_ctrl)' check would crash. +Add a test for !ops to the condition. + +All sub-devices that have controls will use the control framework, +so they do not have an equivalent to ops->vidioc_query_ext_ctrl. +Returning false if ops is NULL is the correct thing to do here. + +Fixes: b8c601e8af ("v4l2-compat-ioctl32.c: fix ctrl_is_pointer") + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Reported-by: Laurent Pinchart +Reviewed-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -612,7 +612,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.9/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch new file mode 100644 index 00000000000..c7a8222a0cc --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch @@ -0,0 +1,172 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:21 +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 , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-5-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit 486c521510c44a04cd756a9267e7d1e271c8a4ba upstream. + +These helper functions do not really help. Move the code to the +__get/put_v4l2_format32 functions. + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 104 +++++--------------------- + 1 file changed, 20 insertions(+), 84 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -89,78 +89,6 @@ static int put_v4l2_window32(struct v4l2 + return 0; + } + +-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) +-{ +- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, +- struct v4l2_pix_format_mplane __user *up) +-{ +- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) +- return -EFAULT; +- return 0; +-} +- +-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) +-{ +- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, +- struct v4l2_pix_format_mplane __user *up) +-{ +- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) +- return -EFAULT; +- return 0; +-} +- +-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) +-{ +- if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) +-{ +- if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) +-{ +- if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) +-{ +- if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) +- return -EFAULT; +- return 0; +-} +- +-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; +-} +- + struct v4l2_format32 { + __u32 type; /* enum v4l2_buf_type */ + union { +@@ -199,23 +127,27 @@ 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; + default: + pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", + kp->type); +@@ -246,23 +178,27 @@ 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; + default: + pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", + kp->type); diff --git a/queue-4.9/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch b/queue-4.9/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch new file mode 100644 index 00000000000..ca5b30faf05 --- /dev/null +++ b/queue-4.9/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch @@ -0,0 +1,1323 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:30 +0100 +Subject: media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Daniel Mentz , Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-14-hverkuil@xs4all.nl> + +From: Daniel Mentz + +commit a1dfb4c48cc1e64eeb7800a27c66a6f7e88d075a upstream. + +The 32-bit compat v4l2 ioctl handling is implemented based on its 64-bit +equivalent. It converts 32-bit data structures into its 64-bit +equivalents and needs to provide the data to the 64-bit ioctl in user +space memory which is commonly allocated using +compat_alloc_user_space(). + +However, due to how that function is implemented, it can only be called +a single time for every syscall invocation. + +Supposedly to avoid this limitation, the existing code uses a mix of +memory from the kernel stack and memory allocated through +compat_alloc_user_space(). + +Under normal circumstances, this would not work, because the 64-bit +ioctl expects all pointers to point to user space memory. As a +workaround, set_fs(KERNEL_DS) is called to temporarily disable this +extra safety check and allow kernel pointers. However, this might +introduce a security vulnerability: The result of the 32-bit to 64-bit +conversion is writeable by user space because the output buffer has been +allocated via compat_alloc_user_space(). A malicious user space process +could then manipulate pointers inside this output buffer, and due to the +previous set_fs(KERNEL_DS) call, functions like get_user() or put_user() +no longer prevent kernel memory access. + +The new approach is to pre-calculate the total amount of user space +memory that is needed, allocate it using compat_alloc_user_space() and +then divide up the allocated memory to accommodate all data structures +that need to be converted. + +An alternative approach would have been to retain the union type karg +that they allocated on the kernel stack in do_video_ioctl(), copy all +data from user space into karg and then back to user space. However, we +decided against this approach because it does not align with other +compat syscall implementations. Instead, we tried to replicate the +get_user/put_user pairs as found in other places in the kernel: + + if (get_user(clipcount, &up->clipcount) || + put_user(clipcount, &kp->clipcount)) return -EFAULT; + +Notes from hans.verkuil@cisco.com: + +This patch was taken from: + https://github.com/LineageOS/android_kernel_samsung_apq8084/commit/97b733953c06e4f0398ade18850f0817778255f7 + +Clearly nobody could be bothered to upstream this patch or at minimum +tell us :-( We only heard about this a week ago. + +This patch was rebased and cleaned up. Compared to the original I +also swapped the order of the convert_in_user arguments so that they +matched copy_in_user. It was hard to review otherwise. I also replaced +the ALLOC_USER_SPACE/ALLOC_AND_GET by a normal function. + +Fixes: 6b5a9492ca ("v4l: introduce string control support.") + +Signed-off-by: Daniel Mentz +Co-developed-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 752 ++++++++++++++++---------- + 1 file changed, 487 insertions(+), 265 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -22,6 +22,14 @@ + #include + #include + ++/* Use the same argument order as copy_in_user */ ++#define assign_in_user(to, from) \ ++({ \ ++ typeof(*from) __assign_tmp; \ ++ \ ++ get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \ ++}) ++ + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + { + long ret = -ENOIOCTLCMD; +@@ -35,12 +43,12 @@ static long native_ioctl(struct file *fi + + struct v4l2_clip32 { + struct v4l2_rect c; +- compat_caddr_t next; ++ compat_caddr_t next; + }; + + struct v4l2_window32 { + struct v4l2_rect w; +- __u32 field; /* enum v4l2_field */ ++ __u32 field; /* enum v4l2_field */ + __u32 chromakey; + compat_caddr_t clips; /* actually struct v4l2_clip32 * */ + __u32 clipcount; +@@ -48,37 +56,41 @@ struct v4l2_window32 { + __u8 global_alpha; + }; + +-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) ++static int get_v4l2_window32(struct v4l2_window __user *kp, ++ struct v4l2_window32 __user *up, ++ void __user *aux_buf, u32 aux_space) + { + struct v4l2_clip32 __user *uclips; + struct v4l2_clip __user *kclips; + compat_caddr_t p; +- u32 n; ++ u32 clipcount; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || +- copy_from_user(&kp->w, &up->w, sizeof(up->w)) || +- get_user(kp->field, &up->field) || +- get_user(kp->chromakey, &up->chromakey) || +- get_user(kp->clipcount, &up->clipcount) || +- get_user(kp->global_alpha, &up->global_alpha)) ++ copy_in_user(&kp->w, &up->w, sizeof(up->w)) || ++ assign_in_user(&kp->field, &up->field) || ++ assign_in_user(&kp->chromakey, &up->chromakey) || ++ assign_in_user(&kp->global_alpha, &up->global_alpha) || ++ get_user(clipcount, &up->clipcount) || ++ put_user(clipcount, &kp->clipcount)) + return -EFAULT; +- if (kp->clipcount > 2048) ++ if (clipcount > 2048) + return -EINVAL; +- if (!kp->clipcount) { +- kp->clips = NULL; +- return 0; +- } ++ if (!clipcount) ++ return put_user(NULL, &kp->clips); + +- n = kp->clipcount; + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); +- kclips = compat_alloc_user_space(n * sizeof(*kclips)); +- kp->clips = kclips; +- while (n--) { ++ if (aux_space < clipcount * sizeof(*kclips)) ++ return -EFAULT; ++ kclips = aux_buf; ++ if (put_user(kclips, &kp->clips)) ++ return -EFAULT; ++ ++ while (clipcount--) { + if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) + return -EFAULT; +- if (put_user(n ? kclips + 1 : NULL, &kclips->next)) ++ if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next)) + return -EFAULT; + uclips++; + kclips++; +@@ -86,27 +98,28 @@ static int get_v4l2_window32(struct v4l2 + return 0; + } + +-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) ++static int put_v4l2_window32(struct v4l2_window __user *kp, ++ struct v4l2_window32 __user *up) + { + struct v4l2_clip __user *kclips = kp->clips; + struct v4l2_clip32 __user *uclips; +- u32 n = kp->clipcount; + compat_caddr_t p; ++ u32 clipcount; + +- if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || +- put_user(kp->field, &up->field) || +- put_user(kp->chromakey, &up->chromakey) || +- put_user(kp->clipcount, &up->clipcount) || +- put_user(kp->global_alpha, &up->global_alpha)) ++ if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) || ++ assign_in_user(&up->field, &kp->field) || ++ assign_in_user(&up->chromakey, &kp->chromakey) || ++ assign_in_user(&up->global_alpha, &kp->global_alpha) || ++ get_user(clipcount, &kp->clipcount) || ++ put_user(clipcount, &up->clipcount)) + return -EFAULT; +- +- if (!kp->clipcount) ++ if (!clipcount) + return 0; + + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); +- while (n--) { ++ while (clipcount--) { + if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) + return -EFAULT; + uclips++; +@@ -145,101 +158,158 @@ struct v4l2_create_buffers32 { + __u32 reserved[8]; + }; + +-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) ++static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) ++{ ++ u32 type; ++ ++ if (get_user(type, &up->type)) ++ return -EFAULT; ++ ++ switch (type) { ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { ++ u32 clipcount; ++ ++ if (get_user(clipcount, &up->fmt.win.clipcount)) ++ return -EFAULT; ++ if (clipcount > 2048) ++ return -EINVAL; ++ *size = clipcount * sizeof(struct v4l2_clip); ++ return 0; ++ } ++ default: ++ *size = 0; ++ return 0; ++ } ++} ++ ++static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) + { +- if (get_user(kp->type, &up->type)) ++ if (!access_ok(VERIFY_READ, up, sizeof(*up))) + return -EFAULT; ++ return __bufsize_v4l2_format(up, size); ++} + +- switch (kp->type) { ++static int __get_v4l2_format32(struct v4l2_format __user *kp, ++ struct v4l2_format32 __user *up, ++ void __user *aux_buf, u32 aux_space) ++{ ++ u32 type; ++ ++ if (get_user(type, &up->type) || put_user(type, &kp->type)) ++ return -EFAULT; ++ ++ switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: +- return copy_from_user(&kp->fmt.pix, &up->fmt.pix, +- sizeof(kp->fmt.pix)) ? -EFAULT : 0; ++ return copy_in_user(&kp->fmt.pix, &up->fmt.pix, ++ sizeof(kp->fmt.pix)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: +- return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, +- sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; ++ return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, ++ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: +- return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); ++ return get_v4l2_window32(&kp->fmt.win, &up->fmt.win, ++ aux_buf, aux_space); + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: +- return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi, +- sizeof(kp->fmt.vbi)) ? -EFAULT : 0; ++ return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi, ++ sizeof(kp->fmt.vbi)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: +- return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, +- sizeof(kp->fmt.sliced)) ? -EFAULT : 0; ++ return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced, ++ sizeof(kp->fmt.sliced)) ? -EFAULT : 0; + 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; + 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, aux_buf, aux_space); ++} ++ ++static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up, ++ u32 *size) + { + if (!access_ok(VERIFY_READ, up, sizeof(*up))) + return -EFAULT; +- return __get_v4l2_format32(kp, up); ++ return __bufsize_v4l2_format(&up->format, size); + } + +-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) ++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; + 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); + } +@@ -253,24 +323,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; + } +@@ -310,11 +383,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, +@@ -329,10 +402,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: +@@ -344,7 +415,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; +@@ -368,8 +440,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; + } +@@ -377,37 +448,75 @@ static int put_v4l2_plane32(struct v4l2_ + return 0; + } + +-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) ++static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size) + { ++ u32 type; ++ u32 length; ++ ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || ++ get_user(type, &up->type) || ++ get_user(length, &up->length)) ++ return -EFAULT; ++ ++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) { ++ if (length > VIDEO_MAX_PLANES) ++ return -EINVAL; ++ ++ /* ++ * We don't really care if userspace decides to kill itself ++ * by passing a very big length value ++ */ ++ *size = length * sizeof(struct v4l2_plane); ++ } else { ++ *size = 0; ++ } ++ return 0; ++} ++ ++static int get_v4l2_buffer32(struct v4l2_buffer __user *kp, ++ struct v4l2_buffer32 __user *up, ++ void __user *aux_buf, u32 aux_space) ++{ ++ u32 type; ++ u32 length; ++ enum v4l2_memory memory; + struct v4l2_plane32 __user *uplane32; + struct v4l2_plane __user *uplane; + compat_caddr_t p; +- int num_planes; + int ret; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || +- get_user(kp->index, &up->index) || +- get_user(kp->type, &up->type) || +- get_user(kp->flags, &up->flags) || +- get_user(kp->memory, &up->memory) || +- get_user(kp->length, &up->length)) +- return -EFAULT; +- +- if (V4L2_TYPE_IS_OUTPUT(kp->type)) +- if (get_user(kp->bytesused, &up->bytesused) || +- get_user(kp->field, &up->field) || +- get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || +- get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec)) ++ assign_in_user(&kp->index, &up->index) || ++ get_user(type, &up->type) || ++ put_user(type, &kp->type) || ++ assign_in_user(&kp->flags, &up->flags) || ++ get_user(memory, &up->memory) || ++ put_user(memory, &kp->memory) || ++ get_user(length, &up->length) || ++ put_user(length, &kp->length)) ++ return -EFAULT; ++ ++ if (V4L2_TYPE_IS_OUTPUT(type)) ++ if (assign_in_user(&kp->bytesused, &up->bytesused) || ++ assign_in_user(&kp->field, &up->field) || ++ assign_in_user(&kp->timestamp.tv_sec, ++ &up->timestamp.tv_sec) || ++ assign_in_user(&kp->timestamp.tv_usec, ++ &up->timestamp.tv_usec)) + return -EFAULT; + +- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { +- num_planes = kp->length; ++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) { ++ u32 num_planes = length; ++ + if (num_planes == 0) { +- kp->m.planes = NULL; +- /* num_planes == 0 is legal, e.g. when userspace doesn't +- * need planes array on DQBUF*/ +- return 0; ++ /* ++ * num_planes == 0 is legal, e.g. when userspace doesn't ++ * need planes array on DQBUF ++ */ ++ return put_user(NULL, &kp->m.planes); + } ++ if (num_planes > VIDEO_MAX_PLANES) ++ return -EINVAL; + + if (get_user(p, &up->m.planes)) + return -EFAULT; +@@ -417,37 +526,43 @@ static int get_v4l2_buffer32(struct v4l2 + num_planes * sizeof(*uplane32))) + return -EFAULT; + +- /* We don't really care if userspace decides to kill itself +- * by passing a very big num_planes value */ +- uplane = compat_alloc_user_space(num_planes * sizeof(*uplane)); +- kp->m.planes = (__force struct v4l2_plane *)uplane; ++ /* ++ * We don't really care if userspace decides to kill itself ++ * by passing a very big num_planes value ++ */ ++ if (aux_space < num_planes * sizeof(*uplane)) ++ return -EFAULT; ++ ++ uplane = aux_buf; ++ if (put_user((__force struct v4l2_plane *)uplane, ++ &kp->m.planes)) ++ return -EFAULT; + +- while (--num_planes >= 0) { +- ret = get_v4l2_plane32(uplane, uplane32, kp->memory); ++ while (num_planes--) { ++ ret = get_v4l2_plane32(uplane, uplane32, memory); + if (ret) + return ret; +- ++uplane; +- ++uplane32; ++ uplane++; ++ uplane32++; + } + } else { +- switch (kp->memory) { ++ switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: +- if (get_user(kp->m.offset, &up->m.offset)) ++ if (assign_in_user(&kp->m.offset, &up->m.offset)) + return -EFAULT; + break; +- case V4L2_MEMORY_USERPTR: +- { +- compat_long_t tmp; +- +- if (get_user(tmp, &up->m.userptr)) +- return -EFAULT; ++ case V4L2_MEMORY_USERPTR: { ++ compat_ulong_t userptr; + +- 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; + } +@@ -456,62 +571,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; + } +@@ -523,7 +646,7 @@ static int put_v4l2_buffer32(struct v4l2 + struct v4l2_framebuffer32 { + __u32 capability; + __u32 flags; +- compat_caddr_t base; ++ compat_caddr_t base; + struct { + __u32 width; + __u32 height; +@@ -536,29 +659,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; + } +@@ -571,21 +697,26 @@ struct v4l2_input32 { + __u32 tuner; /* Associated tuner */ + compat_u64 std; + __u32 status; +- __u32 reserved[4]; ++ __u32 capabilities; ++ __u32 reserved[3]; + }; + +-/* The 64-bit v4l2_input struct has extra padding at the end of the struct. +- Otherwise it is identical to the 32-bit version. */ +-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) ++/* ++ * The 64-bit v4l2_input struct has extra padding at the end of the struct. ++ * Otherwise it is identical to the 32-bit version. ++ */ ++static inline int get_v4l2_input32(struct v4l2_input __user *kp, ++ struct v4l2_input32 __user *up) + { +- if (copy_from_user(kp, up, sizeof(*up))) ++ if (copy_in_user(kp, up, sizeof(*up))) + return -EFAULT; + return 0; + } + +-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) ++static inline int put_v4l2_input32(struct v4l2_input __user *kp, ++ struct v4l2_input32 __user *up) + { +- if (copy_to_user(up, kp, sizeof(*up))) ++ if (copy_in_user(up, kp, sizeof(*up))) + return -EFAULT; + return 0; + } +@@ -639,40 +770,64 @@ static inline bool ctrl_is_pointer(struc + (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); + } + ++static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up, ++ u32 *size) ++{ ++ u32 count; ++ ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || ++ get_user(count, &up->count)) ++ return -EFAULT; ++ if (count > V4L2_CID_MAX_CTRLS) ++ return -EINVAL; ++ *size = count * sizeof(struct v4l2_ext_control); ++ return 0; ++} ++ + static int get_v4l2_ext_controls32(struct file *file, +- struct v4l2_ext_controls *kp, +- struct v4l2_ext_controls32 __user *up) ++ struct v4l2_ext_controls __user *kp, ++ struct v4l2_ext_controls32 __user *up, ++ void __user *aux_buf, u32 aux_space) + { + struct v4l2_ext_control32 __user *ucontrols; + struct v4l2_ext_control __user *kcontrols; +- int n; ++ u32 count; ++ u32 n; + compat_caddr_t p; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || +- get_user(kp->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; +- n = kp->count; +- if (n == 0) { +- kp->controls = NULL; +- return 0; +- } ++ 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 (count == 0) ++ return put_user(NULL, &kp->controls); ++ if (count > V4L2_CID_MAX_CTRLS) ++ return -EINVAL; + if (get_user(p, &up->controls)) + return -EFAULT; + ucontrols = compat_ptr(p); +- if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols))) ++ if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols))) ++ return -EFAULT; ++ if (aux_space < count * sizeof(*kcontrols)) + return -EFAULT; +- kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols)); +- kp->controls = (__force struct v4l2_ext_control *)kcontrols; +- while (--n >= 0) { ++ kcontrols = aux_buf; ++ if (put_user((__force struct v4l2_ext_control *)kcontrols, ++ &kp->controls)) ++ return -EFAULT; ++ ++ for (n = 0; n < count; n++) { + u32 id; + + if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) + return -EFAULT; ++ + if (get_user(id, &kcontrols->id)) + return -EFAULT; ++ + if (ctrl_is_pointer(file, id)) { + void __user *s; + +@@ -689,43 +844,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++; + } +@@ -745,17 +911,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; + } +@@ -768,31 +935,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; + } +@@ -809,7 +979,7 @@ static int put_v4l2_edid32(struct v4l2_e + #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) + #define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32) + #define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32) +-#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) ++#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) + #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) + #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) + #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) +@@ -825,22 +995,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; + +@@ -879,30 +1050,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; + +@@ -910,36 +1103,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; + } +@@ -948,25 +1168,26 @@ static long do_video_ioctl(struct file * + + if (compatible_arg) + err = native_ioctl(file, cmd, (unsigned long)up); +- else { +- mm_segment_t old_fs = get_fs(); +- +- set_fs(KERNEL_DS); +- err = native_ioctl(file, cmd, (unsigned long)&karg); +- set_fs(old_fs); +- } ++ else ++ err = native_ioctl(file, cmd, (unsigned long)up_native); + + if (err == -ENOTTY) + return err; + +- /* Special case: even after an error we need to put the +- results back for these ioctls since the error_idx will +- contain information on which control failed. */ ++ /* ++ * Special case: even after an error we need to put the ++ * results back for these ioctls since the error_idx will ++ * contain information on which control failed. ++ */ + switch (cmd) { + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: +- if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) ++ if (put_v4l2_ext_controls32(file, up_native, up)) ++ err = -EFAULT; ++ break; ++ case VIDIOC_S_EDID: ++ if (put_v4l2_edid32(up_native, up)) + err = -EFAULT; + break; + } +@@ -978,45 +1199,46 @@ static long do_video_ioctl(struct file * + case VIDIOC_S_OUTPUT: + case VIDIOC_G_INPUT: + case VIDIOC_G_OUTPUT: +- err = put_user(((s32)karg.vi), (s32 __user *)up); ++ if (assign_in_user((compat_uint_t __user *)up, ++ ((unsigned int __user *)up_native))) ++ err = -EFAULT; + break; + + case VIDIOC_G_FBUF: +- err = put_v4l2_framebuffer32(&karg.v2fb, up); ++ err = put_v4l2_framebuffer32(up_native, up); + break; + + case VIDIOC_DQEVENT: +- err = put_v4l2_event32(&karg.v2ev, up); ++ err = put_v4l2_event32(up_native, up); + break; + + case VIDIOC_G_EDID: +- case VIDIOC_S_EDID: +- err = put_v4l2_edid32(&karg.v2edid, up); ++ err = put_v4l2_edid32(up_native, up); + break; + + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: +- err = put_v4l2_format32(&karg.v2f, up); ++ err = put_v4l2_format32(up_native, up); + break; + + case VIDIOC_CREATE_BUFS: +- err = put_v4l2_create32(&karg.v2crt, up); ++ err = put_v4l2_create32(up_native, up); + break; + + case VIDIOC_PREPARE_BUF: + case VIDIOC_QUERYBUF: + case VIDIOC_QBUF: + case VIDIOC_DQBUF: +- err = put_v4l2_buffer32(&karg.v2b, up); ++ err = put_v4l2_buffer32(up_native, up); + break; + + case VIDIOC_ENUMSTD: +- err = put_v4l2_standard32(&karg.v2s, up); ++ err = put_v4l2_standard32(up_native, up); + break; + + case VIDIOC_ENUMINPUT: +- err = put_v4l2_input32(&karg.v2i, up); ++ err = put_v4l2_input32(up_native, up); + break; + } + return err; diff --git a/queue-4.9/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch b/queue-4.9/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch new file mode 100644 index 00000000000..d7a6760ce5a --- /dev/null +++ b/queue-4.9/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch @@ -0,0 +1,38 @@ +From foo@baz Thu Feb 15 08:41:28 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:48:18 +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 , Mauro Carvalho Chehab +Message-ID: <20180214114830.27171-2-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -2862,8 +2862,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.9/series b/queue-4.9/series index adc09a5dbad..f7fe0c18286 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -33,3 +33,16 @@ crypto-cryptd-pass-through-absence-of-setkey.patch crypto-mcryptd-pass-through-absence-of-setkey.patch crypto-poly1305-remove-setkey-method.patch nsfs-mark-dentry-with-dcache_rcuaccess.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-make-ctrl_is_pointer-work-for-subdevs.patch +media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch +media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch +media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch +media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch +media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch