From 4a022271ced5a50bb1b3191ba207e05f028c2b44 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 14 Feb 2018 20:56:06 +0100 Subject: [PATCH] 4.14-stable patches added patches: media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch media-v4l2-compat-ioctl32.c-fix-the-indentation.patch media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch --- ...l32.c-add-missing-vidioc_prepare_buf.patch | 33 + ...2-compat-ioctl32.c-avoid-sizeof-type.patch | 324 ++++ ...-copy-clip-list-in-put_v4l2_window32.patch | 111 ++ ...c-copy-m.userptr-in-put_v4l2_plane32.patch | 132 ++ ...y-back-the-result-for-certain-errors.patch | 36 + ...drop-pr_info-for-unknown-buffer-type.patch | 44 + ...compat-ioctl32.c-fix-ctrl_is_pointer.patch | 144 ++ ...compat-ioctl32.c-fix-the-indentation.patch | 429 ++++++ ...ake-ctrl_is_pointer-work-for-subdevs.patch | 43 + ...functions-to-__get-put_v4l2_format32.patch | 194 +++ ...tl32.c-refactor-compat-ioctl32-logic.patch | 1302 +++++++++++++++++ ...on-t-copy-back-the-result-for-enotty.patch | 38 + ...c-use-check_fmt-for-enum-g-s-try_fmt.patch | 394 +++++ queue-4.14/series | 13 + 14 files changed, 3237 insertions(+) create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch create mode 100644 queue-4.14/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch create mode 100644 queue-4.14/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch create mode 100644 queue-4.14/media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch new file mode 100644 index 00000000000..593b7620c18 --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch @@ -0,0 +1,33 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:24 +0100 +Subject: media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-4-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 +@@ -1052,6 +1052,7 @@ static long do_video_ioctl(struct file * + err = put_v4l2_create32(&karg.v2crt, up); + break; + ++ case VIDIOC_PREPARE_BUF: + case VIDIOC_QUERYBUF: + case VIDIOC_QBUF: + case VIDIOC_DQBUF: diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch new file mode 100644 index 00000000000..425ed1f1338 --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch @@ -0,0 +1,324 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:27 +0100 +Subject: media: v4l2-compat-ioctl32.c: avoid sizeof(type) +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-7-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 | 79 +++++++++++--------------- + 1 file changed, 36 insertions(+), 43 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -48,7 +48,7 @@ struct v4l2_window32 { + + static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) + { +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + copy_from_user(&kp->w, &up->w, sizeof(up->w)) || + get_user(kp->field, &up->field) || + get_user(kp->chromakey, &up->chromakey) || +@@ -66,7 +66,7 @@ static int get_v4l2_window32(struct v4l2 + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); +- kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); ++ kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (--n >= 0) { + if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) +@@ -164,14 +164,14 @@ static int __get_v4l2_format32(struct v4 + + static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) + { +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32))) ++ if (!access_ok(VERIFY_READ, up, sizeof(*up))) + return -EFAULT; + return __get_v4l2_format32(kp, up); + } + + static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) + { +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) || ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) + return -EFAULT; + return __get_v4l2_format32(&kp->format, &up->format); +@@ -218,14 +218,14 @@ static int __put_v4l2_format32(struct v4 + + static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) + { +- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32))) ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) + return -EFAULT; + return __put_v4l2_format32(kp, up); + } + + static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) + { +- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + return -EFAULT; +@@ -244,7 +244,7 @@ struct v4l2_standard32 { + static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) + { + /* other fields are not set by the user, nor used by the driver */ +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(kp->index, &up->index)) + return -EFAULT; + return 0; +@@ -252,14 +252,14 @@ static int get_v4l2_standard32(struct v4 + + static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) + { +- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + put_user(kp->index, &up->index) || + put_user(kp->id, &up->id) || +- copy_to_user(up->name, kp->name, 24) || ++ copy_to_user(up->name, kp->name, sizeof(up->name)) || + copy_to_user(&up->frameperiod, &kp->frameperiod, + sizeof(kp->frameperiod)) || + put_user(kp->framelines, &up->framelines) || +- copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) ++ copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + return -EFAULT; + return 0; + } +@@ -307,7 +307,7 @@ static int get_v4l2_plane32(struct v4l2_ + + if (copy_in_user(up, up32, 2 * sizeof(__u32)) || + copy_in_user(&up->data_offset, &up32->data_offset, +- sizeof(__u32))) ++ sizeof(up->data_offset))) + return -EFAULT; + + if (memory == V4L2_MEMORY_USERPTR) { +@@ -317,11 +317,11 @@ static int get_v4l2_plane32(struct v4l2_ + if (put_user((unsigned long)up_pln, &up->m.userptr)) + return -EFAULT; + } else if (memory == V4L2_MEMORY_DMABUF) { +- if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int))) ++ if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd))) + return -EFAULT; + } else { + if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, +- sizeof(__u32))) ++ sizeof(up32->m.mem_offset))) + return -EFAULT; + } + +@@ -333,19 +333,19 @@ static int put_v4l2_plane32(struct v4l2_ + { + if (copy_in_user(up32, up, 2 * sizeof(__u32)) || + copy_in_user(&up32->data_offset, &up->data_offset, +- sizeof(__u32))) ++ sizeof(up->data_offset))) + return -EFAULT; + + /* For MMAP, driver might've set up the offset, so copy it back. + * USERPTR stays the same (was userspace-provided), so no copying. */ + if (memory == V4L2_MEMORY_MMAP) + if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, +- sizeof(__u32))) ++ sizeof(up->m.mem_offset))) + return -EFAULT; + /* For DMABUF, driver might've set up the fd, so copy it back. */ + if (memory == V4L2_MEMORY_DMABUF) + if (copy_in_user(&up32->m.fd, &up->m.fd, +- sizeof(int))) ++ sizeof(up->m.fd))) + return -EFAULT; + + return 0; +@@ -358,7 +358,7 @@ static int get_v4l2_buffer32(struct v4l2 + compat_caddr_t p; + int ret; + +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(kp->index, &up->index) || + get_user(kp->type, &up->type) || + get_user(kp->flags, &up->flags) || +@@ -370,8 +370,7 @@ static int get_v4l2_buffer32(struct v4l2 + if (get_user(kp->bytesused, &up->bytesused) || + get_user(kp->field, &up->field) || + get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || +- get_user(kp->timestamp.tv_usec, +- &up->timestamp.tv_usec)) ++ get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec)) + return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { +@@ -391,13 +390,12 @@ static int get_v4l2_buffer32(struct v4l2 + + uplane32 = compat_ptr(p); + if (!access_ok(VERIFY_READ, uplane32, +- kp->length * sizeof(struct v4l2_plane32))) ++ kp->length * sizeof(*uplane32))) + return -EFAULT; + + /* We don't really care if userspace decides to kill itself + * by passing a very big num_planes value */ +- uplane = compat_alloc_user_space(kp->length * +- sizeof(struct v4l2_plane)); ++ uplane = compat_alloc_user_space(kp->length * sizeof(*uplane)); + kp->m.planes = (__force struct v4l2_plane *)uplane; + + for (num_planes = 0; num_planes < kp->length; num_planes++) { +@@ -445,7 +443,7 @@ static int put_v4l2_buffer32(struct v4l2 + int num_planes; + int ret; + +- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + put_user(kp->index, &up->index) || + put_user(kp->type, &up->type) || + put_user(kp->flags, &up->flags) || +@@ -456,8 +454,7 @@ static int put_v4l2_buffer32(struct v4l2 + put_user(kp->field, &up->field) || + put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || +- copy_to_user(&up->timecode, &kp->timecode, +- sizeof(struct v4l2_timecode)) || ++ copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || + put_user(kp->sequence, &up->sequence) || + put_user(kp->reserved2, &up->reserved2) || + put_user(kp->reserved, &up->reserved) || +@@ -525,7 +522,7 @@ static int get_v4l2_framebuffer32(struct + { + u32 tmp; + +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(tmp, &up->base) || + get_user(kp->capability, &up->capability) || + get_user(kp->flags, &up->flags) || +@@ -539,7 +536,7 @@ static int put_v4l2_framebuffer32(struct + { + u32 tmp = (u32)((unsigned long)kp->base); + +- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + put_user(tmp, &up->base) || + put_user(kp->capability, &up->capability) || + put_user(kp->flags, &up->flags) || +@@ -564,14 +561,14 @@ struct v4l2_input32 { + Otherwise it is identical to the 32-bit version. */ + static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) + { +- if (copy_from_user(kp, up, sizeof(struct v4l2_input32))) ++ if (copy_from_user(kp, up, sizeof(*up))) + return -EFAULT; + return 0; + } + + static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) + { +- if (copy_to_user(up, kp, sizeof(struct v4l2_input32))) ++ if (copy_to_user(up, kp, sizeof(*up))) + return -EFAULT; + return 0; + } +@@ -619,12 +616,11 @@ static int get_v4l2_ext_controls32(struc + unsigned int n; + compat_caddr_t p; + +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(kp->which, &up->which) || + get_user(kp->count, &up->count) || + get_user(kp->error_idx, &up->error_idx) || +- copy_from_user(kp->reserved, up->reserved, +- sizeof(kp->reserved))) ++ copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + return -EFAULT; + if (kp->count == 0) { + kp->controls = NULL; +@@ -635,11 +631,9 @@ static int get_v4l2_ext_controls32(struc + if (get_user(p, &up->controls)) + return -EFAULT; + ucontrols = compat_ptr(p); +- if (!access_ok(VERIFY_READ, ucontrols, +- kp->count * sizeof(struct v4l2_ext_control32))) ++ if (!access_ok(VERIFY_READ, ucontrols, kp->count * sizeof(*ucontrols))) + return -EFAULT; +- kcontrols = compat_alloc_user_space(kp->count * +- sizeof(struct v4l2_ext_control)); ++ kcontrols = compat_alloc_user_space(kp->count * sizeof(*kcontrols)); + kp->controls = (__force struct v4l2_ext_control *)kcontrols; + for (n = 0; n < kp->count; n++) { + u32 id; +@@ -671,7 +665,7 @@ static int put_v4l2_ext_controls32(struc + int n = kp->count; + compat_caddr_t p; + +- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + put_user(kp->which, &up->which) || + put_user(kp->count, &up->count) || + put_user(kp->error_idx, &up->error_idx) || +@@ -683,8 +677,7 @@ static int put_v4l2_ext_controls32(struc + if (get_user(p, &up->controls)) + return -EFAULT; + ucontrols = compat_ptr(p); +- if (!access_ok(VERIFY_WRITE, ucontrols, +- n * sizeof(struct v4l2_ext_control32))) ++ if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols))) + return -EFAULT; + + while (--n >= 0) { +@@ -721,7 +714,7 @@ struct v4l2_event32 { + + static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) + { +- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) || ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + put_user(kp->type, &up->type) || + copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || + put_user(kp->pending, &up->pending) || +@@ -729,7 +722,7 @@ static int put_v4l2_event32(struct v4l2_ + put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || + put_user(kp->id, &up->id) || +- copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) ++ copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + return -EFAULT; + return 0; + } +@@ -746,7 +739,7 @@ static int get_v4l2_edid32(struct v4l2_e + { + u32 tmp; + +- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(kp->pad, &up->pad) || + get_user(kp->start_block, &up->start_block) || + get_user(kp->blocks, &up->blocks) || +@@ -761,7 +754,7 @@ static int put_v4l2_edid32(struct v4l2_e + { + u32 tmp = (u32)((unsigned long)kp->edid); + +- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + put_user(kp->pad, &up->pad) || + put_user(kp->start_block, &up->start_block) || + put_user(kp->blocks, &up->blocks) || diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch new file mode 100644 index 00000000000..b67b782db0e --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch @@ -0,0 +1,111 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:30 +0100 +Subject: media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-10-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.14/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch new file mode 100644 index 00000000000..78486726286 --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch @@ -0,0 +1,132 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:28 +0100 +Subject: media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-8-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 +@@ -310,19 +310,24 @@ static int get_v4l2_plane32(struct v4l2_ + sizeof(up->data_offset))) + return -EFAULT; + +- if (memory == V4L2_MEMORY_USERPTR) { ++ switch (memory) { ++ case V4L2_MEMORY_MMAP: ++ case V4L2_MEMORY_OVERLAY: ++ if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, ++ sizeof(up32->m.mem_offset))) ++ return -EFAULT; ++ break; ++ case V4L2_MEMORY_USERPTR: + if (get_user(p, &up32->m.userptr)) + return -EFAULT; + up_pln = compat_ptr(p); + if (put_user((unsigned long)up_pln, &up->m.userptr)) + return -EFAULT; +- } else if (memory == V4L2_MEMORY_DMABUF) { ++ break; ++ case V4L2_MEMORY_DMABUF: + if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd))) + return -EFAULT; +- } else { +- if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, +- sizeof(up32->m.mem_offset))) +- return -EFAULT; ++ break; + } + + return 0; +@@ -331,22 +336,32 @@ static int get_v4l2_plane32(struct v4l2_ + static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, + enum v4l2_memory memory) + { ++ unsigned long p; ++ + if (copy_in_user(up32, up, 2 * sizeof(__u32)) || + copy_in_user(&up32->data_offset, &up->data_offset, + sizeof(up->data_offset))) + return -EFAULT; + +- /* For MMAP, driver might've set up the offset, so copy it back. +- * USERPTR stays the same (was userspace-provided), so no copying. */ +- if (memory == V4L2_MEMORY_MMAP) ++ switch (memory) { ++ case V4L2_MEMORY_MMAP: ++ case V4L2_MEMORY_OVERLAY: + if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, + sizeof(up->m.mem_offset))) + return -EFAULT; +- /* For DMABUF, driver might've set up the fd, so copy it back. */ +- if (memory == V4L2_MEMORY_DMABUF) ++ break; ++ case V4L2_MEMORY_USERPTR: ++ if (get_user(p, &up->m.userptr) || ++ put_user((compat_ulong_t)ptr_to_compat((__force void *)p), ++ &up32->m.userptr)) ++ return -EFAULT; ++ break; ++ case V4L2_MEMORY_DMABUF: + if (copy_in_user(&up32->m.fd, &up->m.fd, + sizeof(up->m.fd))) + return -EFAULT; ++ break; ++ } + + return 0; + } +@@ -408,6 +423,7 @@ static int get_v4l2_buffer32(struct v4l2 + } else { + switch (kp->memory) { + case V4L2_MEMORY_MMAP: ++ case V4L2_MEMORY_OVERLAY: + if (get_user(kp->m.offset, &up->m.offset)) + return -EFAULT; + break; +@@ -421,10 +437,6 @@ static int get_v4l2_buffer32(struct v4l2 + kp->m.userptr = (unsigned long)compat_ptr(tmp); + } + break; +- case V4L2_MEMORY_OVERLAY: +- if (get_user(kp->m.offset, &up->m.offset)) +- return -EFAULT; +- break; + case V4L2_MEMORY_DMABUF: + if (get_user(kp->m.fd, &up->m.fd)) + return -EFAULT; +@@ -481,6 +493,7 @@ static int put_v4l2_buffer32(struct v4l2 + } else { + switch (kp->memory) { + case V4L2_MEMORY_MMAP: ++ case V4L2_MEMORY_OVERLAY: + if (put_user(kp->m.offset, &up->m.offset)) + return -EFAULT; + break; +@@ -488,10 +501,6 @@ static int put_v4l2_buffer32(struct v4l2 + if (put_user(kp->m.userptr, &up->m.userptr)) + return -EFAULT; + break; +- case V4L2_MEMORY_OVERLAY: +- if (put_user(kp->m.offset, &up->m.offset)) +- return -EFAULT; +- break; + case V4L2_MEMORY_DMABUF: + if (put_user(kp->m.fd, &up->m.fd)) + return -EFAULT; diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch new file mode 100644 index 00000000000..6ee0201d5e7 --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch @@ -0,0 +1,36 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:32 +0100 +Subject: media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-12-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 +@@ -968,6 +968,9 @@ static long do_video_ioctl(struct file * + set_fs(old_fs); + } + ++ if (err == -ENOTTY) ++ return err; ++ + /* Special case: even after an error we need to put the + results back for these ioctls since the error_idx will + contain information on which control failed. */ diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch new file mode 100644 index 00000000000..23f0252a5ca --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch @@ -0,0 +1,44 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:31 +0100 +Subject: media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-11-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 +@@ -179,8 +179,6 @@ static int __get_v4l2_format32(struct v4 + return copy_from_user(&kp->fmt.meta, &up->fmt.meta, + sizeof(kp->fmt.meta)) ? -EFAULT : 0; + default: +- pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", +- kp->type); + return -EINVAL; + } + } +@@ -233,8 +231,6 @@ static int __put_v4l2_format32(struct v4 + return copy_to_user(&up->fmt.meta, &kp->fmt.meta, + sizeof(kp->fmt.meta)) ? -EFAULT : 0; + default: +- pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", +- kp->type); + return -EINVAL; + } + } diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch new file mode 100644 index 00000000000..831aed662b8 --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch @@ -0,0 +1,144 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:29 +0100 +Subject: media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-9-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) +@@ -601,24 +603,39 @@ struct v4l2_ext_control32 { + }; + } __attribute__ ((packed)); + +-/* The following function really belong in v4l2-common, but that causes +- a circular dependency between modules. We need to think about this, but +- for now this will do. */ +- +-/* Return non-zero if this control is a pointer type. Currently only +- type STRING is a pointer type. */ +-static inline int ctrl_is_pointer(u32 id) +-{ +- switch (id) { +- case V4L2_CID_RDS_TX_PS_NAME: +- case V4L2_CID_RDS_TX_RADIO_TEXT: +- return 1; +- default: +- return 0; ++/* Return true if this control is a pointer type. */ ++static inline bool ctrl_is_pointer(struct file *file, u32 id) ++{ ++ struct video_device *vdev = video_devdata(file); ++ struct v4l2_fh *fh = NULL; ++ struct v4l2_ctrl_handler *hdl = NULL; ++ struct v4l2_query_ext_ctrl qec = { id }; ++ const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; ++ ++ if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) ++ fh = file->private_data; ++ ++ if (fh && fh->ctrl_handler) ++ hdl = fh->ctrl_handler; ++ else if (vdev->ctrl_handler) ++ hdl = vdev->ctrl_handler; ++ ++ if (hdl) { ++ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id); ++ ++ return ctrl && ctrl->is_ptr; + } ++ ++ if (!ops->vidioc_query_ext_ctrl) ++ return false; ++ ++ return !ops->vidioc_query_ext_ctrl(file, fh, &qec) && ++ (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); + } + +-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) ++static int get_v4l2_ext_controls32(struct file *file, ++ struct v4l2_ext_controls *kp, ++ struct v4l2_ext_controls32 __user *up) + { + struct v4l2_ext_control32 __user *ucontrols; + struct v4l2_ext_control __user *kcontrols; +@@ -651,7 +668,7 @@ static int get_v4l2_ext_controls32(struc + return -EFAULT; + if (get_user(id, &kcontrols->id)) + return -EFAULT; +- if (ctrl_is_pointer(id)) { ++ if (ctrl_is_pointer(file, id)) { + void __user *s; + + if (get_user(p, &ucontrols->string)) +@@ -666,7 +683,9 @@ static int get_v4l2_ext_controls32(struc + return 0; + } + +-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) ++static int put_v4l2_ext_controls32(struct file *file, ++ struct v4l2_ext_controls *kp, ++ struct v4l2_ext_controls32 __user *up) + { + struct v4l2_ext_control32 __user *ucontrols; + struct v4l2_ext_control __user *kcontrols = +@@ -698,7 +717,7 @@ static int put_v4l2_ext_controls32(struc + /* Do not modify the pointer when copying a pointer control. + The contents of the pointer was changed, not the pointer + itself. */ +- if (ctrl_is_pointer(id)) ++ if (ctrl_is_pointer(file, id)) + size -= sizeof(ucontrols->value64); + if (copy_in_user(ucontrols, kcontrols, size)) + return -EFAULT; +@@ -912,7 +931,7 @@ static long do_video_ioctl(struct file * + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: +- err = get_v4l2_ext_controls32(&karg.v2ecs, up); ++ err = get_v4l2_ext_controls32(file, &karg.v2ecs, up); + compatible_arg = 0; + break; + case VIDIOC_DQEVENT: +@@ -939,7 +958,7 @@ static long do_video_ioctl(struct file * + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: +- if (put_v4l2_ext_controls32(&karg.v2ecs, up)) ++ if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) + err = -EFAULT; + break; + case VIDIOC_S_EDID: diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch new file mode 100644 index 00000000000..9136c4c9b75 --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch @@ -0,0 +1,429 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:25 +0100 +Subject: media: v4l2-compat-ioctl32.c: fix the indentation +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-5-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 | 212 +++++++++++++------------- + 1 file changed, 107 insertions(+), 105 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -49,12 +49,12 @@ struct v4l2_window32 { + static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) + { + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || +- copy_from_user(&kp->w, &up->w, sizeof(up->w)) || +- get_user(kp->field, &up->field) || +- get_user(kp->chromakey, &up->chromakey) || +- get_user(kp->clipcount, &up->clipcount) || +- get_user(kp->global_alpha, &up->global_alpha)) +- return -EFAULT; ++ copy_from_user(&kp->w, &up->w, sizeof(up->w)) || ++ get_user(kp->field, &up->field) || ++ get_user(kp->chromakey, &up->chromakey) || ++ get_user(kp->clipcount, &up->clipcount) || ++ get_user(kp->global_alpha, &up->global_alpha)) ++ return -EFAULT; + if (kp->clipcount > 2048) + return -EINVAL; + if (kp->clipcount) { +@@ -84,11 +84,11 @@ static int get_v4l2_window32(struct v4l2 + static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) + { + if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || +- put_user(kp->field, &up->field) || +- put_user(kp->chromakey, &up->chromakey) || +- put_user(kp->clipcount, &up->clipcount) || +- put_user(kp->global_alpha, &up->global_alpha)) +- return -EFAULT; ++ put_user(kp->field, &up->field) || ++ put_user(kp->chromakey, &up->chromakey) || ++ put_user(kp->clipcount, &up->clipcount) || ++ put_user(kp->global_alpha, &up->global_alpha)) ++ return -EFAULT; + return 0; + } + +@@ -100,7 +100,7 @@ static inline int get_v4l2_pix_format(st + } + + static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, +- struct v4l2_pix_format_mplane __user *up) ++ struct v4l2_pix_format_mplane __user *up) + { + if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) + return -EFAULT; +@@ -115,7 +115,7 @@ static inline int put_v4l2_pix_format(st + } + + static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, +- struct v4l2_pix_format_mplane __user *up) ++ struct v4l2_pix_format_mplane __user *up) + { + if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) + return -EFAULT; +@@ -238,7 +238,7 @@ static int __get_v4l2_format32(struct v4 + return get_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta); + default: + pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", +- kp->type); ++ kp->type); + return -EINVAL; + } + } +@@ -287,7 +287,7 @@ static int __put_v4l2_format32(struct v4 + return put_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta); + default: + pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", +- kp->type); ++ kp->type); + return -EINVAL; + } + } +@@ -321,7 +321,7 @@ static int get_v4l2_standard32(struct v4 + { + /* other fields are not set by the user, nor used by the driver */ + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || +- get_user(kp->index, &up->index)) ++ get_user(kp->index, &up->index)) + return -EFAULT; + return 0; + } +@@ -329,13 +329,14 @@ static int get_v4l2_standard32(struct v4 + static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) + { + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || +- put_user(kp->index, &up->index) || +- put_user(kp->id, &up->id) || +- copy_to_user(up->name, kp->name, 24) || +- copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || +- put_user(kp->framelines, &up->framelines) || +- copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) +- return -EFAULT; ++ put_user(kp->index, &up->index) || ++ put_user(kp->id, &up->id) || ++ copy_to_user(up->name, kp->name, 24) || ++ copy_to_user(&up->frameperiod, &kp->frameperiod, ++ sizeof(kp->frameperiod)) || ++ put_user(kp->framelines, &up->framelines) || ++ copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) ++ return -EFAULT; + return 0; + } + +@@ -375,14 +376,14 @@ struct v4l2_buffer32 { + }; + + static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, +- enum v4l2_memory memory) ++ enum v4l2_memory memory) + { + void __user *up_pln; + compat_long_t p; + + if (copy_in_user(up, up32, 2 * sizeof(__u32)) || +- copy_in_user(&up->data_offset, &up32->data_offset, +- sizeof(__u32))) ++ copy_in_user(&up->data_offset, &up32->data_offset, ++ sizeof(__u32))) + return -EFAULT; + + if (memory == V4L2_MEMORY_USERPTR) { +@@ -396,7 +397,7 @@ static int get_v4l2_plane32(struct v4l2_ + return -EFAULT; + } else { + if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, +- sizeof(__u32))) ++ sizeof(__u32))) + return -EFAULT; + } + +@@ -404,23 +405,23 @@ static int get_v4l2_plane32(struct v4l2_ + } + + static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, +- enum v4l2_memory memory) ++ enum v4l2_memory memory) + { + if (copy_in_user(up32, up, 2 * sizeof(__u32)) || +- copy_in_user(&up32->data_offset, &up->data_offset, +- sizeof(__u32))) ++ copy_in_user(&up32->data_offset, &up->data_offset, ++ sizeof(__u32))) + return -EFAULT; + + /* For MMAP, driver might've set up the offset, so copy it back. + * USERPTR stays the same (was userspace-provided), so no copying. */ + if (memory == V4L2_MEMORY_MMAP) + if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, +- sizeof(__u32))) ++ sizeof(__u32))) + return -EFAULT; + /* For DMABUF, driver might've set up the fd, so copy it back. */ + if (memory == V4L2_MEMORY_DMABUF) + if (copy_in_user(&up32->m.fd, &up->m.fd, +- sizeof(int))) ++ sizeof(int))) + return -EFAULT; + + return 0; +@@ -434,19 +435,19 @@ static int get_v4l2_buffer32(struct v4l2 + int ret; + + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || +- get_user(kp->index, &up->index) || +- get_user(kp->type, &up->type) || +- get_user(kp->flags, &up->flags) || +- get_user(kp->memory, &up->memory) || +- get_user(kp->length, &up->length)) +- return -EFAULT; ++ get_user(kp->index, &up->index) || ++ get_user(kp->type, &up->type) || ++ get_user(kp->flags, &up->flags) || ++ get_user(kp->memory, &up->memory) || ++ get_user(kp->length, &up->length)) ++ return -EFAULT; + + if (V4L2_TYPE_IS_OUTPUT(kp->type)) + if (get_user(kp->bytesused, &up->bytesused) || +- get_user(kp->field, &up->field) || +- get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || +- get_user(kp->timestamp.tv_usec, +- &up->timestamp.tv_usec)) ++ get_user(kp->field, &up->field) || ++ get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || ++ get_user(kp->timestamp.tv_usec, ++ &up->timestamp.tv_usec)) + return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { +@@ -466,7 +467,7 @@ static int get_v4l2_buffer32(struct v4l2 + + uplane32 = compat_ptr(p); + if (!access_ok(VERIFY_READ, uplane32, +- kp->length * sizeof(struct v4l2_plane32))) ++ kp->length * sizeof(struct v4l2_plane32))) + return -EFAULT; + + /* We don't really care if userspace decides to kill itself +@@ -490,12 +491,12 @@ static int get_v4l2_buffer32(struct v4l2 + break; + case V4L2_MEMORY_USERPTR: + { +- compat_long_t tmp; ++ compat_long_t tmp; + +- if (get_user(tmp, &up->m.userptr)) +- return -EFAULT; ++ if (get_user(tmp, &up->m.userptr)) ++ return -EFAULT; + +- kp->m.userptr = (unsigned long)compat_ptr(tmp); ++ kp->m.userptr = (unsigned long)compat_ptr(tmp); + } + break; + case V4L2_MEMORY_OVERLAY: +@@ -521,22 +522,23 @@ static int put_v4l2_buffer32(struct v4l2 + int ret; + + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || +- put_user(kp->index, &up->index) || +- put_user(kp->type, &up->type) || +- put_user(kp->flags, &up->flags) || +- put_user(kp->memory, &up->memory)) +- return -EFAULT; ++ put_user(kp->index, &up->index) || ++ put_user(kp->type, &up->type) || ++ put_user(kp->flags, &up->flags) || ++ put_user(kp->memory, &up->memory)) ++ return -EFAULT; + + if (put_user(kp->bytesused, &up->bytesused) || +- put_user(kp->field, &up->field) || +- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || +- put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || +- copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || +- put_user(kp->sequence, &up->sequence) || +- put_user(kp->reserved2, &up->reserved2) || +- put_user(kp->reserved, &up->reserved) || +- put_user(kp->length, &up->length)) +- return -EFAULT; ++ put_user(kp->field, &up->field) || ++ put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || ++ put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || ++ copy_to_user(&up->timecode, &kp->timecode, ++ sizeof(struct v4l2_timecode)) || ++ put_user(kp->sequence, &up->sequence) || ++ put_user(kp->reserved2, &up->reserved2) || ++ put_user(kp->reserved, &up->reserved) || ++ put_user(kp->length, &up->length)) ++ return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { + num_planes = kp->length; +@@ -600,11 +602,11 @@ static int get_v4l2_framebuffer32(struct + u32 tmp; + + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || +- get_user(tmp, &up->base) || +- get_user(kp->capability, &up->capability) || +- get_user(kp->flags, &up->flags) || +- copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) +- return -EFAULT; ++ get_user(tmp, &up->base) || ++ get_user(kp->capability, &up->capability) || ++ get_user(kp->flags, &up->flags) || ++ copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) ++ return -EFAULT; + kp->base = (__force void *)compat_ptr(tmp); + return 0; + } +@@ -614,11 +616,11 @@ static int put_v4l2_framebuffer32(struct + u32 tmp = (u32)((unsigned long)kp->base); + + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || +- put_user(tmp, &up->base) || +- put_user(kp->capability, &up->capability) || +- put_user(kp->flags, &up->flags) || +- copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) +- return -EFAULT; ++ put_user(tmp, &up->base) || ++ put_user(kp->capability, &up->capability) || ++ put_user(kp->flags, &up->flags) || ++ copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) ++ return -EFAULT; + return 0; + } + +@@ -694,12 +696,12 @@ static int get_v4l2_ext_controls32(struc + compat_caddr_t p; + + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || +- get_user(kp->which, &up->which) || +- get_user(kp->count, &up->count) || +- get_user(kp->error_idx, &up->error_idx) || +- copy_from_user(kp->reserved, up->reserved, +- sizeof(kp->reserved))) +- return -EFAULT; ++ get_user(kp->which, &up->which) || ++ get_user(kp->count, &up->count) || ++ get_user(kp->error_idx, &up->error_idx) || ++ copy_from_user(kp->reserved, up->reserved, ++ sizeof(kp->reserved))) ++ return -EFAULT; + if (kp->count == 0) { + kp->controls = NULL; + return 0; +@@ -710,7 +712,7 @@ static int get_v4l2_ext_controls32(struc + return -EFAULT; + ucontrols = compat_ptr(p); + if (!access_ok(VERIFY_READ, ucontrols, +- kp->count * sizeof(struct v4l2_ext_control32))) ++ kp->count * sizeof(struct v4l2_ext_control32))) + return -EFAULT; + kcontrols = compat_alloc_user_space(kp->count * + sizeof(struct v4l2_ext_control)); +@@ -746,11 +748,11 @@ static int put_v4l2_ext_controls32(struc + compat_caddr_t p; + + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || +- put_user(kp->which, &up->which) || +- put_user(kp->count, &up->count) || +- put_user(kp->error_idx, &up->error_idx) || +- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) +- return -EFAULT; ++ put_user(kp->which, &up->which) || ++ put_user(kp->count, &up->count) || ++ put_user(kp->error_idx, &up->error_idx) || ++ copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) ++ return -EFAULT; + if (!kp->count) + return 0; + +@@ -758,7 +760,7 @@ static int put_v4l2_ext_controls32(struc + return -EFAULT; + ucontrols = compat_ptr(p); + if (!access_ok(VERIFY_WRITE, ucontrols, +- n * sizeof(struct v4l2_ext_control32))) ++ n * sizeof(struct v4l2_ext_control32))) + return -EFAULT; + + while (--n >= 0) { +@@ -796,15 +798,15 @@ struct v4l2_event32 { + static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) + { + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) || +- put_user(kp->type, &up->type) || +- copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || +- put_user(kp->pending, &up->pending) || +- put_user(kp->sequence, &up->sequence) || +- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || +- put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || +- put_user(kp->id, &up->id) || +- copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) +- return -EFAULT; ++ put_user(kp->type, &up->type) || ++ copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || ++ put_user(kp->pending, &up->pending) || ++ put_user(kp->sequence, &up->sequence) || ++ put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || ++ put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || ++ put_user(kp->id, &up->id) || ++ copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) ++ return -EFAULT; + return 0; + } + +@@ -821,12 +823,12 @@ static int get_v4l2_edid32(struct v4l2_e + u32 tmp; + + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || +- get_user(kp->pad, &up->pad) || +- get_user(kp->start_block, &up->start_block) || +- get_user(kp->blocks, &up->blocks) || +- get_user(tmp, &up->edid) || +- copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) +- return -EFAULT; ++ get_user(kp->pad, &up->pad) || ++ get_user(kp->start_block, &up->start_block) || ++ get_user(kp->blocks, &up->blocks) || ++ get_user(tmp, &up->edid) || ++ copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) ++ return -EFAULT; + kp->edid = (__force u8 *)compat_ptr(tmp); + return 0; + } +@@ -836,12 +838,12 @@ static int put_v4l2_edid32(struct v4l2_e + u32 tmp = (u32)((unsigned long)kp->edid); + + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || +- put_user(kp->pad, &up->pad) || +- put_user(kp->start_block, &up->start_block) || +- put_user(kp->blocks, &up->blocks) || +- put_user(tmp, &up->edid) || +- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) +- return -EFAULT; ++ put_user(kp->pad, &up->pad) || ++ put_user(kp->start_block, &up->start_block) || ++ put_user(kp->blocks, &up->blocks) || ++ put_user(tmp, &up->edid) || ++ copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) ++ return -EFAULT; + return 0; + } + diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch new file mode 100644 index 00000000000..60a56f10eb4 --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch @@ -0,0 +1,43 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:34 +0100 +Subject: media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-14-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 +@@ -770,7 +770,7 @@ static inline bool ctrl_is_pointer(struc + return ctrl && ctrl->is_ptr; + } + +- if (!ops->vidioc_query_ext_ctrl) ++ if (!ops || !ops->vidioc_query_ext_ctrl) + return false; + + return !ops->vidioc_query_ext_ctrl(file, fh, &qec) && diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch new file mode 100644 index 00000000000..b7aacc5028f --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch @@ -0,0 +1,194 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:26 +0100 +Subject: media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-6-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 | 124 +++++--------------------- + 1 file changed, 24 insertions(+), 100 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -92,92 +92,6 @@ static int put_v4l2_window32(struct v4l2 + return 0; + } + +-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) +-{ +- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, +- struct v4l2_pix_format_mplane __user *up) +-{ +- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) +- return -EFAULT; +- return 0; +-} +- +-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) +-{ +- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, +- struct v4l2_pix_format_mplane __user *up) +-{ +- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) +- return -EFAULT; +- return 0; +-} +- +-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) +-{ +- if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) +-{ +- if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) +-{ +- if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) +-{ +- if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up) +-{ +- if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up) +-{ +- if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int get_v4l2_meta_format(struct v4l2_meta_format *kp, struct v4l2_meta_format __user *up) +-{ +- if (copy_from_user(kp, up, sizeof(struct v4l2_meta_format))) +- return -EFAULT; +- return 0; +-} +- +-static inline int put_v4l2_meta_format(struct v4l2_meta_format *kp, struct v4l2_meta_format __user *up) +-{ +- if (copy_to_user(up, kp, sizeof(struct v4l2_meta_format))) +- return -EFAULT; +- return 0; +-} +- + struct v4l2_format32 { + __u32 type; /* enum v4l2_buf_type */ + union { +@@ -217,25 +131,30 @@ static int __get_v4l2_format32(struct v4 + switch (kp->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: +- return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); ++ return copy_from_user(&kp->fmt.pix, &up->fmt.pix, ++ sizeof(kp->fmt.pix)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: +- return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp, +- &up->fmt.pix_mp); ++ return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, ++ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: +- return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); ++ return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi, ++ sizeof(kp->fmt.vbi)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: +- return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); ++ return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, ++ sizeof(kp->fmt.sliced)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SDR_CAPTURE: + case V4L2_BUF_TYPE_SDR_OUTPUT: +- return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); ++ return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr, ++ sizeof(kp->fmt.sdr)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_META_CAPTURE: +- return get_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta); ++ return copy_from_user(&kp->fmt.meta, &up->fmt.meta, ++ sizeof(kp->fmt.meta)) ? -EFAULT : 0; + default: + pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", + kp->type); +@@ -266,25 +185,30 @@ static int __put_v4l2_format32(struct v4 + switch (kp->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: +- return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); ++ return copy_to_user(&up->fmt.pix, &kp->fmt.pix, ++ sizeof(kp->fmt.pix)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: +- return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp, +- &up->fmt.pix_mp); ++ return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, ++ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: +- return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); ++ return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi, ++ sizeof(kp->fmt.vbi)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: +- return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); ++ return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced, ++ sizeof(kp->fmt.sliced)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SDR_CAPTURE: + case V4L2_BUF_TYPE_SDR_OUTPUT: +- return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); ++ return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr, ++ sizeof(kp->fmt.sdr)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_META_CAPTURE: +- return put_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta); ++ return copy_to_user(&up->fmt.meta, &kp->fmt.meta, ++ sizeof(kp->fmt.meta)) ? -EFAULT : 0; + default: + pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", + kp->type); diff --git a/queue-4.14/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch b/queue-4.14/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch new file mode 100644 index 00000000000..3325891dfe7 --- /dev/null +++ b/queue-4.14/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch @@ -0,0 +1,1302 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Daniel Mentz +Date: Wed, 14 Feb 2018 12:44:33 +0100 +Subject: media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Daniel Mentz , Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-13-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, 483 insertions(+), 269 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -22,6 +22,14 @@ + #include + #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; +@@ -48,37 +56,41 @@ struct v4l2_window32 { + __u8 global_alpha; + }; + +-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) ++static int get_v4l2_window32(struct v4l2_window __user *kp, ++ struct v4l2_window32 __user *up, ++ void __user *aux_buf, u32 aux_space) + { + struct v4l2_clip32 __user *uclips; + struct v4l2_clip __user *kclips; + compat_caddr_t p; +- u32 n; ++ u32 clipcount; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || +- copy_from_user(&kp->w, &up->w, sizeof(up->w)) || +- get_user(kp->field, &up->field) || +- get_user(kp->chromakey, &up->chromakey) || +- get_user(kp->clipcount, &up->clipcount) || +- get_user(kp->global_alpha, &up->global_alpha)) ++ copy_in_user(&kp->w, &up->w, sizeof(up->w)) || ++ assign_in_user(&kp->field, &up->field) || ++ assign_in_user(&kp->chromakey, &up->chromakey) || ++ assign_in_user(&kp->global_alpha, &up->global_alpha) || ++ get_user(clipcount, &up->clipcount) || ++ put_user(clipcount, &kp->clipcount)) + return -EFAULT; +- if (kp->clipcount > 2048) ++ if (clipcount > 2048) + return -EINVAL; +- if (!kp->clipcount) { +- kp->clips = NULL; +- return 0; +- } ++ if (!clipcount) ++ return put_user(NULL, &kp->clips); + +- n = kp->clipcount; + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); +- kclips = compat_alloc_user_space(n * sizeof(*kclips)); +- kp->clips = kclips; +- while (n--) { ++ if (aux_space < clipcount * sizeof(*kclips)) ++ return -EFAULT; ++ kclips = aux_buf; ++ if (put_user(kclips, &kp->clips)) ++ return -EFAULT; ++ ++ while (clipcount--) { + if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) + return -EFAULT; +- if (put_user(n ? kclips + 1 : NULL, &kclips->next)) ++ if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next)) + return -EFAULT; + uclips++; + kclips++; +@@ -86,27 +98,28 @@ static int get_v4l2_window32(struct v4l2 + return 0; + } + +-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) ++static int put_v4l2_window32(struct v4l2_window __user *kp, ++ struct v4l2_window32 __user *up) + { + struct v4l2_clip __user *kclips = kp->clips; + struct v4l2_clip32 __user *uclips; +- u32 n = kp->clipcount; + compat_caddr_t p; ++ u32 clipcount; + +- if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || +- put_user(kp->field, &up->field) || +- put_user(kp->chromakey, &up->chromakey) || +- put_user(kp->clipcount, &up->clipcount) || +- put_user(kp->global_alpha, &up->global_alpha)) ++ if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) || ++ assign_in_user(&up->field, &kp->field) || ++ assign_in_user(&up->chromakey, &kp->chromakey) || ++ assign_in_user(&up->global_alpha, &kp->global_alpha) || ++ get_user(clipcount, &kp->clipcount) || ++ put_user(clipcount, &up->clipcount)) + return -EFAULT; +- +- if (!kp->clipcount) ++ if (!clipcount) + return 0; + + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); +- while (n--) { ++ while (clipcount--) { + if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) + return -EFAULT; + uclips++; +@@ -146,107 +159,164 @@ struct v4l2_create_buffers32 { + __u32 reserved[8]; + }; + +-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) ++static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) ++{ ++ u32 type; ++ ++ if (get_user(type, &up->type)) ++ return -EFAULT; ++ ++ switch (type) { ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { ++ u32 clipcount; ++ ++ if (get_user(clipcount, &up->fmt.win.clipcount)) ++ return -EFAULT; ++ if (clipcount > 2048) ++ return -EINVAL; ++ *size = clipcount * sizeof(struct v4l2_clip); ++ return 0; ++ } ++ default: ++ *size = 0; ++ return 0; ++ } ++} ++ ++static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) ++{ ++ if (!access_ok(VERIFY_READ, up, sizeof(*up))) ++ return -EFAULT; ++ return __bufsize_v4l2_format(up, size); ++} ++ ++static int __get_v4l2_format32(struct v4l2_format __user *kp, ++ struct v4l2_format32 __user *up, ++ void __user *aux_buf, u32 aux_space) + { +- if (get_user(kp->type, &up->type)) ++ u32 type; ++ ++ if (get_user(type, &up->type) || put_user(type, &kp->type)) + return -EFAULT; + +- switch (kp->type) { ++ switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: +- return copy_from_user(&kp->fmt.pix, &up->fmt.pix, +- sizeof(kp->fmt.pix)) ? -EFAULT : 0; ++ return copy_in_user(&kp->fmt.pix, &up->fmt.pix, ++ sizeof(kp->fmt.pix)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: +- return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, +- sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; ++ return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, ++ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: +- return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); ++ return get_v4l2_window32(&kp->fmt.win, &up->fmt.win, ++ aux_buf, aux_space); + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: +- return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi, +- sizeof(kp->fmt.vbi)) ? -EFAULT : 0; ++ return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi, ++ sizeof(kp->fmt.vbi)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: +- return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, +- sizeof(kp->fmt.sliced)) ? -EFAULT : 0; ++ return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced, ++ sizeof(kp->fmt.sliced)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SDR_CAPTURE: + case V4L2_BUF_TYPE_SDR_OUTPUT: +- return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr, +- sizeof(kp->fmt.sdr)) ? -EFAULT : 0; ++ return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr, ++ sizeof(kp->fmt.sdr)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_META_CAPTURE: +- return copy_from_user(&kp->fmt.meta, &up->fmt.meta, +- sizeof(kp->fmt.meta)) ? -EFAULT : 0; ++ return copy_in_user(&kp->fmt.meta, &up->fmt.meta, ++ sizeof(kp->fmt.meta)) ? -EFAULT : 0; + default: + return -EINVAL; + } + } + +-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) ++static int get_v4l2_format32(struct v4l2_format __user *kp, ++ struct v4l2_format32 __user *up, ++ void __user *aux_buf, u32 aux_space) + { + if (!access_ok(VERIFY_READ, up, sizeof(*up))) + return -EFAULT; +- return __get_v4l2_format32(kp, up); ++ return __get_v4l2_format32(kp, up, aux_buf, aux_space); + } + +-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) ++static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up, ++ u32 *size) ++{ ++ if (!access_ok(VERIFY_READ, up, sizeof(*up))) ++ return -EFAULT; ++ return __bufsize_v4l2_format(&up->format, size); ++} ++ ++static int get_v4l2_create32(struct v4l2_create_buffers __user *kp, ++ struct v4l2_create_buffers32 __user *up, ++ void __user *aux_buf, u32 aux_space) + { + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || +- copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) ++ copy_in_user(kp, up, ++ offsetof(struct v4l2_create_buffers32, format))) + return -EFAULT; +- return __get_v4l2_format32(&kp->format, &up->format); ++ return __get_v4l2_format32(&kp->format, &up->format, ++ aux_buf, aux_space); + } + +-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) ++static int __put_v4l2_format32(struct v4l2_format __user *kp, ++ struct v4l2_format32 __user *up) + { +- if (put_user(kp->type, &up->type)) ++ u32 type; ++ ++ if (get_user(type, &kp->type)) + return -EFAULT; + +- switch (kp->type) { ++ switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: +- return copy_to_user(&up->fmt.pix, &kp->fmt.pix, ++ return copy_in_user(&up->fmt.pix, &kp->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: +- return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, ++ return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: +- return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi, ++ return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: +- return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced, ++ return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SDR_CAPTURE: + case V4L2_BUF_TYPE_SDR_OUTPUT: +- return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr, ++ return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr, + sizeof(kp->fmt.sdr)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_META_CAPTURE: +- return copy_to_user(&up->fmt.meta, &kp->fmt.meta, ++ return copy_in_user(&up->fmt.meta, &kp->fmt.meta, + sizeof(kp->fmt.meta)) ? -EFAULT : 0; + default: + return -EINVAL; + } + } + +-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) ++static int put_v4l2_format32(struct v4l2_format __user *kp, ++ struct v4l2_format32 __user *up) + { + if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) + return -EFAULT; + return __put_v4l2_format32(kp, up); + } + +-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) ++static int put_v4l2_create32(struct v4l2_create_buffers __user *kp, ++ struct v4l2_create_buffers32 __user *up) + { + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || +- copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || +- copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) ++ copy_in_user(up, kp, ++ offsetof(struct v4l2_create_buffers32, format)) || ++ copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + return -EFAULT; + return __put_v4l2_format32(&kp->format, &up->format); + } +@@ -260,25 +330,27 @@ struct v4l2_standard32 { + __u32 reserved[4]; + }; + +-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) ++static int get_v4l2_standard32(struct v4l2_standard __user *kp, ++ struct v4l2_standard32 __user *up) + { + /* other fields are not set by the user, nor used by the driver */ + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || +- get_user(kp->index, &up->index)) ++ assign_in_user(&kp->index, &up->index)) + return -EFAULT; + return 0; + } + +-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) ++static int put_v4l2_standard32(struct v4l2_standard __user *kp, ++ struct v4l2_standard32 __user *up) + { + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || +- put_user(kp->index, &up->index) || +- put_user(kp->id, &up->id) || +- copy_to_user(up->name, kp->name, sizeof(up->name)) || +- copy_to_user(&up->frameperiod, &kp->frameperiod, +- sizeof(kp->frameperiod)) || +- put_user(kp->framelines, &up->framelines) || +- copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) ++ assign_in_user(&up->index, &kp->index) || ++ assign_in_user(&up->id, &kp->id) || ++ copy_in_user(up->name, kp->name, sizeof(up->name)) || ++ copy_in_user(&up->frameperiod, &kp->frameperiod, ++ sizeof(up->frameperiod)) || ++ assign_in_user(&up->framelines, &kp->framelines) || ++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) + return -EFAULT; + return 0; + } +@@ -318,11 +390,11 @@ struct v4l2_buffer32 { + __u32 reserved; + }; + +-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, ++static int get_v4l2_plane32(struct v4l2_plane __user *up, ++ struct v4l2_plane32 __user *up32, + enum v4l2_memory memory) + { +- void __user *up_pln; +- compat_long_t p; ++ compat_ulong_t p; + + if (copy_in_user(up, up32, 2 * sizeof(__u32)) || + copy_in_user(&up->data_offset, &up32->data_offset, +@@ -337,10 +409,8 @@ static int get_v4l2_plane32(struct v4l2_ + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: +- if (get_user(p, &up32->m.userptr)) +- return -EFAULT; +- up_pln = compat_ptr(p); +- if (put_user((unsigned long)up_pln, &up->m.userptr)) ++ if (get_user(p, &up32->m.userptr) || ++ put_user((unsigned long)compat_ptr(p), &up->m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: +@@ -352,7 +422,8 @@ static int get_v4l2_plane32(struct v4l2_ + return 0; + } + +-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, ++static int put_v4l2_plane32(struct v4l2_plane __user *up, ++ struct v4l2_plane32 __user *up32, + enum v4l2_memory memory) + { + unsigned long p; +@@ -376,8 +447,7 @@ static int put_v4l2_plane32(struct v4l2_ + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: +- if (copy_in_user(&up32->m.fd, &up->m.fd, +- sizeof(up->m.fd))) ++ if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd))) + return -EFAULT; + break; + } +@@ -385,79 +455,121 @@ static int put_v4l2_plane32(struct v4l2_ + return 0; + } + +-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) ++static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size) + { ++ u32 type; ++ u32 length; ++ ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || ++ get_user(type, &up->type) || ++ get_user(length, &up->length)) ++ return -EFAULT; ++ ++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) { ++ if (length > VIDEO_MAX_PLANES) ++ return -EINVAL; ++ ++ /* ++ * We don't really care if userspace decides to kill itself ++ * by passing a very big length value ++ */ ++ *size = length * sizeof(struct v4l2_plane); ++ } else { ++ *size = 0; ++ } ++ return 0; ++} ++ ++static int get_v4l2_buffer32(struct v4l2_buffer __user *kp, ++ struct v4l2_buffer32 __user *up, ++ void __user *aux_buf, u32 aux_space) ++{ ++ u32 type; ++ u32 length; ++ enum v4l2_memory memory; + struct v4l2_plane32 __user *uplane32; + struct v4l2_plane __user *uplane; + compat_caddr_t p; + int ret; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || +- get_user(kp->index, &up->index) || +- get_user(kp->type, &up->type) || +- get_user(kp->flags, &up->flags) || +- get_user(kp->memory, &up->memory) || +- get_user(kp->length, &up->length)) +- return -EFAULT; +- +- if (V4L2_TYPE_IS_OUTPUT(kp->type)) +- if (get_user(kp->bytesused, &up->bytesused) || +- get_user(kp->field, &up->field) || +- get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || +- get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec)) +- return -EFAULT; +- +- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { +- unsigned int num_planes; +- +- if (kp->length == 0) { +- kp->m.planes = NULL; +- /* num_planes == 0 is legal, e.g. when userspace doesn't +- * need planes array on DQBUF*/ +- return 0; +- } else if (kp->length > VIDEO_MAX_PLANES) { +- return -EINVAL; ++ assign_in_user(&kp->index, &up->index) || ++ get_user(type, &up->type) || ++ put_user(type, &kp->type) || ++ assign_in_user(&kp->flags, &up->flags) || ++ get_user(memory, &up->memory) || ++ put_user(memory, &kp->memory) || ++ get_user(length, &up->length) || ++ put_user(length, &kp->length)) ++ return -EFAULT; ++ ++ if (V4L2_TYPE_IS_OUTPUT(type)) ++ if (assign_in_user(&kp->bytesused, &up->bytesused) || ++ assign_in_user(&kp->field, &up->field) || ++ assign_in_user(&kp->timestamp.tv_sec, ++ &up->timestamp.tv_sec) || ++ assign_in_user(&kp->timestamp.tv_usec, ++ &up->timestamp.tv_usec)) ++ return -EFAULT; ++ ++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) { ++ u32 num_planes = length; ++ ++ if (num_planes == 0) { ++ /* ++ * num_planes == 0 is legal, e.g. when userspace doesn't ++ * need planes array on DQBUF ++ */ ++ return put_user(NULL, &kp->m.planes); + } ++ if (num_planes > VIDEO_MAX_PLANES) ++ return -EINVAL; + + if (get_user(p, &up->m.planes)) + return -EFAULT; + + uplane32 = compat_ptr(p); + if (!access_ok(VERIFY_READ, uplane32, +- kp->length * sizeof(*uplane32))) ++ num_planes * sizeof(*uplane32))) + return -EFAULT; + +- /* We don't really care if userspace decides to kill itself +- * by passing a very big num_planes value */ +- uplane = compat_alloc_user_space(kp->length * sizeof(*uplane)); +- kp->m.planes = (__force struct v4l2_plane *)uplane; ++ /* ++ * We don't really care if userspace decides to kill itself ++ * by passing a very big num_planes value ++ */ ++ if (aux_space < num_planes * sizeof(*uplane)) ++ return -EFAULT; + +- for (num_planes = 0; num_planes < kp->length; num_planes++) { +- ret = get_v4l2_plane32(uplane, uplane32, kp->memory); ++ uplane = aux_buf; ++ if (put_user((__force struct v4l2_plane *)uplane, ++ &kp->m.planes)) ++ return -EFAULT; ++ ++ while (num_planes--) { ++ ret = get_v4l2_plane32(uplane, uplane32, memory); + if (ret) + return ret; +- ++uplane; +- ++uplane32; ++ uplane++; ++ uplane32++; + } + } else { +- switch (kp->memory) { ++ switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: +- if (get_user(kp->m.offset, &up->m.offset)) ++ if (assign_in_user(&kp->m.offset, &up->m.offset)) + return -EFAULT; + break; +- case V4L2_MEMORY_USERPTR: +- { +- compat_long_t tmp; ++ case V4L2_MEMORY_USERPTR: { ++ compat_ulong_t userptr; + +- if (get_user(tmp, &up->m.userptr)) +- return -EFAULT; +- +- kp->m.userptr = (unsigned long)compat_ptr(tmp); +- } ++ if (get_user(userptr, &up->m.userptr) || ++ put_user((unsigned long)compat_ptr(userptr), ++ &kp->m.userptr)) ++ return -EFAULT; + break; ++ } + case V4L2_MEMORY_DMABUF: +- if (get_user(kp->m.fd, &up->m.fd)) ++ if (assign_in_user(&kp->m.fd, &up->m.fd)) + return -EFAULT; + break; + } +@@ -466,62 +578,70 @@ static int get_v4l2_buffer32(struct v4l2 + return 0; + } + +-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) ++static int put_v4l2_buffer32(struct v4l2_buffer __user *kp, ++ struct v4l2_buffer32 __user *up) + { ++ u32 type; ++ u32 length; ++ enum v4l2_memory memory; + struct v4l2_plane32 __user *uplane32; + struct v4l2_plane __user *uplane; + compat_caddr_t p; +- int num_planes; + int ret; + + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || +- put_user(kp->index, &up->index) || +- put_user(kp->type, &up->type) || +- put_user(kp->flags, &up->flags) || +- put_user(kp->memory, &up->memory)) +- return -EFAULT; +- +- if (put_user(kp->bytesused, &up->bytesused) || +- put_user(kp->field, &up->field) || +- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || +- put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || +- copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || +- put_user(kp->sequence, &up->sequence) || +- put_user(kp->reserved2, &up->reserved2) || +- put_user(kp->reserved, &up->reserved) || +- put_user(kp->length, &up->length)) ++ assign_in_user(&up->index, &kp->index) || ++ get_user(type, &kp->type) || ++ put_user(type, &up->type) || ++ assign_in_user(&up->flags, &kp->flags) || ++ get_user(memory, &kp->memory) || ++ put_user(memory, &up->memory)) ++ return -EFAULT; ++ ++ if (assign_in_user(&up->bytesused, &kp->bytesused) || ++ assign_in_user(&up->field, &kp->field) || ++ assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || ++ assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) || ++ copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || ++ assign_in_user(&up->sequence, &kp->sequence) || ++ assign_in_user(&up->reserved2, &kp->reserved2) || ++ assign_in_user(&up->reserved, &kp->reserved) || ++ get_user(length, &kp->length) || ++ put_user(length, &up->length)) + return -EFAULT; + +- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { +- num_planes = kp->length; ++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) { ++ u32 num_planes = length; ++ + if (num_planes == 0) + return 0; + +- uplane = (__force struct v4l2_plane __user *)kp->m.planes; ++ if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes))) ++ return -EFAULT; + if (get_user(p, &up->m.planes)) + return -EFAULT; + uplane32 = compat_ptr(p); + +- while (--num_planes >= 0) { +- ret = put_v4l2_plane32(uplane, uplane32, kp->memory); ++ while (num_planes--) { ++ ret = put_v4l2_plane32(uplane, uplane32, memory); + if (ret) + return ret; + ++uplane; + ++uplane32; + } + } else { +- switch (kp->memory) { ++ switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: +- if (put_user(kp->m.offset, &up->m.offset)) ++ if (assign_in_user(&up->m.offset, &kp->m.offset)) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: +- if (put_user(kp->m.userptr, &up->m.userptr)) ++ if (assign_in_user(&up->m.userptr, &kp->m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: +- if (put_user(kp->m.fd, &up->m.fd)) ++ if (assign_in_user(&up->m.fd, &kp->m.fd)) + return -EFAULT; + break; + } +@@ -546,29 +666,32 @@ struct v4l2_framebuffer32 { + } fmt; + }; + +-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) ++static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, ++ struct v4l2_framebuffer32 __user *up) + { +- u32 tmp; ++ compat_caddr_t tmp; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(tmp, &up->base) || +- get_user(kp->capability, &up->capability) || +- get_user(kp->flags, &up->flags) || +- copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) ++ put_user((__force void *)compat_ptr(tmp), &kp->base) || ++ assign_in_user(&kp->capability, &up->capability) || ++ assign_in_user(&kp->flags, &up->flags) || ++ copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt))) + return -EFAULT; +- kp->base = (__force void *)compat_ptr(tmp); + return 0; + } + +-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) ++static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, ++ struct v4l2_framebuffer32 __user *up) + { +- u32 tmp = (u32)((unsigned long)kp->base); ++ void *base; + + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || +- put_user(tmp, &up->base) || +- put_user(kp->capability, &up->capability) || +- put_user(kp->flags, &up->flags) || +- copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) ++ get_user(base, &kp->base) || ++ put_user(ptr_to_compat(base), &up->base) || ++ assign_in_user(&up->capability, &kp->capability) || ++ assign_in_user(&up->flags, &kp->flags) || ++ copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt))) + return -EFAULT; + return 0; + } +@@ -585,18 +708,22 @@ struct v4l2_input32 { + __u32 reserved[3]; + }; + +-/* The 64-bit v4l2_input struct has extra padding at the end of the struct. +- Otherwise it is identical to the 32-bit version. */ +-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) ++/* ++ * The 64-bit v4l2_input struct has extra padding at the end of the struct. ++ * Otherwise it is identical to the 32-bit version. ++ */ ++static inline int get_v4l2_input32(struct v4l2_input __user *kp, ++ struct v4l2_input32 __user *up) + { +- if (copy_from_user(kp, up, sizeof(*up))) ++ if (copy_in_user(kp, up, sizeof(*up))) + return -EFAULT; + return 0; + } + +-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) ++static inline int put_v4l2_input32(struct v4l2_input __user *kp, ++ struct v4l2_input32 __user *up) + { +- if (copy_to_user(up, kp, sizeof(*up))) ++ if (copy_in_user(up, kp, sizeof(*up))) + return -EFAULT; + return 0; + } +@@ -650,41 +777,64 @@ static inline bool ctrl_is_pointer(struc + (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); + } + ++static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up, ++ u32 *size) ++{ ++ u32 count; ++ ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || ++ get_user(count, &up->count)) ++ return -EFAULT; ++ if (count > V4L2_CID_MAX_CTRLS) ++ return -EINVAL; ++ *size = count * sizeof(struct v4l2_ext_control); ++ return 0; ++} ++ + static int get_v4l2_ext_controls32(struct file *file, +- struct v4l2_ext_controls *kp, +- struct v4l2_ext_controls32 __user *up) ++ struct v4l2_ext_controls __user *kp, ++ struct v4l2_ext_controls32 __user *up, ++ void __user *aux_buf, u32 aux_space) + { + struct v4l2_ext_control32 __user *ucontrols; + struct v4l2_ext_control __user *kcontrols; +- unsigned int n; ++ u32 count; ++ u32 n; + compat_caddr_t p; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || +- get_user(kp->which, &up->which) || +- get_user(kp->count, &up->count) || +- get_user(kp->error_idx, &up->error_idx) || +- copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) ++ assign_in_user(&kp->which, &up->which) || ++ get_user(count, &up->count) || ++ put_user(count, &kp->count) || ++ assign_in_user(&kp->error_idx, &up->error_idx) || ++ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + return -EFAULT; +- if (kp->count == 0) { +- kp->controls = NULL; +- return 0; +- } else if (kp->count > V4L2_CID_MAX_CTRLS) { ++ ++ if (count == 0) ++ return put_user(NULL, &kp->controls); ++ if (count > V4L2_CID_MAX_CTRLS) + return -EINVAL; +- } + if (get_user(p, &up->controls)) + return -EFAULT; + ucontrols = compat_ptr(p); +- if (!access_ok(VERIFY_READ, ucontrols, kp->count * sizeof(*ucontrols))) ++ if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols))) + return -EFAULT; +- kcontrols = compat_alloc_user_space(kp->count * sizeof(*kcontrols)); +- kp->controls = (__force struct v4l2_ext_control *)kcontrols; +- for (n = 0; n < kp->count; n++) { ++ if (aux_space < count * sizeof(*kcontrols)) ++ return -EFAULT; ++ kcontrols = aux_buf; ++ if (put_user((__force struct v4l2_ext_control *)kcontrols, ++ &kp->controls)) ++ return -EFAULT; ++ ++ for (n = 0; n < count; n++) { + u32 id; + + if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) + return -EFAULT; ++ + if (get_user(id, &kcontrols->id)) + return -EFAULT; ++ + if (ctrl_is_pointer(file, id)) { + void __user *s; + +@@ -701,43 +851,54 @@ static int get_v4l2_ext_controls32(struc + } + + static int put_v4l2_ext_controls32(struct file *file, +- struct v4l2_ext_controls *kp, ++ struct v4l2_ext_controls __user *kp, + struct v4l2_ext_controls32 __user *up) + { + struct v4l2_ext_control32 __user *ucontrols; +- struct v4l2_ext_control __user *kcontrols = +- (__force struct v4l2_ext_control __user *)kp->controls; +- int n = kp->count; ++ struct v4l2_ext_control __user *kcontrols; ++ u32 count; ++ u32 n; + compat_caddr_t p; + + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || +- put_user(kp->which, &up->which) || +- put_user(kp->count, &up->count) || +- put_user(kp->error_idx, &up->error_idx) || +- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) ++ assign_in_user(&up->which, &kp->which) || ++ get_user(count, &kp->count) || ++ put_user(count, &up->count) || ++ assign_in_user(&up->error_idx, &kp->error_idx) || ++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) || ++ get_user(kcontrols, &kp->controls)) + return -EFAULT; +- if (!kp->count) +- return 0; + ++ if (!count) ++ return 0; + if (get_user(p, &up->controls)) + return -EFAULT; + ucontrols = compat_ptr(p); +- if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols))) ++ if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols))) + return -EFAULT; + +- while (--n >= 0) { +- unsigned size = sizeof(*ucontrols); ++ for (n = 0; n < count; n++) { ++ unsigned int size = sizeof(*ucontrols); + u32 id; + +- if (get_user(id, &kcontrols->id)) ++ if (get_user(id, &kcontrols->id) || ++ put_user(id, &ucontrols->id) || ++ assign_in_user(&ucontrols->size, &kcontrols->size) || ++ copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2, ++ sizeof(ucontrols->reserved2))) + return -EFAULT; +- /* Do not modify the pointer when copying a pointer control. +- The contents of the pointer was changed, not the pointer +- itself. */ ++ ++ /* ++ * Do not modify the pointer when copying a pointer control. ++ * The contents of the pointer was changed, not the pointer ++ * itself. ++ */ + if (ctrl_is_pointer(file, id)) + size -= sizeof(ucontrols->value64); ++ + if (copy_in_user(ucontrols, kcontrols, size)) + return -EFAULT; ++ + ucontrols++; + kcontrols++; + } +@@ -757,17 +918,18 @@ struct v4l2_event32 { + __u32 reserved[8]; + }; + +-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) ++static int put_v4l2_event32(struct v4l2_event __user *kp, ++ struct v4l2_event32 __user *up) + { + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || +- put_user(kp->type, &up->type) || +- copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || +- put_user(kp->pending, &up->pending) || +- put_user(kp->sequence, &up->sequence) || +- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || +- put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || +- put_user(kp->id, &up->id) || +- copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) ++ assign_in_user(&up->type, &kp->type) || ++ copy_in_user(&up->u, &kp->u, sizeof(kp->u)) || ++ assign_in_user(&up->pending, &kp->pending) || ++ assign_in_user(&up->sequence, &kp->sequence) || ++ assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || ++ assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) || ++ assign_in_user(&up->id, &kp->id) || ++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) + return -EFAULT; + return 0; + } +@@ -780,31 +942,34 @@ struct v4l2_edid32 { + compat_caddr_t edid; + }; + +-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) ++static int get_v4l2_edid32(struct v4l2_edid __user *kp, ++ struct v4l2_edid32 __user *up) + { +- u32 tmp; ++ compat_uptr_t tmp; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || +- get_user(kp->pad, &up->pad) || +- get_user(kp->start_block, &up->start_block) || +- get_user(kp->blocks, &up->blocks) || ++ assign_in_user(&kp->pad, &up->pad) || ++ assign_in_user(&kp->start_block, &up->start_block) || ++ assign_in_user(&kp->blocks, &up->blocks) || + get_user(tmp, &up->edid) || +- copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) ++ put_user(compat_ptr(tmp), &kp->edid) || ++ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + return -EFAULT; +- kp->edid = (__force u8 *)compat_ptr(tmp); + return 0; + } + +-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) ++static int put_v4l2_edid32(struct v4l2_edid __user *kp, ++ struct v4l2_edid32 __user *up) + { +- u32 tmp = (u32)((unsigned long)kp->edid); ++ void *edid; + + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || +- put_user(kp->pad, &up->pad) || +- put_user(kp->start_block, &up->start_block) || +- put_user(kp->blocks, &up->blocks) || +- put_user(tmp, &up->edid) || +- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) ++ assign_in_user(&up->pad, &kp->pad) || ++ assign_in_user(&up->start_block, &kp->start_block) || ++ assign_in_user(&up->blocks, &kp->blocks) || ++ get_user(edid, &kp->edid) || ++ put_user(ptr_to_compat(edid), &up->edid) || ++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) + return -EFAULT; + return 0; + } +@@ -837,22 +1002,23 @@ static int put_v4l2_edid32(struct v4l2_e + #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32) + #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32) + ++static int alloc_userspace(unsigned int size, u32 aux_space, ++ void __user **up_native) ++{ ++ *up_native = compat_alloc_user_space(size + aux_space); ++ if (!*up_native) ++ return -ENOMEM; ++ if (clear_user(*up_native, size)) ++ return -EFAULT; ++ return 0; ++} ++ + static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + { +- union { +- struct v4l2_format v2f; +- struct v4l2_buffer v2b; +- struct v4l2_framebuffer v2fb; +- struct v4l2_input v2i; +- struct v4l2_standard v2s; +- struct v4l2_ext_controls v2ecs; +- struct v4l2_event v2ev; +- struct v4l2_create_buffers v2crt; +- struct v4l2_edid v2edid; +- unsigned long vx; +- int vi; +- } karg; + void __user *up = compat_ptr(arg); ++ void __user *up_native = NULL; ++ void __user *aux_buf; ++ u32 aux_space; + int compatible_arg = 1; + long err = 0; + +@@ -891,30 +1057,52 @@ static long do_video_ioctl(struct file * + case VIDIOC_STREAMOFF: + case VIDIOC_S_INPUT: + case VIDIOC_S_OUTPUT: +- err = get_user(karg.vi, (s32 __user *)up); ++ err = alloc_userspace(sizeof(unsigned int), 0, &up_native); ++ if (!err && assign_in_user((unsigned int __user *)up_native, ++ (compat_uint_t __user *)up)) ++ err = -EFAULT; + compatible_arg = 0; + break; + + case VIDIOC_G_INPUT: + case VIDIOC_G_OUTPUT: ++ err = alloc_userspace(sizeof(unsigned int), 0, &up_native); + compatible_arg = 0; + break; + + case VIDIOC_G_EDID: + case VIDIOC_S_EDID: +- err = get_v4l2_edid32(&karg.v2edid, up); ++ err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native); ++ if (!err) ++ err = get_v4l2_edid32(up_native, up); + compatible_arg = 0; + break; + + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: +- err = get_v4l2_format32(&karg.v2f, up); ++ err = bufsize_v4l2_format(up, &aux_space); ++ if (!err) ++ err = alloc_userspace(sizeof(struct v4l2_format), ++ aux_space, &up_native); ++ if (!err) { ++ aux_buf = up_native + sizeof(struct v4l2_format); ++ err = get_v4l2_format32(up_native, up, ++ aux_buf, aux_space); ++ } + compatible_arg = 0; + break; + + case VIDIOC_CREATE_BUFS: +- err = get_v4l2_create32(&karg.v2crt, up); ++ err = bufsize_v4l2_create(up, &aux_space); ++ if (!err) ++ err = alloc_userspace(sizeof(struct v4l2_create_buffers), ++ aux_space, &up_native); ++ if (!err) { ++ aux_buf = up_native + sizeof(struct v4l2_create_buffers); ++ err = get_v4l2_create32(up_native, up, ++ aux_buf, aux_space); ++ } + compatible_arg = 0; + break; + +@@ -922,36 +1110,63 @@ static long do_video_ioctl(struct file * + case VIDIOC_QUERYBUF: + case VIDIOC_QBUF: + case VIDIOC_DQBUF: +- err = get_v4l2_buffer32(&karg.v2b, up); ++ err = bufsize_v4l2_buffer(up, &aux_space); ++ if (!err) ++ err = alloc_userspace(sizeof(struct v4l2_buffer), ++ aux_space, &up_native); ++ if (!err) { ++ aux_buf = up_native + sizeof(struct v4l2_buffer); ++ err = get_v4l2_buffer32(up_native, up, ++ aux_buf, aux_space); ++ } + compatible_arg = 0; + break; + + case VIDIOC_S_FBUF: +- err = get_v4l2_framebuffer32(&karg.v2fb, up); ++ err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, ++ &up_native); ++ if (!err) ++ err = get_v4l2_framebuffer32(up_native, up); + compatible_arg = 0; + break; + + case VIDIOC_G_FBUF: ++ err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, ++ &up_native); + compatible_arg = 0; + break; + + case VIDIOC_ENUMSTD: +- err = get_v4l2_standard32(&karg.v2s, up); ++ err = alloc_userspace(sizeof(struct v4l2_standard), 0, ++ &up_native); ++ if (!err) ++ err = get_v4l2_standard32(up_native, up); + compatible_arg = 0; + break; + + case VIDIOC_ENUMINPUT: +- err = get_v4l2_input32(&karg.v2i, up); ++ err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native); ++ if (!err) ++ err = get_v4l2_input32(up_native, up); + compatible_arg = 0; + break; + + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: +- err = get_v4l2_ext_controls32(file, &karg.v2ecs, up); ++ err = bufsize_v4l2_ext_controls(up, &aux_space); ++ if (!err) ++ err = alloc_userspace(sizeof(struct v4l2_ext_controls), ++ aux_space, &up_native); ++ if (!err) { ++ aux_buf = up_native + sizeof(struct v4l2_ext_controls); ++ err = get_v4l2_ext_controls32(file, up_native, up, ++ aux_buf, aux_space); ++ } + compatible_arg = 0; + break; + case VIDIOC_DQEVENT: ++ err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native); + compatible_arg = 0; + break; + } +@@ -960,29 +1175,26 @@ static long do_video_ioctl(struct file * + + if (compatible_arg) + err = native_ioctl(file, cmd, (unsigned long)up); +- else { +- mm_segment_t old_fs = get_fs(); +- +- set_fs(KERNEL_DS); +- err = native_ioctl(file, cmd, (unsigned long)&karg); +- set_fs(old_fs); +- } ++ else ++ err = native_ioctl(file, cmd, (unsigned long)up_native); + + if (err == -ENOTTY) + return err; + +- /* Special case: even after an error we need to put the +- results back for these ioctls since the error_idx will +- contain information on which control failed. */ ++ /* ++ * Special case: even after an error we need to put the ++ * results back for these ioctls since the error_idx will ++ * contain information on which control failed. ++ */ + switch (cmd) { + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: +- if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) ++ if (put_v4l2_ext_controls32(file, up_native, up)) + err = -EFAULT; + break; + case VIDIOC_S_EDID: +- if (put_v4l2_edid32(&karg.v2edid, up)) ++ if (put_v4l2_edid32(up_native, up)) + err = -EFAULT; + break; + } +@@ -994,44 +1206,46 @@ static long do_video_ioctl(struct file * + case VIDIOC_S_OUTPUT: + case VIDIOC_G_INPUT: + case VIDIOC_G_OUTPUT: +- err = put_user(((s32)karg.vi), (s32 __user *)up); ++ if (assign_in_user((compat_uint_t __user *)up, ++ ((unsigned int __user *)up_native))) ++ err = -EFAULT; + break; + + case VIDIOC_G_FBUF: +- err = put_v4l2_framebuffer32(&karg.v2fb, up); ++ err = put_v4l2_framebuffer32(up_native, up); + break; + + case VIDIOC_DQEVENT: +- err = put_v4l2_event32(&karg.v2ev, up); ++ err = put_v4l2_event32(up_native, up); + break; + + case VIDIOC_G_EDID: +- err = put_v4l2_edid32(&karg.v2edid, up); ++ err = put_v4l2_edid32(up_native, up); + break; + + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: +- err = put_v4l2_format32(&karg.v2f, up); ++ err = put_v4l2_format32(up_native, up); + break; + + case VIDIOC_CREATE_BUFS: +- err = put_v4l2_create32(&karg.v2crt, up); ++ err = put_v4l2_create32(up_native, up); + break; + + case VIDIOC_PREPARE_BUF: + case VIDIOC_QUERYBUF: + case VIDIOC_QBUF: + case VIDIOC_DQBUF: +- err = put_v4l2_buffer32(&karg.v2b, up); ++ err = put_v4l2_buffer32(up_native, up); + break; + + case VIDIOC_ENUMSTD: +- err = put_v4l2_standard32(&karg.v2s, up); ++ err = put_v4l2_standard32(up_native, up); + break; + + case VIDIOC_ENUMINPUT: +- err = put_v4l2_input32(&karg.v2i, up); ++ err = put_v4l2_input32(up_native, up); + break; + } + return err; diff --git a/queue-4.14/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch b/queue-4.14/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch new file mode 100644 index 00000000000..be9094fc3d2 --- /dev/null +++ b/queue-4.14/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch @@ -0,0 +1,38 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:23 +0100 +Subject: media: v4l2-ioctl.c: don't copy back the result for -ENOTTY +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-3-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 +@@ -2892,8 +2892,11 @@ video_usercopy(struct file *file, unsign + + /* Handles IOCTL */ + err = func(file, cmd, parg); +- if (err == -ENOIOCTLCMD) ++ if (err == -ENOTTY || err == -ENOIOCTLCMD) { + err = -ENOTTY; ++ goto out; ++ } ++ + if (err == 0) { + if (cmd == VIDIOC_DQBUF) + trace_v4l2_dqbuf(video_devdata(file)->minor, parg); diff --git a/queue-4.14/media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch b/queue-4.14/media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch new file mode 100644 index 00000000000..a4f79d23dd9 --- /dev/null +++ b/queue-4.14/media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch @@ -0,0 +1,394 @@ +From foo@baz Wed Feb 14 20:54:11 CET 2018 +From: Hans Verkuil +Date: Wed, 14 Feb 2018 12:44:22 +0100 +Subject: media: v4l2-ioctl.c: use check_fmt for enum/g/s/try_fmt +To: stable@vger.kernel.org +Cc: linux-media@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214114434.26842-2-hverkuil@xs4all.nl> + +From: Hans Verkuil + +commit b2469c814fbc8f1f19676dd4912717b798df511e upstream. + +Don't duplicate the buffer type checks in enum/g/s/try_fmt. +The check_fmt function does that already. + +It is hard to keep the checks in sync for all these functions and +in fact the check for VBI was wrong in the _fmt functions as it +allowed SDR types as well. This caused a v4l2-compliance failure +for /dev/swradio0 using vivid. + +This simplifies the code and keeps the check in one place and +fixes the SDR/VBI bug. + +Signed-off-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-ioctl.c | 140 +++++++++++++---------------------- + 1 file changed, 54 insertions(+), 86 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1308,52 +1308,50 @@ static int v4l_enum_fmt(const struct v4l + struct file *file, void *fh, void *arg) + { + struct v4l2_fmtdesc *p = arg; +- struct video_device *vfd = video_devdata(file); +- bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; +- bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; +- bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; +- bool is_rx = vfd->vfl_dir != VFL_DIR_TX; +- bool is_tx = vfd->vfl_dir != VFL_DIR_RX; +- int ret = -EINVAL; ++ int ret = check_fmt(file, p->type); ++ ++ if (ret) ++ return ret; ++ ret = -EINVAL; + + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: +- if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_enum_fmt_vid_cap)) ++ if (unlikely(!ops->vidioc_enum_fmt_vid_cap)) + break; + ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_cap_mplane)) ++ if (unlikely(!ops->vidioc_enum_fmt_vid_cap_mplane)) + break; + ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_overlay)) ++ if (unlikely(!ops->vidioc_enum_fmt_vid_overlay)) + break; + ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, arg); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_enum_fmt_vid_out)) ++ if (unlikely(!ops->vidioc_enum_fmt_vid_out)) + break; + ret = ops->vidioc_enum_fmt_vid_out(file, fh, arg); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_enum_fmt_vid_out_mplane)) ++ if (unlikely(!ops->vidioc_enum_fmt_vid_out_mplane)) + break; + ret = ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg); + break; + case V4L2_BUF_TYPE_SDR_CAPTURE: +- if (unlikely(!is_rx || !is_sdr || !ops->vidioc_enum_fmt_sdr_cap)) ++ if (unlikely(!ops->vidioc_enum_fmt_sdr_cap)) + break; + ret = ops->vidioc_enum_fmt_sdr_cap(file, fh, arg); + break; + case V4L2_BUF_TYPE_SDR_OUTPUT: +- if (unlikely(!is_tx || !is_sdr || !ops->vidioc_enum_fmt_sdr_out)) ++ if (unlikely(!ops->vidioc_enum_fmt_sdr_out)) + break; + ret = ops->vidioc_enum_fmt_sdr_out(file, fh, arg); + break; + case V4L2_BUF_TYPE_META_CAPTURE: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_meta_cap)) ++ if (unlikely(!ops->vidioc_enum_fmt_meta_cap)) + break; + ret = ops->vidioc_enum_fmt_meta_cap(file, fh, arg); + break; +@@ -1367,13 +1365,10 @@ static int v4l_g_fmt(const struct v4l2_i + struct file *file, void *fh, void *arg) + { + struct v4l2_format *p = arg; +- struct video_device *vfd = video_devdata(file); +- bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; +- bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; +- bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; +- bool is_rx = vfd->vfl_dir != VFL_DIR_TX; +- bool is_tx = vfd->vfl_dir != VFL_DIR_RX; +- int ret; ++ int ret = check_fmt(file, p->type); ++ ++ if (ret) ++ return ret; + + /* + * fmt can't be cleared for these overlay types due to the 'clips' +@@ -1401,7 +1396,7 @@ static int v4l_g_fmt(const struct v4l2_i + + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: +- if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_g_fmt_vid_cap)) ++ if (unlikely(!ops->vidioc_g_fmt_vid_cap)) + break; + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg); +@@ -1409,23 +1404,15 @@ static int v4l_g_fmt(const struct v4l2_i + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + return ret; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_cap_mplane)) +- break; + return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OVERLAY: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_overlay)) +- break; + return ops->vidioc_g_fmt_vid_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VBI_CAPTURE: +- if (unlikely(!is_rx || is_vid || !ops->vidioc_g_fmt_vbi_cap)) +- break; + return ops->vidioc_g_fmt_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: +- if (unlikely(!is_rx || is_vid || !ops->vidioc_g_fmt_sliced_vbi_cap)) +- break; + return ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out)) ++ if (unlikely(!ops->vidioc_g_fmt_vid_out)) + break; + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + ret = ops->vidioc_g_fmt_vid_out(file, fh, arg); +@@ -1433,32 +1420,18 @@ static int v4l_g_fmt(const struct v4l2_i + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + return ret; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_mplane)) +- break; + return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_overlay)) +- break; + return ops->vidioc_g_fmt_vid_out_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VBI_OUTPUT: +- if (unlikely(!is_tx || is_vid || !ops->vidioc_g_fmt_vbi_out)) +- break; + return ops->vidioc_g_fmt_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: +- if (unlikely(!is_tx || is_vid || !ops->vidioc_g_fmt_sliced_vbi_out)) +- break; + return ops->vidioc_g_fmt_sliced_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SDR_CAPTURE: +- if (unlikely(!is_rx || !is_sdr || !ops->vidioc_g_fmt_sdr_cap)) +- break; + return ops->vidioc_g_fmt_sdr_cap(file, fh, arg); + case V4L2_BUF_TYPE_SDR_OUTPUT: +- if (unlikely(!is_tx || !is_sdr || !ops->vidioc_g_fmt_sdr_out)) +- break; + return ops->vidioc_g_fmt_sdr_out(file, fh, arg); + case V4L2_BUF_TYPE_META_CAPTURE: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_meta_cap)) +- break; + return ops->vidioc_g_fmt_meta_cap(file, fh, arg); + } + return -EINVAL; +@@ -1484,12 +1457,10 @@ static int v4l_s_fmt(const struct v4l2_i + { + struct v4l2_format *p = arg; + struct video_device *vfd = video_devdata(file); +- bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; +- bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; +- bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; +- bool is_rx = vfd->vfl_dir != VFL_DIR_TX; +- bool is_tx = vfd->vfl_dir != VFL_DIR_RX; +- int ret; ++ int ret = check_fmt(file, p->type); ++ ++ if (ret) ++ return ret; + + ret = v4l_enable_media_source(vfd); + if (ret) +@@ -1498,37 +1469,37 @@ static int v4l_s_fmt(const struct v4l2_i + + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: +- if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_s_fmt_vid_cap)) ++ if (unlikely(!ops->vidioc_s_fmt_vid_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.pix); + ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg); + /* just in case the driver zeroed it again */ + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; +- if (is_tch) ++ if (vfd->vfl_type == VFL_TYPE_TOUCH) + v4l_pix_format_touch(&p->fmt.pix); + return ret; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap_mplane)) ++ if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane)) + break; + CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OVERLAY: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_overlay)) ++ if (unlikely(!ops->vidioc_s_fmt_vid_overlay)) + break; + CLEAR_AFTER_FIELD(p, fmt.win); + return ops->vidioc_s_fmt_vid_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VBI_CAPTURE: +- if (unlikely(!is_rx || is_vid || !ops->vidioc_s_fmt_vbi_cap)) ++ if (unlikely(!ops->vidioc_s_fmt_vbi_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.vbi); + return ops->vidioc_s_fmt_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: +- if (unlikely(!is_rx || is_vid || !ops->vidioc_s_fmt_sliced_vbi_cap)) ++ if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.sliced); + return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out)) ++ if (unlikely(!ops->vidioc_s_fmt_vid_out)) + break; + CLEAR_AFTER_FIELD(p, fmt.pix); + ret = ops->vidioc_s_fmt_vid_out(file, fh, arg); +@@ -1536,37 +1507,37 @@ static int v4l_s_fmt(const struct v4l2_i + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + return ret; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_mplane)) ++ if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane)) + break; + CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_overlay)) ++ if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay)) + break; + CLEAR_AFTER_FIELD(p, fmt.win); + return ops->vidioc_s_fmt_vid_out_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VBI_OUTPUT: +- if (unlikely(!is_tx || is_vid || !ops->vidioc_s_fmt_vbi_out)) ++ if (unlikely(!ops->vidioc_s_fmt_vbi_out)) + break; + CLEAR_AFTER_FIELD(p, fmt.vbi); + return ops->vidioc_s_fmt_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: +- if (unlikely(!is_tx || is_vid || !ops->vidioc_s_fmt_sliced_vbi_out)) ++ if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out)) + break; + CLEAR_AFTER_FIELD(p, fmt.sliced); + return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SDR_CAPTURE: +- if (unlikely(!is_rx || !is_sdr || !ops->vidioc_s_fmt_sdr_cap)) ++ if (unlikely(!ops->vidioc_s_fmt_sdr_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.sdr); + return ops->vidioc_s_fmt_sdr_cap(file, fh, arg); + case V4L2_BUF_TYPE_SDR_OUTPUT: +- if (unlikely(!is_tx || !is_sdr || !ops->vidioc_s_fmt_sdr_out)) ++ if (unlikely(!ops->vidioc_s_fmt_sdr_out)) + break; + CLEAR_AFTER_FIELD(p, fmt.sdr); + return ops->vidioc_s_fmt_sdr_out(file, fh, arg); + case V4L2_BUF_TYPE_META_CAPTURE: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_meta_cap)) ++ if (unlikely(!ops->vidioc_s_fmt_meta_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.meta); + return ops->vidioc_s_fmt_meta_cap(file, fh, arg); +@@ -1578,19 +1549,16 @@ static int v4l_try_fmt(const struct v4l2 + struct file *file, void *fh, void *arg) + { + struct v4l2_format *p = arg; +- struct video_device *vfd = video_devdata(file); +- bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; +- bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; +- bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; +- bool is_rx = vfd->vfl_dir != VFL_DIR_TX; +- bool is_tx = vfd->vfl_dir != VFL_DIR_RX; +- int ret; ++ int ret = check_fmt(file, p->type); ++ ++ if (ret) ++ return ret; + + v4l_sanitize_format(p); + + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: +- if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_try_fmt_vid_cap)) ++ if (unlikely(!ops->vidioc_try_fmt_vid_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.pix); + ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg); +@@ -1598,27 +1566,27 @@ static int v4l_try_fmt(const struct v4l2 + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + return ret; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_cap_mplane)) ++ if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane)) + break; + CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OVERLAY: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_overlay)) ++ if (unlikely(!ops->vidioc_try_fmt_vid_overlay)) + break; + CLEAR_AFTER_FIELD(p, fmt.win); + return ops->vidioc_try_fmt_vid_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VBI_CAPTURE: +- if (unlikely(!is_rx || is_vid || !ops->vidioc_try_fmt_vbi_cap)) ++ if (unlikely(!ops->vidioc_try_fmt_vbi_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.vbi); + return ops->vidioc_try_fmt_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: +- if (unlikely(!is_rx || is_vid || !ops->vidioc_try_fmt_sliced_vbi_cap)) ++ if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.sliced); + return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out)) ++ if (unlikely(!ops->vidioc_try_fmt_vid_out)) + break; + CLEAR_AFTER_FIELD(p, fmt.pix); + ret = ops->vidioc_try_fmt_vid_out(file, fh, arg); +@@ -1626,37 +1594,37 @@ static int v4l_try_fmt(const struct v4l2 + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + return ret; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out_mplane)) ++ if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane)) + break; + CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: +- if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out_overlay)) ++ if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay)) + break; + CLEAR_AFTER_FIELD(p, fmt.win); + return ops->vidioc_try_fmt_vid_out_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VBI_OUTPUT: +- if (unlikely(!is_tx || is_vid || !ops->vidioc_try_fmt_vbi_out)) ++ if (unlikely(!ops->vidioc_try_fmt_vbi_out)) + break; + CLEAR_AFTER_FIELD(p, fmt.vbi); + return ops->vidioc_try_fmt_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: +- if (unlikely(!is_tx || is_vid || !ops->vidioc_try_fmt_sliced_vbi_out)) ++ if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out)) + break; + CLEAR_AFTER_FIELD(p, fmt.sliced); + return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SDR_CAPTURE: +- if (unlikely(!is_rx || !is_sdr || !ops->vidioc_try_fmt_sdr_cap)) ++ if (unlikely(!ops->vidioc_try_fmt_sdr_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.sdr); + return ops->vidioc_try_fmt_sdr_cap(file, fh, arg); + case V4L2_BUF_TYPE_SDR_OUTPUT: +- if (unlikely(!is_tx || !is_sdr || !ops->vidioc_try_fmt_sdr_out)) ++ if (unlikely(!ops->vidioc_try_fmt_sdr_out)) + break; + CLEAR_AFTER_FIELD(p, fmt.sdr); + return ops->vidioc_try_fmt_sdr_out(file, fh, arg); + case V4L2_BUF_TYPE_META_CAPTURE: +- if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_meta_cap)) ++ if (unlikely(!ops->vidioc_try_fmt_meta_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.meta); + return ops->vidioc_try_fmt_meta_cap(file, fh, arg); diff --git a/queue-4.14/series b/queue-4.14/series index ea02f0f3ec6..15f5356a3fe 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -117,3 +117,16 @@ crypto-mcryptd-pass-through-absence-of-setkey.patch crypto-poly1305-remove-setkey-method.patch crypto-hash-annotate-algorithms-taking-optional-key.patch crypto-hash-prevent-using-keyed-hashes-without-setting-key.patch +media-v4l2-ioctl.c-use-check_fmt-for-enum-g-s-try_fmt.patch +media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch +media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch +media-v4l2-compat-ioctl32.c-fix-the-indentation.patch +media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch +media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch +media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch +media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch +media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch +media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch +media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch +media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch +media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch -- 2.47.3