[PATCH for v4.4 00/14] v4l2-compat-ioctl32.c: remove set_fs(KERNEL_DS)
From: Hans VerkuilThis patch series fixes a number of bugs and culminates in the removal of the set_fs(KERNEL_DS) call in v4l2-compat-ioctl32.c. This was tested with a VM running 4.4, the vivid driver (since that emulates almost all V4L2 ioctls that need to pass through v4l2-compat-ioctl32.c) and a 32-bit v4l2-compliance utility since that exercises almost all ioctls as well. Combined this gives good test coverage. Most of the v4l2-compat-ioctl32.c do cleanups and fix subtle issues that v4l2-compliance complained about. The purpose is to 1) make it easy to verify that the final patch didn't introduce errors by first eliminating errors caused by other known bugs, and 2) keep the final patch at least somewhat readable. Regards, Hans Daniel Mentz (2): media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic Hans Verkuil (11): media: v4l2-ioctl.c: don't copy back the result for -ENOTTY media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF media: v4l2-compat-ioctl32.c: fix the indentation media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 media: v4l2-compat-ioctl32.c: avoid sizeof(type) media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors Ricardo Ribalda Delgado (1): vb2: V4L2_BUF_FLAG_DONE is set after DQBUF drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1023 +++-- drivers/media/v4l2-core/v4l2-ioctl.c |5 +- drivers/media/v4l2-core/videobuf2-v4l2.c |6 + 3 files changed, 624 insertions(+), 410 deletions(-) -- 2.15.1
[PATCH for v4.4 14/14] media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
From: Daniel Mentzcommit 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, >clipcount) || put_user(clipcount, >clipcount)) return -EFAULT; Notes from hans.verk...@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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 744 +- 1 file changed, 483 insertions(+), 261 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 4b6ea1b20d2a..943f90e392a7 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -22,6 +22,14 @@ #include #include +/* Use the same argument order as copy_in_user */ +#define assign_in_user(to, from) \ +({ \ + typeof(*from) __assign_tmp; \ + \ + get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \ +}) + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = -ENOIOCTLCMD; @@ -35,12 +43,12 @@ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct v4l2_clip32 { struct v4l2_rectc; - compat_caddr_t next; + compat_caddr_t next; }; struct v4l2_window32 { struct v4l2_rectw; - __u32 field; /* enum v4l2_field */ + __u32 field; /* enum v4l2_field */ __u32 chromakey; compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; @@ -48,37 +56,41 @@ struct v4l2_window32 { __u8global_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
[PATCH for v4.4 10/14] media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha
From: Daniel Mentzcommit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream. Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output overlays.") added the field global_alpha to struct v4l2_window but did not update the compat layer accordingly. This change adds global_alpha to struct v4l2_window32 and copies the value for global_alpha back and forth. Signed-off-by: Daniel Mentz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 0c3949a00570..e55231a12f00 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -45,6 +45,7 @@ struct v4l2_window32 { compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; compat_caddr_t bitmap; + __u8global_alpha; }; static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) @@ -53,7 +54,8 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user copy_from_user(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount)) + get_user(kp->clipcount, >clipcount) || + get_user(kp->global_alpha, >global_alpha)) return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; @@ -86,7 +88,8 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (copy_to_user(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount)) + put_user(kp->clipcount, >clipcount) || + put_user(kp->global_alpha, >global_alpha)) return -EFAULT; return 0; } -- 2.15.1
[PATCH for v4.4 13/14] media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index c8635e4f91ef..4b6ea1b20d2a 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -956,6 +956,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar 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. */ -- 2.15.1
[PATCH for v4.4 02/14] vb2: V4L2_BUF_FLAG_DONE is set after DQBUF
From: Ricardo Ribaldacommit 3171cc2b4eb9831ab4df1d80d0410a945b8bc84e upstream. According to the doc, V4L2_BUF_FLAG_DONE is cleared after DQBUF: V4L2_BUF_FLAG_DONE 0x0004 ... After calling the VIDIOC_QBUF or VIDIOC_DQBUF it is always cleared ... Unfortunately, it seems that videobuf2 keeps it set after DQBUF. This can be tested with vivid and dev_debug: [257604.338082] video1: VIDIOC_DQBUF: 71:33:25.00260479 index=3, type=vid-cap, flags=0x2004, field=none, sequence=163, memory=userptr, bytesused=460800, offset/userptr=0x344b000, length=460800 This patch forces FLAG_DONE to 0 after calling DQBUF. Reported-by: Dimitrios Katsaros Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-v4l2.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c index 6c441be8f893..bf23234d957e 100644 --- a/drivers/media/v4l2-core/videobuf2-v4l2.c +++ b/drivers/media/v4l2-core/videobuf2-v4l2.c @@ -593,6 +593,12 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, b->flags & V4L2_BUF_FLAG_LAST) q->last_buffer_dequeued = true; + /* +* After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be +* cleared. +*/ + b->flags &= ~V4L2_BUF_FLAG_DONE; + return ret; } -- 2.15.1
[PATCH for v4.4 07/14] media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 47 --- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index ace1d7b050a5..af197980ab8e 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -299,19 +299,24 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ 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(>m.mem_offset, >m.mem_offset, +sizeof(up32->m.mem_offset))) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: if (get_user(p, >m.userptr)) return -EFAULT; up_pln = compat_ptr(p); if (put_user((unsigned long)up_pln, >m.userptr)) return -EFAULT; - } else if (memory == V4L2_MEMORY_DMABUF) { + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(>m.fd, >m.fd, sizeof(up32->m.fd))) return -EFAULT; - } else { - if (copy_in_user(>m.mem_offset, >m.mem_offset, -sizeof(up32->m.mem_offset))) - return -EFAULT; + break; } return 0; @@ -320,22 +325,32 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ 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(>data_offset, >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(>m.mem_offset, >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, >m.userptr) || + put_user((compat_ulong_t)ptr_to_compat((__force void *)p), +>m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(>m.fd, >m.fd, sizeof(up->m.fd))) return -EFAULT; + break; + } return 0; } @@ -395,6 +410,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (get_user(kp->m.offset, >m.offset)) return -EFAULT; break; @@ -408,10 +424,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, >m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (get_user(kp->m.fd, >m.fd)) return -EFAULT; @@ -468,6 +480,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (put_user(kp->m.offset, >m.offset)) return -EFAULT; break; @@ -475,10 +488,6 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
[PATCH for v4.4 06/14] media: v4l2-compat-ioctl32.c: avoid sizeof(type)
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 77 +-- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 5ebc11476f63..ace1d7b050a5 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -47,7 +47,7 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || @@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (get_user(p, >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(>c, >c, sizeof(uclips->c))) @@ -157,14 +157,14 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us 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(>format, >format); @@ -208,14 +208,14 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32))) + if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; return __put_v4l2_format32(kp, up); } static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; @@ -234,7 +234,7 @@ struct v4l2_standard32 { static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->index, >index)) return -EFAULT; return 0; @@ -242,13 +242,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 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, >index) || put_user(kp->id, >id) || - copy_to_user(up->name, kp->name, 24) || + copy_to_user(up->name, kp->name, sizeof(up->name)) || copy_to_user(>frameperiod, >frameperiod, sizeof(kp->frameperiod)) || put_user(kp->framelines, >framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return 0; } @@ -296,7 +296,7 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(>data_offset, >data_offset, -
[PATCH for v4.4 05/14] media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 104 +- 1 file changed, 20 insertions(+), 84 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index c849b67b98df..5ebc11476f63 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -89,78 +89,6 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return 0; } -static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, -struct v4l2_pix_format_mplane __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, -struct v4l2_pix_format_mplane __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format))) - return -EFAULT; - return 0; -} - struct v4l2_format32 { __u32 type; /* enum v4l2_buf_type */ union { @@ -199,23 +127,27 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(>fmt.pix, >fmt.pix); + return copy_from_user(>fmt.pix, >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(>fmt.pix_mp, - >fmt.pix_mp); + return copy_from_user(>fmt.pix_mp, >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(>fmt.win, >fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(>fmt.vbi, >fmt.vbi); + return copy_from_user(>fmt.vbi, >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(>fmt.sliced, >fmt.sliced); + return copy_from_user(>fmt.sliced, >fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; case
[PATCH for v4.4 03/14] media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 4379b949bb93..f47a30b89281 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -1022,6 +1022,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_create32(, up); break; + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: -- 2.15.1
[PATCH for v4.4 12/14] media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 1 file changed, 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 84fb4c54b101..c8635e4f91ef 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -175,8 +175,6 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_from_user(>fmt.sdr, >fmt.sdr, sizeof(kp->fmt.sdr)) ? -EFAULT : 0; default: - pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } @@ -226,8 +224,6 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_to_user(>fmt.sdr, >fmt.sdr, sizeof(kp->fmt.sdr)) ? -EFAULT : 0; default: - pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } -- 2.15.1
[PATCH for v4.4 11/14] media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 ++- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index e55231a12f00..84fb4c54b101 100644 --- 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(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || @@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user 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, >clips)) + n = kp->clipcount; + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (n--) { + if (copy_in_user(>c, >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(>c, >c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, >next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else - kp->clips = NULL; + if (put_user(n ? kclips + 1 : NULL, >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(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || put_user(kp->clipcount, >clipcount) || put_user(kp->global_alpha, >global_alpha)) return -EFAULT; + + if (!kp->clipcount) + return 0; + + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + while (n--) { + if (copy_in_user(>c, >c, sizeof(uclips->c))) + return -EFAULT; + uclips++; + kclips++; + } return 0; } -- 2.15.1
[PATCH for v4.4 04/14] media: v4l2-compat-ioctl32.c: fix the indentation
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 208 +- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index f47a30b89281..c849b67b98df 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -48,11 +48,11 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || - copy_from_user(>w, >w, sizeof(up->w)) || - get_user(kp->field, >field) || - get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount)) - return -EFAULT; + copy_from_user(>w, >w, sizeof(up->w)) || + get_user(kp->field, >field) || + get_user(kp->chromakey, >chromakey) || + get_user(kp->clipcount, >clipcount)) + return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; if (kp->clipcount) { @@ -82,10 +82,10 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (copy_to_user(>w, >w, sizeof(kp->w)) || - put_user(kp->field, >field) || - put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount)) - return -EFAULT; + put_user(kp->field, >field) || + put_user(kp->chromakey, >chromakey) || + put_user(kp->clipcount, >clipcount)) + return -EFAULT; return 0; } @@ -97,7 +97,7 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) +struct v4l2_pix_format_mplane __user *up) { if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -112,7 +112,7 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) +struct v4l2_pix_format_mplane __user *up) { if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -218,7 +218,7 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return get_v4l2_sdr_format(>fmt.sdr, >fmt.sdr); default: pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -265,7 +265,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return put_v4l2_sdr_format(>fmt.sdr, >fmt.sdr); default: pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -299,7 +299,7 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 { /* 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, >index)) + get_user(kp->index, >index)) return -EFAULT; return 0; } @@ -307,13 +307,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 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, >index) || - put_user(kp->id, >id) || - copy_to_user(up->name, kp->name, 24) || - copy_to_user(>frameperiod, >frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, >framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) - return
[PATCH for v4.4 01/14] media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-ioctl.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 7486af2c8ae4..5e2a7e59f578 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2783,8 +2783,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, /* 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); -- 2.15.1
[PATCH for v3.2 08/12] media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha
From: Daniel Mentzcommit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream. Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output overlays.") added the field global_alpha to struct v4l2_window but did not update the compat layer accordingly. This change adds global_alpha to struct v4l2_window32 and copies the value for global_alpha back and forth. Signed-off-by: Daniel Mentz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-compat-ioctl32.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 925271c25177..a7b71a256d56 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -46,6 +46,7 @@ struct v4l2_window32 { compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; compat_caddr_t bitmap; + __u8global_alpha; }; static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) @@ -54,7 +55,8 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user copy_from_user(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount)) + get_user(kp->clipcount, >clipcount) || + get_user(kp->global_alpha, >global_alpha)) return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; @@ -87,7 +89,8 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (copy_to_user(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount)) + put_user(kp->clipcount, >clipcount) || + put_user(kp->global_alpha, >global_alpha)) return -EFAULT; return 0; } -- 2.15.1
[PATCH for v3.2 04/12] media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
From: Hans Verkuilcommit 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 --- drivers/media/video/v4l2-compat-ioctl32.c | 94 +++ 1 file changed, 21 insertions(+), 73 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index e35142d9781b..4d0901573860 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -89,64 +89,6 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return 0; } -static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, -struct v4l2_pix_format_mplane __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, -struct v4l2_pix_format_mplane __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - struct v4l2_format32 { enum v4l2_buf_type type; union { @@ -184,20 +126,23 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(>fmt.pix, >fmt.pix); + return copy_from_user(>fmt.pix, >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(>fmt.pix_mp, - >fmt.pix_mp); + return copy_from_user(>fmt.pix_mp, >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(>fmt.win, >fmt.win); + return get_v4l2_window32(>fmt.win, >fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(>fmt.vbi, >fmt.vbi); + return copy_from_user(>fmt.vbi, >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(>fmt.sliced, >fmt.sliced); + return copy_from_user(>fmt.sliced, >fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; case V4L2_BUF_TYPE_PRIVATE: if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data))) return -EFAULT; @@ -229,20 +174,23 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return put_v4l2_pix_format(>fmt.pix, >fmt.pix); + return
[PATCH for v3.2 12/12] media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
From: Daniel Mentzcommit 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, >clipcount) || put_user(clipcount, >clipcount)) return -EFAULT; Notes from hans.verk...@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 --- drivers/media/video/Makefile | 7 +- drivers/media/video/v4l2-compat-ioctl32.c | 738 +++--- 2 files changed, 481 insertions(+), 264 deletions(-) diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 117f9c4b4cb9..aa1e164cfb87 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -13,12 +13,13 @@ omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ v4l2-event.o v4l2-ctrls.o v4l2-subdev.o +ifeq ($(CONFIG_COMPAT),y) + videodev-objs += v4l2-compat-ioctl32.o +endif + # V4L2 core modules obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o -ifeq ($(CONFIG_COMPAT),y) - obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o -endif obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 7f0eeb8a4d3f..b4f19238c746 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -23,6 +23,14 @@ #ifdef CONFIG_COMPAT +/* 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; @@ -36,12 +44,12 @@ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct v4l2_clip32 { struct v4l2_rectc; - compat_caddr_t next; + compat_caddr_t next; }; struct v4l2_window32 { struct v4l2_rectw;
[PATCH for v3.2 03/12] media: v4l2-compat-ioctl32.c: fix the indentation
From: Hans Verkuilcommit 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 --- drivers/media/video/v4l2-compat-ioctl32.c | 198 +++--- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 9c4a7c7d3534..e35142d9781b 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -48,11 +48,11 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || - copy_from_user(>w, >w, sizeof(up->w)) || - get_user(kp->field, >field) || - get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount)) - return -EFAULT; + copy_from_user(>w, >w, sizeof(up->w)) || + get_user(kp->field, >field) || + get_user(kp->chromakey, >chromakey) || + get_user(kp->clipcount, >clipcount)) + return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; if (kp->clipcount) { @@ -82,10 +82,10 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (copy_to_user(>w, >w, sizeof(kp->w)) || - put_user(kp->field, >field) || - put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount)) - return -EFAULT; + put_user(kp->field, >field) || + put_user(kp->chromakey, >chromakey) || + put_user(kp->clipcount, >clipcount)) + return -EFAULT; return 0; } @@ -97,7 +97,7 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) +struct v4l2_pix_format_mplane __user *up) { if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -112,7 +112,7 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } 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; @@ -204,7 +204,7 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return 0; default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -249,7 +249,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return 0; default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -257,7 +257,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || - put_user(kp->type, >type)) + put_user(kp->type, >type)) return -EFAULT; return __put_v4l2_format32(kp, up); } @@ -266,7 +266,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_ { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) - return -EFAULT; + return -EFAULT; return __put_v4l2_format32(>format, >format); } @@ -283,7 +283,7 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 { /* 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, >index)) +
[PATCH for v3.2 02/12] media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
From: Hans Verkuilcommit 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 --- drivers/media/video/v4l2-compat-ioctl32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 2671959f01bb..9c4a7c7d3534 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -920,6 +920,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_create32(, up); break; + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: -- 2.15.1
[PATCH for v3.2 06/12] media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
From: Hans Verkuilcommit 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 --- drivers/media/video/v4l2-compat-ioctl32.c | 30 ++ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index e2dee29eaaa5..7477feff92b1 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -293,16 +293,20 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, 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(>m.mem_offset, >m.mem_offset, +sizeof(up32->m.mem_offset))) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: if (get_user(p, >m.userptr)) return -EFAULT; up_pln = compat_ptr(p); if (put_user((unsigned long)up_pln, >m.userptr)) return -EFAULT; - } else { - if (copy_in_user(>m.mem_offset, >m.mem_offset, -sizeof(up32->m.mem_offset))) - return -EFAULT; + break; } return 0; @@ -311,17 +315,27 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, enum v4l2_memory memory) { + unsigned long p; + if (copy_in_user(up32, up, 2 * sizeof(__u32)) || copy_in_user(>data_offset, >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(>m.mem_offset, >m.mem_offset, sizeof(up->m.mem_offset))) return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: + if (get_user(p, >m.userptr) || + put_user((compat_ulong_t)ptr_to_compat((__force void *)p), +>m.userptr)) + return -EFAULT; + break; + } return 0; } -- 2.15.1
[PATCH for v3.2 07/12] media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
From: Hans Verkuilcommit 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 --- drivers/media/video/v4l2-compat-ioctl32.c | 51 +++ 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 7477feff92b1..925271c25177 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include #ifdef CONFIG_COMPAT @@ -568,24 +571,32 @@ 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) +/* Return true if this control is a pointer type. */ +static inline bool ctrl_is_pointer(struct file *file, u32 id) { - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; + struct video_device *vdev = video_devdata(file); + struct v4l2_fh *fh = NULL; + struct v4l2_ctrl_handler *hdl = NULL; + + if (test_bit(V4L2_FL_USES_V4L2_FH, >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->type == V4L2_CTRL_TYPE_STRING; } + return false; } -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; @@ -613,7 +624,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext while (--n >= 0) { if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) return -EFAULT; - if (ctrl_is_pointer(kcontrols->id)) { + if (ctrl_is_pointer(file, kcontrols->id)) { void __user *s; if (get_user(p, >string)) @@ -628,7 +639,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext 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 = kp->controls; @@ -656,7 +669,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext /* 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(kcontrols->id)) + if (ctrl_is_pointer(file, kcontrols->id)) size -= sizeof(ucontrols->value64); if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; @@ -819,7 +832,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(, up); + err = get_v4l2_ext_controls32(file, , up); compatible_arg = 0; break; case VIDIOC_DQEVENT: @@ -846,7 +859,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS:
[PATCH for v3.2 09/12] media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
From: Hans Verkuilcommit 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 --- drivers/media/video/v4l2-compat-ioctl32.c | 59 +-- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index a7b71a256d56..6c3e15f7703e 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -51,6 +51,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(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || @@ -60,38 +65,54 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user 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, >clips)) + n = kp->clipcount; + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (n--) { + if (copy_in_user(>c, >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(>c, >c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, >next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else - kp->clips = NULL; + if (put_user(n ? kclips + 1 : NULL, >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(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || put_user(kp->clipcount, >clipcount) || put_user(kp->global_alpha, >global_alpha)) return -EFAULT; + + if (!kp->clipcount) + return 0; + + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + while (n--) { + if (copy_in_user(>c, >c, sizeof(uclips->c))) + return -EFAULT; + uclips++; + kclips++; + } return 0; } -- 2.15.1
[PATCH for v3.2 00/12] v4l2-compat-ioctl32.c: remove set_fs(KERNEL_DS)
From: Hans VerkuilThis patch series fixes a number of bugs and culminates in the removal of the set_fs(KERNEL_DS) call in v4l2-compat-ioctl32.c. This was tested with a VM running 3.2, the vivi driver (a poor substitute for the much improved vivid driver that's available in later kernels, but it's the best I had) since that emulates the more common V4L2 ioctls that need to pass through v4l2-compat-ioctl32.c) and the 32-bit v4l2-compliance + 32-bit v4l2-ctl utilities that together exercised the most common ioctls. Most of the v4l2-compat-ioctl32.c do cleanups and fix subtle issues that v4l2-compliance complained about. The purpose is to 1) make it easy to verify that the final patch didn't introduce errors by first eliminating errors caused by other known bugs, and 2) keep the final patch at least somewhat readable. Regards, Hans Daniel Mentz (2): media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic Hans Verkuil (10): media: v4l2-ioctl.c: don't copy back the result for -ENOTTY media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF media: v4l2-compat-ioctl32.c: fix the indentation media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 media: v4l2-compat-ioctl32.c: avoid sizeof(type) media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors drivers/media/video/Makefile | 7 +- drivers/media/video/v4l2-compat-ioctl32.c | 966 ++ drivers/media/video/v4l2-ioctl.c | 6 +- 3 files changed, 597 insertions(+), 382 deletions(-) -- 2.15.1
[PATCH for v3.2 11/12] media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
From: Hans Verkuilcommit 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 --- drivers/media/video/v4l2-compat-ioctl32.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 44e8a8d15558..7f0eeb8a4d3f 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -872,6 +872,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar 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. */ -- 2.15.1
[PATCH for v3.2 10/12] media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
From: Hans Verkuilcommit 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 --- drivers/media/video/v4l2-compat-ioctl32.c | 4 1 file changed, 4 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 6c3e15f7703e..44e8a8d15558 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -175,8 +175,6 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return -EFAULT; return 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } @@ -223,8 +221,6 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return -EFAULT; return 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } -- 2.15.1
Re: exposing a large-ish calibration table through V4L2?
Hi Florian, On 14/02/18 13:09, Florian Echtler wrote: > Hello Hans, > > I've picked up work on the sur40 driver again recently. There is one major > feature left that is currently unsupported by the Linux driver, which is the > hardware-based calibration. > > The internal device memory contains a table with two bytes for each sensor > pixel > (i.e. 960x540x2 = 1036800 bytes) that basically provide individual black and > white levels per-pixel that are used in preprocessing. The table can either be > set externally, or the sensor can be covered with a black/white surface and a > custom command triggers an internal calibration. > > AFAICT the usual V4L2 controls are unsuitable for this sort of data; do you > have > any suggestions on how to approach this? Maybe something like a custom IOCTL? So the table has a fixed size? You can use array controls for that, a V4L2_CTRL_TYPE_U16 in a two-dimensional array would do it. See https://hverkuil.home.xs4all.nl/spec/uapi/v4l/vidioc-queryctrl.html for more information on how this works. Regards, Hans
media: v4l: alsa: Associating V4L2 and ALSA devices coming from the same device (a webcam for example)
I have an application that allows for recording audio/video from input devices. I now want to add to it the ability to autodetect plugged-in USB webcams via udev. The problem is that audio and video are handled separately, by a video4linux and an ALSA device. The goal is to discover the ALSA device name and the Video4Linux device node that are associated (that is, belonging to the same camera input feed). Surprisingly, there does not seem to be any interface in V4L2 for this, so I had to resort to looking at the udev properties. I came up with a very dirty hack that accomplishes what I want. I pasted it below. This code relies on the ID_USB_INTERFACES property to associate the V4L2 and ALSA devices, which may or may not be fragile. Furthermore, it traverses directories in /sys/ . I use libgudev here. I now ask the mailing list if there is an easier way to do this. Note that I cannot rely on tools like the gst device monitor. It would also be preferable to not have to rely on specific udev rules, though I will add them if it is truly necessary. Also, I found it difficult to get a meaningful label that I can present the user. The V4L2 properties produced fairly useless labels (something like "UVC camera (:)"). What produced the best results was the ID_MODEL_FROM_DATABASE - but this is a property of the ALSA devices. So, anybody has a better idea how to accomplish this? The hacky code: std::regex sndcard_regex(".*/sound/card[[:digit:]]+/controlC[[:digit:]]+$"); std::regex pcmc_regex("pcmC([[:digit:]]+)D([[:digit:]]+)c"); void process_added_device(GUdevDevice *p_added_device) { gchar const *bus_cstr = g_udev_device_get_property(p_added_device, "ID_BUS"); if (g_strcmp0(bus_cstr, "usb") != 0) return; gchar const *path_cstr = g_udev_device_get_sysfs_path(p_added_device); gchar const *subsystem_cstr = g_udev_device_get_property(p_added_device, "SUBSYSTEM"); gchar const *usb_interfaces_cstr = g_udev_device_get_property(p_added_device, "ID_USB_INTERFACES"); std::string id = std::string("usbif_") + usb_interfaces_cstr; capture_device new_capture_device; new_capture_device.m_is_hdmi_device = false; new_capture_device.m_label = id; // initially use the ID as label, as fallback if no other label can be found new_capture_device.m_id = id; auto _view = m_entries.get < id_tag > (); auto iter = id_view.find(id); if (iter != id_view.end()) // check if an entry exists already; if so, retrieve it { new_capture_device = *iter; // remove the device from the boost multi-index container. we'll reinsert a modified version later. id_view.erase(iter); } if (g_strcmp0(subsystem_cstr, "video4linux") == 0) { gchar const *devnode_cstr = g_udev_device_get_device_file(p_added_device); new_capture_device.m_v4l2_device = devnode_cstr; } else if (g_strcmp0(subsystem_cstr, "sound") == 0) { gchar const *model_from_db = g_udev_device_get_property(p_added_device, "ID_MODEL_FROM_DATABASE"); if (model_from_db != nullptr) new_capture_device.m_label = model_from_db; std::smatch base_match; std::string path_str = path_cstr; if (std::regex_match(path_str, base_match, sndcard_regex)) // check if this sound device path is one to an ALSA control device { boost::filesystem::path path = path_str; path = path.parent_path(); boost::system::error_code ec; boost::filesystem::directory_iterator dir_iter(path, ec); if (ec) return; // search the parent directory for a PCM capture device boost::filesystem::directory_iterator end_dir_iter; for (; dir_iter != end_dir_iter; ++dir_iter) { std::smatch pcm_match; if (std::regex_match(dir_iter->path().filename().string(), pcm_match, pcmc_regex)) new_capture_device.m_alsa_device = std::string("plughw:") + std::string(pcm_match[1]) + "," + std::string(pcm_match[2]); } } } id_view.emplace(new_capture_device); }
[PATCH for v4.9 10/13] media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 ++- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index c32feb94b3e5..3b5f3c8956f2 100644 --- 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(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || @@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user 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, >clips)) + n = kp->clipcount; + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (n--) { + if (copy_in_user(>c, >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(>c, >c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, >next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else - kp->clips = NULL; + if (put_user(n ? kclips + 1 : NULL, >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(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || put_user(kp->clipcount, >clipcount) || put_user(kp->global_alpha, >global_alpha)) return -EFAULT; + + if (!kp->clipcount) + return 0; + + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + while (n--) { + if (copy_in_user(>c, >c, sizeof(uclips->c))) + return -EFAULT; + uclips++; + kclips++; + } return 0; } -- 2.15.1
[PATCH for v4.9 09/13] media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha
From: Daniel Mentzcommit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream. Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output overlays.") added the field global_alpha to struct v4l2_window but did not update the compat layer accordingly. This change adds global_alpha to struct v4l2_window32 and copies the value for global_alpha back and forth. Signed-off-by: Daniel Mentz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index da55322bbb0f..c32feb94b3e5 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -45,6 +45,7 @@ struct v4l2_window32 { compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; compat_caddr_t bitmap; + __u8global_alpha; }; static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) @@ -53,7 +54,8 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user copy_from_user(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount)) + get_user(kp->clipcount, >clipcount) || + get_user(kp->global_alpha, >global_alpha)) return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; @@ -86,7 +88,8 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (copy_to_user(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount)) + put_user(kp->clipcount, >clipcount) || + put_user(kp->global_alpha, >global_alpha)) return -EFAULT; return 0; } -- 2.15.1
[PATCH for v4.9 11/13] media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 1 file changed, 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 3b5f3c8956f2..75653d756dd9 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -175,8 +175,6 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_from_user(>fmt.sdr, >fmt.sdr, sizeof(kp->fmt.sdr)) ? -EFAULT : 0; default: - pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } @@ -226,8 +224,6 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_to_user(>fmt.sdr, >fmt.sdr, sizeof(kp->fmt.sdr)) ? -EFAULT : 0; default: - pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } -- 2.15.1
[PATCH for v4.9 06/13] media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 47 --- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 64e3977ab851..2ddeecdababe 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -299,19 +299,24 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ 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(>m.mem_offset, >m.mem_offset, +sizeof(up32->m.mem_offset))) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: if (get_user(p, >m.userptr)) return -EFAULT; up_pln = compat_ptr(p); if (put_user((unsigned long)up_pln, >m.userptr)) return -EFAULT; - } else if (memory == V4L2_MEMORY_DMABUF) { + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(>m.fd, >m.fd, sizeof(up32->m.fd))) return -EFAULT; - } else { - if (copy_in_user(>m.mem_offset, >m.mem_offset, -sizeof(up32->m.mem_offset))) - return -EFAULT; + break; } return 0; @@ -320,22 +325,32 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ 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(>data_offset, >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(>m.mem_offset, >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, >m.userptr) || + put_user((compat_ulong_t)ptr_to_compat((__force void *)p), +>m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(>m.fd, >m.fd, sizeof(up->m.fd))) return -EFAULT; + break; + } return 0; } @@ -395,6 +410,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (get_user(kp->m.offset, >m.offset)) return -EFAULT; break; @@ -408,10 +424,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, >m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (get_user(kp->m.fd, >m.fd)) return -EFAULT; @@ -468,6 +480,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (put_user(kp->m.offset, >m.offset)) return -EFAULT; break; @@ -475,10 +488,6 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
[PATCH for v4.9 05/13] media: v4l2-compat-ioctl32.c: avoid sizeof(type)
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 77 +-- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 64bc493edd7f..64e3977ab851 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -47,7 +47,7 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || @@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (get_user(p, >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(>c, >c, sizeof(uclips->c))) @@ -157,14 +157,14 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us 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(>format, >format); @@ -208,14 +208,14 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32))) + if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; return __put_v4l2_format32(kp, up); } static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; @@ -234,7 +234,7 @@ struct v4l2_standard32 { static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->index, >index)) return -EFAULT; return 0; @@ -242,13 +242,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 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, >index) || put_user(kp->id, >id) || - copy_to_user(up->name, kp->name, 24) || + copy_to_user(up->name, kp->name, sizeof(up->name)) || copy_to_user(>frameperiod, >frameperiod, sizeof(kp->frameperiod)) || put_user(kp->framelines, >framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return 0; } @@ -296,7 +296,7 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(>data_offset, >data_offset, -
[PATCH for v4.9 01/13] media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-ioctl.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index c52d94c018bb..4510e8a37244 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2862,8 +2862,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, /* 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); -- 2.15.1
[PATCH for v4.9 07/13] media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 57 ++- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 2ddeecdababe..c8dd39884f6e 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -587,24 +589,39 @@ struct v4l2_ext_control32 { }; } __attribute__ ((packed)); -/* The following function really belong in v4l2-common, but that causes - a circular dependency between modules. We need to think about this, but - for now this will do. */ - -/* Return non-zero if this control is a pointer type. Currently only - type STRING is a pointer type. */ -static inline int ctrl_is_pointer(u32 id) +/* Return true if this control is a pointer type. */ +static inline bool ctrl_is_pointer(struct file *file, u32 id) { - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; + 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, >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.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); } -static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int get_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; @@ -636,7 +653,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return -EFAULT; if (get_user(id, >id)) return -EFAULT; - if (ctrl_is_pointer(id)) { + if (ctrl_is_pointer(file, id)) { void __user *s; if (get_user(p, >string)) @@ -651,7 +668,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return 0; } -static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int put_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols = @@ -683,7 +702,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext /* Do not modify the pointer when copying a pointer control. The contents of the pointer was changed, not the pointer itself. */ - if (ctrl_is_pointer(id)) + if (ctrl_is_pointer(file, id)) size -= sizeof(ucontrols->value64); if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; @@ -897,7 +916,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(, up); + err = get_v4l2_ext_controls32(file, , up);
[PATCH for v4.9 03/13] media: v4l2-compat-ioctl32.c: fix the indentation
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 208 +- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 049380bbf4cf..57211c7fc491 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -48,11 +48,11 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || - copy_from_user(>w, >w, sizeof(up->w)) || - get_user(kp->field, >field) || - get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount)) - return -EFAULT; + copy_from_user(>w, >w, sizeof(up->w)) || + get_user(kp->field, >field) || + get_user(kp->chromakey, >chromakey) || + get_user(kp->clipcount, >clipcount)) + return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; if (kp->clipcount) { @@ -82,10 +82,10 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (copy_to_user(>w, >w, sizeof(kp->w)) || - put_user(kp->field, >field) || - put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount)) - return -EFAULT; + put_user(kp->field, >field) || + put_user(kp->chromakey, >chromakey) || + put_user(kp->clipcount, >clipcount)) + return -EFAULT; return 0; } @@ -97,7 +97,7 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) +struct v4l2_pix_format_mplane __user *up) { if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -112,7 +112,7 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) +struct v4l2_pix_format_mplane __user *up) { if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -218,7 +218,7 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return get_v4l2_sdr_format(>fmt.sdr, >fmt.sdr); default: pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -265,7 +265,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return put_v4l2_sdr_format(>fmt.sdr, >fmt.sdr); default: pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -299,7 +299,7 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 { /* 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, >index)) + get_user(kp->index, >index)) return -EFAULT; return 0; } @@ -307,13 +307,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 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, >index) || - put_user(kp->id, >id) || - copy_to_user(up->name, kp->name, 24) || - copy_to_user(>frameperiod, >frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, >framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) - return
[PATCH for v4.9 04/13] media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 104 +- 1 file changed, 20 insertions(+), 84 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 57211c7fc491..64bc493edd7f 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -89,78 +89,6 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return 0; } -static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, -struct v4l2_pix_format_mplane __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, -struct v4l2_pix_format_mplane __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format))) - return -EFAULT; - return 0; -} - struct v4l2_format32 { __u32 type; /* enum v4l2_buf_type */ union { @@ -199,23 +127,27 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(>fmt.pix, >fmt.pix); + return copy_from_user(>fmt.pix, >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(>fmt.pix_mp, - >fmt.pix_mp); + return copy_from_user(>fmt.pix_mp, >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(>fmt.win, >fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(>fmt.vbi, >fmt.vbi); + return copy_from_user(>fmt.vbi, >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(>fmt.sliced, >fmt.sliced); + return copy_from_user(>fmt.sliced, >fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; case
[PATCH for v4.9 02/13] media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index dc51dd86377d..049380bbf4cf 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -1022,6 +1022,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_create32(, up); break; + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: -- 2.15.1
[PATCH for v4.9 00/13] v4l2-compat-ioctl32.c: remove set_fs(KERNEL_DS)
From: Hans VerkuilThis patch series fixes a number of bugs and culminates in the removal of the set_fs(KERNEL_DS) call in v4l2-compat-ioctl32.c. This was tested with a VM running 4.9, the vivid driver (since that emulates almost all V4L2 ioctls that need to pass through v4l2-compat-ioctl32.c) and a 32-bit v4l2-compliance utility since that exercises almost all ioctls as well. Combined this gives good test coverage. Most of the v4l2-compat-ioctl32.c do cleanups and fix subtle issues that v4l2-compliance complained about. The purpose is to 1) make it easy to verify that the final patch didn't introduce errors by first eliminating errors caused by other bugs, and 2) keep the final patch at least somewhat readable. Regards, Hans Daniel Mentz (2): media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic Hans Verkuil (11): media: v4l2-ioctl.c: don't copy back the result for -ENOTTY media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF media: v4l2-compat-ioctl32.c: fix the indentation media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 media: v4l2-compat-ioctl32.c: avoid sizeof(type) media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1023 +++-- drivers/media/v4l2-core/v4l2-ioctl.c |5 +- 2 files changed, 618 insertions(+), 410 deletions(-) -- 2.15.1
[PATCH for v4.9 08/13] media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index c8dd39884f6e..da55322bbb0f 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -612,7 +612,7 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) 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, ) && -- 2.15.1
[PATCH for v3.16 13/14] media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 2a03bd72cefc..64d1a2bddd5e 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -921,6 +921,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar 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. */ -- 2.15.1
[PATCH for v3.16 12/14] media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 1 file changed, 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index e7ebd20b6c6a..2a03bd72cefc 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -170,8 +170,6 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_from_user(>fmt.sliced, >fmt.sliced, sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } @@ -214,8 +212,6 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_to_user(>fmt.sliced, >fmt.sliced, sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } -- 2.15.1
[PATCH for v3.16 11/14] media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 ++- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index de69afde9e86..e7ebd20b6c6a 100644 --- 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(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || @@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user 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, >clips)) + n = kp->clipcount; + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (n--) { + if (copy_in_user(>c, >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(>c, >c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, >next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else - kp->clips = NULL; + if (put_user(n ? kclips + 1 : NULL, >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(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || put_user(kp->clipcount, >clipcount) || put_user(kp->global_alpha, >global_alpha)) return -EFAULT; + + if (!kp->clipcount) + return 0; + + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + while (n--) { + if (copy_in_user(>c, >c, sizeof(uclips->c))) + return -EFAULT; + uclips++; + kclips++; + } return 0; } -- 2.15.1
[PATCH for v3.16 14/14] media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
From: Daniel Mentzcommit 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, >clipcount) || put_user(clipcount, >clipcount)) return -EFAULT; Notes from hans.verk...@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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 780 +- 1 file changed, 510 insertions(+), 270 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 64d1a2bddd5e..d35b67b37077 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -22,6 +22,14 @@ #include #include +/* Use the same argument order as copy_in_user */ +#define assign_in_user(to, from) \ +({ \ + typeof(*from) __assign_tmp; \ + \ + get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \ +}) + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = -ENOIOCTLCMD; @@ -35,12 +43,12 @@ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct v4l2_clip32 { struct v4l2_rectc; - compat_caddr_t next; + compat_caddr_t next; }; struct v4l2_window32 { struct v4l2_rectw; - __u32 field; /* enum v4l2_field */ + __u32 field; /* enum v4l2_field */ __u32 chromakey; compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; @@ -48,37 +56,41 @@ struct v4l2_window32 { __u8global_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
[PATCH for v3.16 09/14] media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 50 +-- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 3a72a735a940..69d772d1237d 100644 --- 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) @@ -567,24 +569,32 @@ 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) +/* Return true if this control is a pointer type. */ +static inline bool ctrl_is_pointer(struct file *file, u32 id) { - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; + struct video_device *vdev = video_devdata(file); + struct v4l2_fh *fh = NULL; + struct v4l2_ctrl_handler *hdl = NULL; + + if (test_bit(V4L2_FL_USES_V4L2_FH, >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->type == V4L2_CTRL_TYPE_STRING; } + return false; } -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; @@ -612,7 +622,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext while (--n >= 0) { if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) return -EFAULT; - if (ctrl_is_pointer(kcontrols->id)) { + if (ctrl_is_pointer(file, kcontrols->id)) { void __user *s; if (get_user(p, >string)) @@ -627,7 +637,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext 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 = kp->controls; @@ -655,7 +667,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext /* 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(kcontrols->id)) + if (ctrl_is_pointer(file, kcontrols->id)) size -= sizeof(ucontrols->value64); if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; @@ -869,7 +881,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(, up); + err = get_v4l2_ext_controls32(file, , up); compatible_arg = 0; break; case VIDIOC_DQEVENT: @@ -896,7 +908,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
[PATCH for v3.16 01/14] adv7604: use correct drive strength defines
From: Hans VerkuilThe prefix is ADV7604_, not ADV76XX. Fixes: f31b62e14a ("adv7604: add hdmi driver strength adjustment") Signed-off-by: Hans Verkuil --- drivers/media/i2c/adv7604.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index af8a99716de5..9e0e592f50ab 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2735,9 +2735,9 @@ static int adv7604_parse_dt(struct adv7604_state *state) state->pdata.alt_data_sat = 1; state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0; state->pdata.bus_order = ADV7604_BUS_ORDER_RGB; - state->pdata.dr_str_data = ADV76XX_DR_STR_MEDIUM_HIGH; - state->pdata.dr_str_clk = ADV76XX_DR_STR_MEDIUM_HIGH; - state->pdata.dr_str_sync = ADV76XX_DR_STR_MEDIUM_HIGH; + state->pdata.dr_str_data = ADV7604_DR_STR_MEDIUM_HIGH; + state->pdata.dr_str_clk = ADV7604_DR_STR_MEDIUM_HIGH; + state->pdata.dr_str_sync = ADV7604_DR_STR_MEDIUM_HIGH; return 0; } -- 2.15.1
[no subject]
hi Linux https://goo.gl/jMp8sb Scott Tisdale
Re: exposing a large-ish calibration table through V4L2?
On 14/02/18 13:27, Florian Echtler wrote: > Hello Hans, > > On 14.02.2018 13:13, Hans Verkuil wrote: >> >> On 14/02/18 13:09, Florian Echtler wrote: >>> >>> The internal device memory contains a table with two bytes for each sensor >>> pixel >>> (i.e. 960x540x2 = 1036800 bytes) that basically provide individual black and >>> white levels per-pixel that are used in preprocessing. The table can either >>> be >>> set externally, or the sensor can be covered with a black/white surface and >>> a >>> custom command triggers an internal calibration. >>> >>> AFAICT the usual V4L2 controls are unsuitable for this sort of data; do you >>> have >>> any suggestions on how to approach this? Maybe something like a custom >>> IOCTL? >> >> So the table has a fixed size? >> You can use array controls for that, a V4L2_CTRL_TYPE_U16 in a >> two-dimensional array >> would do it. > > Good to know, thanks. > >> See https://hverkuil.home.xs4all.nl/spec/uapi/v4l/vidioc-queryctrl.html for >> more >> information on how this works. > > This means I have to implement QUERY_EXT_CTRL, G_EXT_CTRLS and S_EXT_CTRLS, > correct? Will this work in parallel to the "regular" controls that use the > control framework? No, just use the control framework. You need to make a custom control that is specific to your driver So reserve a range for your driver in include/uapi/linux/v4l2-controls.h (search for 'USER-class private control IDs'). Then you can define a control ID. The next step is to configure the control: static const struct v4l2_ctrl_config cal_table_control = { .ops = _ctrl_ops, .id = V4L2_CID_SUR40_CAL_TABLE, .name = "Calibration Table", .type = V4L2_CTRL_TYPE_U16, .max = 0x, .step = 1, .def = 0, .dims = { 960, 540 }, }; And register it with a control handler: v4l2_ctrl_new_custom(hdl, _table_control, NULL); See e.g. drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c and the DETECT_MD controls. Regards, Hans
Re: [PATCH v7 2/2] v4l: cadence: Add Cadence MIPI-CSI2 RX driver
Hi Laurent, On Thu, Feb 08, 2018 at 08:17:19PM +0200, Laurent Pinchart wrote: > > + /* > > +* Create a static mapping between the CSI virtual channels > > +* and the output stream. > > +* > > +* This should be enhanced, but v4l2 lacks the support for > > +* changing that mapping dynamically. > > +* > > +* We also cannot enable and disable independant streams here, > > +* hence the reference counting. > > +*/ > > If you start all streams in one go, will s_stream(1) be called multiple times > ? If not, you could possibly skip the whole reference counting and avoid > locking. I guess that while we should expect the CSI-2 bus to be always enabled, the downstream camera interface could be shutdown independently, so I guess s_stream would be called each time one is brought up or brought down? Maxime -- Maxime Ripard, Bootlin (formerly Free Electrons) Embedded Linux and Kernel engineering http://bootlin.com signature.asc Description: PGP signature
[PATCH for v4.14 13/13] media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index ec4a69728ed4..cbeea8343a5c 100644 --- 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(struct file *file, u32 id) 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, ) && -- 2.15.1
[PATCH for v4.14 11/13] media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index bef9c990c9bd..5603c7c1edd5 100644 --- 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 *file, unsigned int cmd, unsigned long ar 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. */ -- 2.15.1
[PATCH for v3.16 06/14] media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 92 ++- 1 file changed, 20 insertions(+), 72 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index a3e62cf3acaa..f76ed4ee7df9 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -89,64 +89,6 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return 0; } -static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, -struct v4l2_pix_format_mplane __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, -struct v4l2_pix_format_mplane __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - struct v4l2_format32 { __u32 type; /* enum v4l2_buf_type */ union { @@ -184,20 +126,23 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(>fmt.pix, >fmt.pix); + return copy_from_user(>fmt.pix, >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(>fmt.pix_mp, - >fmt.pix_mp); + return copy_from_user(>fmt.pix_mp, >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(>fmt.win, >fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(>fmt.vbi, >fmt.vbi); + return copy_from_user(>fmt.vbi, >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(>fmt.sliced, >fmt.sliced); + return copy_from_user(>fmt.sliced, >fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", kp->type); @@ -225,20 +170,23 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return put_v4l2_pix_format(>fmt.pix, >fmt.pix); + return copy_to_user(>fmt.pix, >fmt.pix, +
[PATCH for v3.16 10/14] media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha
From: Daniel Mentzcommit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream. Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output overlays.") added the field global_alpha to struct v4l2_window but did not update the compat layer accordingly. This change adds global_alpha to struct v4l2_window32 and copies the value for global_alpha back and forth. Signed-off-by: Daniel Mentz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 69d772d1237d..de69afde9e86 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -45,6 +45,7 @@ struct v4l2_window32 { compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; compat_caddr_t bitmap; + __u8global_alpha; }; static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) @@ -53,7 +54,8 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user copy_from_user(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount)) + get_user(kp->clipcount, >clipcount) || + get_user(kp->global_alpha, >global_alpha)) return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; @@ -86,7 +88,8 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (copy_to_user(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount)) + put_user(kp->clipcount, >clipcount) || + put_user(kp->global_alpha, >global_alpha)) return -EFAULT; return 0; } -- 2.15.1
[PATCH for v3.16 07/14] media: v4l2-compat-ioctl32.c: avoid sizeof(type)
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 73 +-- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index f76ed4ee7df9..c9d9f23e660a 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -47,7 +47,7 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || @@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (get_user(p, >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(>c, >c, sizeof(uclips->c))) @@ -152,14 +152,14 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us 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(>format, >format); @@ -196,7 +196,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us 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)) || put_user(kp->type, >type)) return -EFAULT; return __put_v4l2_format32(kp, up); @@ -204,7 +204,7 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user 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.fmt))) return -EFAULT; return __put_v4l2_format32(>format, >format); @@ -222,7 +222,7 @@ struct v4l2_standard32 { static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->index, >index)) return -EFAULT; return 0; @@ -230,13 +230,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 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, >index) || put_user(kp->id, >id) || - copy_to_user(up->name, kp->name, 24) || + copy_to_user(up->name, kp->name, sizeof(up->name)) || copy_to_user(>frameperiod, >frameperiod, sizeof(kp->frameperiod)) || put_user(kp->framelines, >framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return 0; } @@ -284,7 +284,7 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
[PATCH for v3.16 00/14] v4l2-compat-ioctl32.c: remove set_fs(KERNEL_DS)
From: Hans VerkuilThis patch series fixes a number of bugs and culminates in the removal of the set_fs(KERNEL_DS) call in v4l2-compat-ioctl32.c. This was tested with a VM running 3.16, the vivi driver (a poor substitute for the much improved vivid driver that's available in later kernels, but it's the best I had) since that emulates the more common V4L2 ioctls that need to pass through v4l2-compat-ioctl32.c) and the 32-bit v4l2-compliance + 32-bit v4l2-ctl utilities that together exercised the most common ioctls. Most of the v4l2-compat-ioctl32.c do cleanups and fix subtle issues that v4l2-compliance complained about. The purpose is to 1) make it easy to verify that the final patch didn't introduce errors by first eliminating errors caused by other known bugs, and 2) keep the final patch at least somewhat readable. While compiling the media drivers for 3.16 I also came across a bug introduced in the 3.16 stable series that caused a compile error in the adv7604 driver. That's fixed in the first patch. Call it a bonus patch :-) Regards, Hans Daniel Mentz (2): media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic Hans Verkuil (11): adv7604: use correct drive strength defines media: v4l2-ioctl.c: don't copy back the result for -ENOTTY media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF media: v4l2-compat-ioctl32.c: fix the indentation media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 media: v4l2-compat-ioctl32.c: avoid sizeof(type) media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors Ricardo Ribalda (1): vb2: V4L2_BUF_FLAG_DONE is set after DQBUF drivers/media/i2c/adv7604.c |6 +- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1030 +++-- drivers/media/v4l2-core/v4l2-ioctl.c |5 +- drivers/media/v4l2-core/videobuf2-core.c |5 + 4 files changed, 642 insertions(+), 404 deletions(-) -- 2.15.1
[PATCH for v3.16 08/14] media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 47 --- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index c9d9f23e660a..3a72a735a940 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -287,19 +287,24 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, 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(>m.mem_offset, >m.mem_offset, +sizeof(up32->m.mem_offset))) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: if (get_user(p, >m.userptr)) return -EFAULT; up_pln = compat_ptr(p); if (put_user((unsigned long)up_pln, >m.userptr)) return -EFAULT; - } else if (memory == V4L2_MEMORY_DMABUF) { + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(>m.fd, >m.fd, sizeof(up32->m.fd))) return -EFAULT; - } else { - if (copy_in_user(>m.mem_offset, >m.mem_offset, -sizeof(up32->m.mem_offset))) - return -EFAULT; + break; } return 0; @@ -308,22 +313,32 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, enum v4l2_memory memory) { + unsigned long p; + if (copy_in_user(up32, up, 2 * sizeof(__u32)) || copy_in_user(>data_offset, >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(>m.mem_offset, >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, >m.userptr) || + put_user((compat_ulong_t)ptr_to_compat((__force void *)p), +>m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(>m.fd, >m.fd, sizeof(up->m.fd))) return -EFAULT; + break; + } return 0; } @@ -384,6 +399,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (get_user(kp->m.offset, >m.offset)) return -EFAULT; break; @@ -397,10 +413,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, >m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (get_user(kp->m.fd, >m.fd)) return -EFAULT; @@ -457,6 +469,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (put_user(kp->m.offset, >m.offset)) return -EFAULT; break; @@ -464,10 +477,6 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
[PATCH for v3.16 05/14] media: v4l2-compat-ioctl32.c: fix the indentation
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 216 +- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index ebedf95a31ed..a3e62cf3acaa 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -48,11 +48,11 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || - copy_from_user(>w, >w, sizeof(up->w)) || - get_user(kp->field, >field) || - get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount)) - return -EFAULT; + copy_from_user(>w, >w, sizeof(up->w)) || + get_user(kp->field, >field) || + get_user(kp->chromakey, >chromakey) || + get_user(kp->clipcount, >clipcount)) + return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; if (kp->clipcount) { @@ -82,10 +82,10 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (copy_to_user(>w, >w, sizeof(kp->w)) || - put_user(kp->field, >field) || - put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount)) - return -EFAULT; + put_user(kp->field, >field) || + put_user(kp->chromakey, >chromakey) || + put_user(kp->clipcount, >clipcount)) + return -EFAULT; return 0; } @@ -97,7 +97,7 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) +struct v4l2_pix_format_mplane __user *up) { if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -112,7 +112,7 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) +struct v4l2_pix_format_mplane __user *up) { if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -200,7 +200,7 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return get_v4l2_sliced_vbi_format(>fmt.sliced, >fmt.sliced); default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -241,7 +241,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return put_v4l2_sliced_vbi_format(>fmt.sliced, >fmt.sliced); default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -249,7 +249,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || - put_user(kp->type, >type)) + put_user(kp->type, >type)) return -EFAULT; return __put_v4l2_format32(kp, up); } @@ -258,7 +258,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_ { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) - return -EFAULT; + return -EFAULT; return __put_v4l2_format32(>format, >format); } @@ -275,7 +275,7 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 { /* other fields are not set by the user, nor used by the driver */ if
[PATCH for v3.16 04/14] media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 0f747ba40b52..ebedf95a31ed 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -980,6 +980,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_create32(, up); break; + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: -- 2.15.1
[PATCH for v3.16 02/14] media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-ioctl.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 16bffd851bf9..e2f71def945a 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2402,8 +2402,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, /* 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); -- 2.15.1
[PATCH for v3.16 03/14] vb2: V4L2_BUF_FLAG_DONE is set after DQBUF
From: Ricardo Ribaldacommit 3171cc2b4eb9831ab4df1d80d0410a945b8bc84e upstream. According to the doc, V4L2_BUF_FLAG_DONE is cleared after DQBUF: V4L2_BUF_FLAG_DONE 0x0004 ... After calling the VIDIOC_QBUF or VIDIOC_DQBUF it is always cleared ... Unfortunately, it seems that videobuf2 keeps it set after DQBUF. This can be tested with vivid and dev_debug: [257604.338082] video1: VIDIOC_DQBUF: 71:33:25.00260479 index=3, type=vid-cap, flags=0x2004, field=none, sequence=163, memory=userptr, bytesused=460800, offset/userptr=0x344b000, length=460800 This patch forces FLAG_DONE to 0 after calling DQBUF. Reported-by: Dimitrios Katsaros Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index e63a7904bf5b..ee8b697972bb 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2069,6 +2069,11 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n dprintk(1, "dqbuf of buffer %d, with state %d\n", vb->v4l2_buf.index, vb->state); + /* +* After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be +* cleared. +*/ + b->flags &= ~V4L2_BUF_FLAG_DONE; return 0; } -- 2.15.1
[PATCH for v3.2 01/12] media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
From: Hans Verkuilcommit 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 --- drivers/media/video/v4l2-ioctl.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 639abeee3392..bae5dd776d82 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -2308,8 +2308,10 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, /* Handles IOCTL */ err = func(file, cmd, parg); - if (err == -ENOIOCTLCMD) - err = -EINVAL; + if (err == -ENOTTY || err == -ENOIOCTLCMD) { + err = -ENOTTY; + goto out; + } if (has_array_args) { *kernel_ptr = user_ptr; -- 2.15.1
[PATCH for v3.2 05/12] media: v4l2-compat-ioctl32.c: avoid sizeof(type)
From: Hans Verkuilcommit 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 --- drivers/media/video/v4l2-compat-ioctl32.c | 65 +++ 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 4d0901573860..e2dee29eaaa5 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -47,7 +47,7 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || @@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (get_user(p, >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(>c, >c, sizeof(uclips->c))) @@ -156,14 +156,14 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us 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(>format, >format); @@ -204,7 +204,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us 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)) || put_user(kp->type, >type)) return -EFAULT; return __put_v4l2_format32(kp, up); @@ -212,7 +212,7 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user 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.fmt))) return -EFAULT; return __put_v4l2_format32(>format, >format); @@ -230,7 +230,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, >index)) return -EFAULT; return 0; @@ -238,13 +238,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 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, >index) || copy_to_user(up->id, >id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, 24) || + copy_to_user(up->name, kp->name, sizeof(up->name)) || copy_to_user(>frameperiod, >frameperiod, sizeof(kp->frameperiod)) || put_user(kp->framelines, >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; } @@ -290,7 +290,7 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
Re: exposing a large-ish calibration table through V4L2?
Hello Hans, On 14.02.2018 13:13, Hans Verkuil wrote: > > On 14/02/18 13:09, Florian Echtler wrote: >> >> The internal device memory contains a table with two bytes for each sensor >> pixel >> (i.e. 960x540x2 = 1036800 bytes) that basically provide individual black and >> white levels per-pixel that are used in preprocessing. The table can either >> be >> set externally, or the sensor can be covered with a black/white surface and a >> custom command triggers an internal calibration. >> >> AFAICT the usual V4L2 controls are unsuitable for this sort of data; do you >> have >> any suggestions on how to approach this? Maybe something like a custom IOCTL? > > So the table has a fixed size? > You can use array controls for that, a V4L2_CTRL_TYPE_U16 in a > two-dimensional array > would do it. Good to know, thanks. > See https://hverkuil.home.xs4all.nl/spec/uapi/v4l/vidioc-queryctrl.html for > more > information on how this works. This means I have to implement QUERY_EXT_CTRL, G_EXT_CTRLS and S_EXT_CTRLS, correct? Will this work in parallel to the "regular" controls that use the control framework? Best, Florian -- SENT FROM MY DEC VT50 TERMINAL signature.asc Description: OpenPGP digital signature
Re: [PATCH v10 6/8] media: i2c: Add TDA1997x HDMI receiver driver
Hi Tim, On 12/02/18 23:27, Tim Harvey wrote: > On Fri, Feb 9, 2018 at 12:08 AM, Hans Verkuilwrote: >> Hi Tim, >> >> We're almost there. Two more comments: >> >> On 02/09/2018 07:32 AM, Tim Harvey wrote: >>> +static int >>> +tda1997x_detect_std(struct tda1997x_state *state, >>> + struct v4l2_dv_timings *timings) >>> +{ >>> + struct v4l2_subdev *sd = >sd; >>> + u32 vper; >>> + u16 hper; >>> + u16 hsper; >>> + int i; >>> + >>> + /* >>> + * Read the FMT registers >>> + * REG_V_PER: Period of a frame (or two fields) in MCLK(27MHz) >>> cycles >>> + * REG_H_PER: Period of a line in MCLK(27MHz) cycles >>> + * REG_HS_WIDTH: Period of horiz sync pulse in MCLK(27MHz) cycles >>> + */ >>> + vper = io_read24(sd, REG_V_PER) & MASK_VPER; >>> + hper = io_read16(sd, REG_H_PER) & MASK_HPER; >>> + hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH; >>> + if (!vper || !hper || !hsper) >>> + return -ENOLINK; >> >> See my comment for g_input_status below. This condition looks more like a >> ENOLCK. >> >> Or perhaps it should be: >> >> if (!vper && !hper && !hsper) >> return -ENOLINK; >> if (!vper || !hper || !hsper) >> return -ENOLCK; >> >> I would recommend that you test a bit with no signal and a bad signal >> (perhaps >> one that uses a pixelclock that is too high for this device?). > > I can't figure out how to produce a signal that can't be locked onto > with what I have available. Are you using a signal generator or just a laptop or something similar as the source? Without a good signal generator it is tricky to test this. A very long HDMI cable would likely do it. But for 1080p60 you probably need 20 meters or more. > >> >>> + v4l2_dbg(1, debug, sd, "Signal Timings: %u/%u/%u\n", vper, hper, >>> hsper); >>> + >>> + for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { >>> + const struct v4l2_bt_timings *bt; >>> + u32 lines, width, _hper, _hsper; >>> + u32 vmin, vmax, hmin, hmax, hsmin, hsmax; >>> + bool vmatch, hmatch, hsmatch; >>> + >>> + bt = _dv_timings_presets[i].bt; >>> + width = V4L2_DV_BT_FRAME_WIDTH(bt); >>> + lines = V4L2_DV_BT_FRAME_HEIGHT(bt); >>> + _hper = (u32)bt->pixelclock / width; >>> + if (bt->interlaced) >>> + lines /= 2; >>> + /* vper +/- 0.7% */ >>> + vmin = ((2700 / 1000) * 993) / _hper * lines; >>> + vmax = ((2700 / 1000) * 1007) / _hper * lines; >>> + /* hper +/- 1.0% */ >>> + hmin = ((2700 / 100) * 99) / _hper; >>> + hmax = ((2700 / 100) * 101) / _hper; >>> + /* hsper +/- 2 (take care to avoid 32bit overflow) */ >>> + _hsper = 27000 * bt->hsync / ((u32)bt->pixelclock/1000); >>> + hsmin = _hsper - 2; >>> + hsmax = _hsper + 2; >>> + >>> + /* vmatch matches the framerate */ >>> + vmatch = ((vper <= vmax) && (vper >= vmin)) ? 1 : 0; >>> + /* hmatch matches the width */ >>> + hmatch = ((hper <= hmax) && (hper >= hmin)) ? 1 : 0; >>> + /* hsmatch matches the hswidth */ >>> + hsmatch = ((hsper <= hsmax) && (hsper >= hsmin)) ? 1 : 0; >>> + if (hmatch && vmatch && hsmatch) { >>> + *timings = v4l2_dv_timings_presets[i]; >>> + v4l2_print_dv_timings(sd->name, "Detected format: ", >>> + timings, false); >>> + return 0; >>> + } >>> + } >>> + >>> + v4l_err(state->client, "no resolution match for timings: %d/%d/%d\n", >>> + vper, hper, hsper); >>> + return -EINVAL; >>> +} >> >> -EINVAL isn't the correct error code here. I would go for -ERANGE. It's not >> perfect, but close enough. >> >> -EINVAL indicates that the user filled in wrong values, but that's not the >> case here. > > done > >> >>> +static int >>> +tda1997x_g_input_status(struct v4l2_subdev *sd, u32 *status) >>> +{ >>> + struct tda1997x_state *state = to_state(sd); >>> + u32 vper; >>> + u16 hper; >>> + u16 hsper; >>> + >>> + mutex_lock(>lock); >>> + v4l2_dbg(1, debug, sd, "inputs:%d/%d\n", >>> + state->input_detect[0], state->input_detect[1]); >>> + if (state->input_detect[0] || state->input_detect[1]) >> >> I'm confused. This device has two HDMI inputs? >> >> Does 'detecting input' equate to 'I see a signal and I am locked'? >> I gather from the irq function that sets these values that it is closer >> to 'I see a signal' and that 'I am locked' is something you would test >> by looking at the vper/hper/hsper. > > The TDA19972 and/or TDA19973 has an A and B input but only a single > output. I'm not entirely clear if/how to select between the two and I
[PATCH 1/1] media: request: Add support for tagged request-based objects
Allow binding objects to requests that can be later on fetched based on that tag. The intent is that the objects are bound at the time data is bound to a request and later retrieved for validation (and finally applied) when the request is queued. A tag can be any pointer, as long as it is unique to a request. Signed-off-by: Sakari Ailus--- Hi Alexandre, Here's the patch. It's on top of your current set so if you remove entity data support there may be some conflicts to resolve. It's only been compile tested so far, but is rather simple. By providing a tag, the caller may attach data objects to the request and they can be found later on, by using the same tag, when the request is queued. The drivers are still responsible for adding only objects they can support with requests. The driver must also detach the data from the request, and at the queue time, make sure that no objects that weren't accounted for were added. drivers/media/media-request.c | 105 ++ include/media/media-request.h | 75 ++ 2 files changed, 180 insertions(+) diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c index 30a2323..c96b747 100644 --- a/drivers/media/media-request.c +++ b/drivers/media/media-request.c @@ -57,10 +57,115 @@ media_request_get_from_fd(int fd) } EXPORT_SYMBOL_GPL(media_request_get_from_fd); +int media_request_data_attach(struct media_request *req, const void *tag, + void *data, + void (*release)(struct media_request *req, + const void *tag, void *data)) +{ + struct media_request_data *req_data; + + req_data = kzalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) + return -ENOMEM; + + req_data->req = req; + req_data->tag = tag; + req_data->data = data; + req_data->release = release; + + mutex_lock(>lock); + list_add(_data->list, >data_list); + mutex_unlock(>lock); + + return 0; +} +EXPORT_SYMBOL_GPL(media_request_data_attach); + +struct media_request_data *__media_request_data_find( + struct media_request *req, const void *tag) +{ + struct media_request_data *req_data; + + lockdep_assert_held(>lock); + + list_for_each_entry(req_data, >data_list, list) + if (req_data->tag == tag) + return req_data; + + return NULL; +} +EXPORT_SYMBOL_GPL(__media_request_data_find); + +void *media_request_data_find(struct media_request *req, const void *tag) +{ + struct media_request_data *req_data; + void *data; + + mutex_lock(>lock); + req_data = __media_request_data_find(req, tag); + mutex_lock(>lock); + + data = req_data ? req_data->data : NULL; + + return data; +} +EXPORT_SYMBOL_GPL(media_request_data_find); + +void media_request_data_detach(struct media_request *req, const void *tag) +{ + struct media_request_data *req_data; + + mutex_lock(>lock); + + req_data = __media_request_data_find(req, tag); + if (WARN_ON(!req_data)) { + mutex_unlock(>lock); + return; + } + + list_del(_data->list); + + mutex_unlock(>lock); + + if (req_data->release) + req_data->release(req_data->req, req_data->tag, req_data->data); + + kfree(req_data); +} +EXPORT_SYMBOL_GPL(media_request_data_detach); + +static void __media_request_data_detach(struct media_request_data *req) +{ + struct media_request_data *req_data; + + list_del(_data->list); + + if (req_data->release) + req_data->release(req_data->req, req_data->tag, req_data->data); + + kfree(req_data); +} + +bool media_request_has_data(struct media_request *req) +{ + bool ret; + + mutex_lock(>lock); + ret = list_empty(>data_list); + mutex_unlock(>lock); + + return ret; +} + static void media_request_release(struct kref *kref) { struct media_request *req = container_of(kref, typeof(*req), kref); + struct media_request_data *req_data, *req_data_safe; + + /* Last reference; no need to acquire the lock here. */ + list_for_each_entry_safe(req_data, req_data_safe, >data_list, list) + __media_request_data_detach(req_data); req->mgr->ops->req_free(req); } diff --git a/include/media/media-request.h b/include/media/media-request.h index 817df13..64b945d 100644 --- a/include/media/media-request.h +++ b/include/media/media-request.h @@ -36,12 +36,23 @@ enum media_request_state { MEDIA_REQUEST_STATE_DELETED, }; +struct media_request_data { + struct media_request *req; + const void *tag; + struct list_head list; + void *data; + void (*release)(struct media_request *req, + const void *tag, void *data); +}; +
[PATCH for v4.14 12/13] media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
From: Daniel Mentzcommit 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, >clipcount) || put_user(clipcount, >clipcount)) return -EFAULT; Notes from hans.verk...@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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 740 +- 1 file changed, 477 insertions(+), 263 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 5603c7c1edd5..ec4a69728ed4 100644 --- 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 { __u8global_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(>w, >w, sizeof(up->w)) || - get_user(kp->field, >field) || - get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount) || - get_user(kp->global_alpha, >global_alpha)) + copy_in_user(>w, >w, sizeof(up->w)) || + assign_in_user(>field, >field) || + assign_in_user(>chromakey, >chromakey) || + assign_in_user(>global_alpha, >global_alpha)
[PATCH for v4.14 07/13] media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 47 --- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index d156b8975f1e..62d44fab5671 100644 --- 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_plane __user *up, struct v4l2_plane32 __ 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(>m.mem_offset, >m.mem_offset, +sizeof(up32->m.mem_offset))) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: if (get_user(p, >m.userptr)) return -EFAULT; up_pln = compat_ptr(p); if (put_user((unsigned long)up_pln, >m.userptr)) return -EFAULT; - } else if (memory == V4L2_MEMORY_DMABUF) { + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(>m.fd, >m.fd, sizeof(up32->m.fd))) return -EFAULT; - } else { - if (copy_in_user(>m.mem_offset, >m.mem_offset, -sizeof(up32->m.mem_offset))) - return -EFAULT; + break; } return 0; @@ -331,22 +336,32 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ 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(>data_offset, >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(>m.mem_offset, >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, >m.userptr) || + put_user((compat_ulong_t)ptr_to_compat((__force void *)p), +>m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(>m.fd, >m.fd, sizeof(up->m.fd))) return -EFAULT; + break; + } return 0; } @@ -408,6 +423,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (get_user(kp->m.offset, >m.offset)) return -EFAULT; break; @@ -421,10 +437,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, >m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (get_user(kp->m.fd, >m.fd)) return -EFAULT; @@ -481,6 +493,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (put_user(kp->m.offset, >m.offset)) return -EFAULT; break; @@ -488,10 +501,6 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
[PATCH for v4.14 02/13] media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-ioctl.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 42e376f46729..d06941cc6a55 100644 --- 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, unsigned int cmd, unsigned long arg, /* 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); -- 2.15.1
[PATCH for v4.14 01/13] media: v4l2-ioctl.c: use check_fmt for enum/g/s/try_fmt
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-ioctl.c | 140 ++- 1 file changed, 54 insertions(+), 86 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index b60a6b0841d1..42e376f46729 100644 --- 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 v4l2_ioctl_ops *ops, 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_ioctl_ops *ops, 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
[PATCH for v4.14 00/13] v4l2-compat-ioctl32.c: remove set_fs(KERNEL_DS)
From: Hans VerkuilThis patch series fixes a number of bugs and culminates in the removal of the set_fs(KERNEL_DS) call in v4l2-compat-ioctl32.c. This was tested with a VM running 4.14, the vivid driver (since that emulates almost all V4L2 ioctls that need to pass through v4l2-compat-ioctl32.c) and a 32-bit v4l2-compliance utility since that exercises almost all ioctls as well. Combined this gives good test coverage. Most of the v4l2-compat-ioctl32.c do cleanups and fix subtle issues that v4l2-compliance complained about. The purpose is to 1) make it easy to verify that the final patch didn't introduce errors by first eliminating errors caused by other bugs, and 2) keep the final patch at least somewhat readable. Rgards, Hans Daniel Mentz (1): media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic Hans Verkuil (12): media: v4l2-ioctl.c: use check_fmt for enum/g/s/try_fmt media: v4l2-ioctl.c: don't copy back the result for -ENOTTY media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF media: v4l2-compat-ioctl32.c: fix the indentation media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 media: v4l2-compat-ioctl32.c: avoid sizeof(type) media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1032 +++-- drivers/media/v4l2-core/v4l2-ioctl.c | 145 ++-- 2 files changed, 665 insertions(+), 512 deletions(-) -- 2.15.1
[PATCH for v4.14 06/13] media: v4l2-compat-ioctl32.c: avoid sizeof(type)
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 79 --- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 297c924aefce..d156b8975f1e 100644 --- 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(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || @@ -66,7 +66,7 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (get_user(p, >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(>c, >c, sizeof(uclips->c))) @@ -164,14 +164,14 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us 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(>format, >format); @@ -218,14 +218,14 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us 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, >index)) return -EFAULT; return 0; @@ -252,14 +252,14 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 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, >index) || put_user(kp->id, >id) || - copy_to_user(up->name, kp->name, 24) || + copy_to_user(up->name, kp->name, sizeof(up->name)) || copy_to_user(>frameperiod, >frameperiod, sizeof(kp->frameperiod)) || put_user(kp->framelines, >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_plane __user *up, struct v4l2_plane32 __ if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(>data_offset,
[PATCH for v4.14 04/13] media: v4l2-compat-ioctl32.c: fix the indentation
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 212 +- 1 file changed, 107 insertions(+), 105 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index f6a7f8793720..44644a2ea3e9 100644 --- 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(>w, >w, sizeof(up->w)) || - get_user(kp->field, >field) || - get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount) || - get_user(kp->global_alpha, >global_alpha)) - return -EFAULT; + copy_from_user(>w, >w, sizeof(up->w)) || + get_user(kp->field, >field) || + get_user(kp->chromakey, >chromakey) || + get_user(kp->clipcount, >clipcount) || + get_user(kp->global_alpha, >global_alpha)) + return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; if (kp->clipcount) { @@ -84,11 +84,11 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (copy_to_user(>w, >w, sizeof(kp->w)) || - put_user(kp->field, >field) || - put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount) || - put_user(kp->global_alpha, >global_alpha)) - return -EFAULT; + put_user(kp->field, >field) || + put_user(kp->chromakey, >chromakey) || + put_user(kp->clipcount, >clipcount) || + put_user(kp->global_alpha, >global_alpha)) + return -EFAULT; return 0; } @@ -100,7 +100,7 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } 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(struct v4l2_pix_format *kp, struct v4l2_pi } 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 v4l2_format *kp, struct v4l2_format32 __us return get_v4l2_meta_format(>fmt.meta, >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 v4l2_format *kp, struct v4l2_format32 __us return put_v4l2_meta_format(>fmt.meta, >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 v4l2_standard *kp, struct v4l2_standard32 { /* 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, >index)) + get_user(kp->index, >index)) return -EFAULT; return 0; } @@ -329,13 +329,14 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 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, >index) || - put_user(kp->id, >id) || - copy_to_user(up->name, kp->name, 24) || -
[PATCH for v4.14 08/13] media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 57 ++- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 62d44fab5671..d11334712c65 100644 --- 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) +/* Return true if this control is a pointer type. */ +static inline bool ctrl_is_pointer(struct file *file, u32 id) { - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; + 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, >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.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(struct v4l2_ext_controls *kp, struct v4l2_ext return -EFAULT; if (get_user(id, >id)) return -EFAULT; - if (ctrl_is_pointer(id)) { + if (ctrl_is_pointer(file, id)) { void __user *s; if (get_user(p, >string)) @@ -666,7 +683,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext 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(struct v4l2_ext_controls *kp, struct v4l2_ext /* 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 *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(, up); + err = get_v4l2_ext_controls32(file, , up);
[PATCH for v4.14 10/13] media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 1 file changed, 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index de3e99dc3caa..bef9c990c9bd 100644 --- 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 v4l2_format *kp, struct v4l2_format32 __us return copy_from_user(>fmt.meta, >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 v4l2_format *kp, struct v4l2_format32 __us return copy_to_user(>fmt.meta, >fmt.meta, sizeof(kp->fmt.meta)) ? -EFAULT : 0; default: - pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } -- 2.15.1
[PATCH for v4.14 09/13] media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 ++- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index d11334712c65..de3e99dc3caa 100644 --- 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(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || @@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user 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, >clips)) + n = kp->clipcount; + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (n--) { + if (copy_in_user(>c, >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(>c, >c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, >next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else - kp->clips = NULL; + if (put_user(n ? kclips + 1 : NULL, >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(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || put_user(kp->clipcount, >clipcount) || put_user(kp->global_alpha, >global_alpha)) return -EFAULT; + + if (!kp->clipcount) + return 0; + + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + while (n--) { + if (copy_in_user(>c, >c, sizeof(uclips->c))) + return -EFAULT; + uclips++; + kclips++; + } return 0; } -- 2.15.1
[PATCH for v4.14 05/13] media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 124 +- 1 file changed, 24 insertions(+), 100 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 44644a2ea3e9..297c924aefce 100644 --- 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_window *kp, struct v4l2_window32 __user 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 v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(>fmt.pix, >fmt.pix); + return copy_from_user(>fmt.pix, >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(>fmt.pix_mp, - >fmt.pix_mp); + return copy_from_user(>fmt.pix_mp, >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(>fmt.win, >fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(>fmt.vbi, >fmt.vbi); +
[PATCH for v4.14 03/13] media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 821f2aa299ae..f6a7f8793720 100644 --- 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 *file, unsigned int cmd, unsigned long ar err = put_v4l2_create32(, up); break; + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: -- 2.15.1
[PATCH for v4.1 00/14] v4l2-compat-ioctl32.c: remove set_fs(KERNEL_DS)
From: Hans VerkuilThis patch series fixes a number of bugs and culminates in the removal of the set_fs(KERNEL_DS) call in v4l2-compat-ioctl32.c. This was tested with a VM running 4.1, the vivid driver (since that emulates almost all V4L2 ioctls that need to pass through v4l2-compat-ioctl32.c) and a 32-bit v4l2-compliance utility since that exercises almost all ioctls as well. Combined this gives good test coverage. Most of the v4l2-compat-ioctl32.c do cleanups and fix subtle issues that v4l2-compliance complained about. The purpose is to 1) make it easy to verify that the final patch didn't introduce errors by first eliminating errors caused by other known bugs, and 2) keep the final patch at least somewhat readable. Regards, Hans Daniel Mentz (2): media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic Hans Verkuil (11): media: v4l2-ioctl.c: don't copy back the result for -ENOTTY media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF media: v4l2-compat-ioctl32.c: fix the indentation media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 media: v4l2-compat-ioctl32.c: avoid sizeof(type) media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors Ricardo Ribalda Delgado (1): vb2: V4L2_BUF_FLAG_DONE is set after DQBUF drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1014 +++-- drivers/media/v4l2-core/v4l2-ioctl.c |5 +- drivers/media/v4l2-core/videobuf2-core.c |5 + 3 files changed, 625 insertions(+), 399 deletions(-) -- 2.15.1
[PATCH for v4.1 07/14] media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 47 --- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 03d1d92a2a8e..25a61fc27a36 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -290,19 +290,24 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ 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(>m.mem_offset, >m.mem_offset, +sizeof(up32->m.mem_offset))) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: if (get_user(p, >m.userptr)) return -EFAULT; up_pln = compat_ptr(p); if (put_user((unsigned long)up_pln, >m.userptr)) return -EFAULT; - } else if (memory == V4L2_MEMORY_DMABUF) { + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(>m.fd, >m.fd, sizeof(up32->m.fd))) return -EFAULT; - } else { - if (copy_in_user(>m.mem_offset, >m.mem_offset, -sizeof(up32->m.mem_offset))) - return -EFAULT; + break; } return 0; @@ -311,22 +316,32 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ 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(>data_offset, >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(>m.mem_offset, >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, >m.userptr) || + put_user((compat_ulong_t)ptr_to_compat((__force void *)p), +>m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(>m.fd, >m.fd, sizeof(up->m.fd))) return -EFAULT; + break; + } return 0; } @@ -386,6 +401,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (get_user(kp->m.offset, >m.offset)) return -EFAULT; break; @@ -399,10 +415,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, >m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (get_user(kp->m.fd, >m.fd)) return -EFAULT; @@ -459,6 +471,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (put_user(kp->m.offset, >m.offset)) return -EFAULT; break; @@ -466,10 +479,6 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
[PATCH for v4.1 09/14] media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 52205d37f97f..626a3b345075 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -603,7 +603,7 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) 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, ) && -- 2.15.1
[PATCH for v4.1 12/14] media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 1 file changed, 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 25cf19193c13..8371bbbda383 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -170,8 +170,6 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_from_user(>fmt.sliced, >fmt.sliced, sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } @@ -217,8 +215,6 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_to_user(>fmt.sliced, >fmt.sliced, sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } -- 2.15.1
[PATCH for v4.1 04/14] media: v4l2-compat-ioctl32.c: fix the indentation
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 216 +- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 42d402948ea2..ba6aaea11e2f 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -48,11 +48,11 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || - copy_from_user(>w, >w, sizeof(up->w)) || - get_user(kp->field, >field) || - get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount)) - return -EFAULT; + copy_from_user(>w, >w, sizeof(up->w)) || + get_user(kp->field, >field) || + get_user(kp->chromakey, >chromakey) || + get_user(kp->clipcount, >clipcount)) + return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; if (kp->clipcount) { @@ -82,10 +82,10 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (copy_to_user(>w, >w, sizeof(kp->w)) || - put_user(kp->field, >field) || - put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount)) - return -EFAULT; + put_user(kp->field, >field) || + put_user(kp->chromakey, >chromakey) || + put_user(kp->clipcount, >clipcount)) + return -EFAULT; return 0; } @@ -97,7 +97,7 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) +struct v4l2_pix_format_mplane __user *up) { if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -112,7 +112,7 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) +struct v4l2_pix_format_mplane __user *up) { if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -200,7 +200,7 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return get_v4l2_sliced_vbi_format(>fmt.sliced, >fmt.sliced); default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -244,7 +244,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return put_v4l2_sliced_vbi_format(>fmt.sliced, >fmt.sliced); default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -278,7 +278,7 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 { /* 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, >index)) + get_user(kp->index, >index)) return -EFAULT; return 0; } @@ -286,13 +286,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 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, >index) || - copy_to_user(up->id, >id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, 24) || - copy_to_user(>frameperiod, >frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, >framelines) || - copy_to_user(up->reserved,
[PATCH for v4.1 14/14] media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
From: Daniel Mentzcommit 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, >clipcount) || put_user(clipcount, >clipcount)) return -EFAULT; Notes from hans.verk...@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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 748 +- 1 file changed, 485 insertions(+), 263 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 3e1d3ed3561c..e03aa0961360 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -22,6 +22,14 @@ #include #include +/* Use the same argument order as copy_in_user */ +#define assign_in_user(to, from) \ +({ \ + typeof(*from) __assign_tmp; \ + \ + get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \ +}) + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = -ENOIOCTLCMD; @@ -35,12 +43,12 @@ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct v4l2_clip32 { struct v4l2_rectc; - compat_caddr_t next; + compat_caddr_t next; }; struct v4l2_window32 { struct v4l2_rectw; - __u32 field; /* enum v4l2_field */ + __u32 field; /* enum v4l2_field */ __u32 chromakey; compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; @@ -48,37 +56,41 @@ struct v4l2_window32 { __u8global_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
[PATCH for v4.1 03/14] media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 4f002d0bebb1..42d402948ea2 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -999,6 +999,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_create32(, up); break; + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: -- 2.15.1
[PATCH for v4.1 13/14] media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 8371bbbda383..3e1d3ed3561c 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -946,6 +946,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar 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. */ -- 2.15.1
[PATCH for v4.1 05/14] media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 84 +-- 1 file changed, 16 insertions(+), 68 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index ba6aaea11e2f..2a116d671f92 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -89,64 +89,6 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return 0; } -static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, -struct v4l2_pix_format_mplane __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, -struct v4l2_pix_format_mplane __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - struct v4l2_format32 { __u32 type; /* enum v4l2_buf_type */ union { @@ -184,20 +126,23 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(>fmt.pix, >fmt.pix); + return copy_from_user(>fmt.pix, >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(>fmt.pix_mp, - >fmt.pix_mp); + return copy_from_user(>fmt.pix_mp, >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(>fmt.win, >fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(>fmt.vbi, >fmt.vbi); + return copy_from_user(>fmt.vbi, >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(>fmt.sliced, >fmt.sliced); + return copy_from_user(>fmt.sliced, >fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", kp->type); @@ -228,20 +173,23 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return put_v4l2_pix_format(>fmt.pix, >fmt.pix); + return copy_to_user(>fmt.pix, >fmt.pix, +
[PATCH for v4.1 10/14] media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha
From: Daniel Mentzcommit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream. Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output overlays.") added the field global_alpha to struct v4l2_window but did not update the compat layer accordingly. This change adds global_alpha to struct v4l2_window32 and copies the value for global_alpha back and forth. Signed-off-by: Daniel Mentz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 626a3b345075..88e4f5716387 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -45,6 +45,7 @@ struct v4l2_window32 { compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; compat_caddr_t bitmap; + __u8global_alpha; }; static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) @@ -53,7 +54,8 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user copy_from_user(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || - get_user(kp->clipcount, >clipcount)) + get_user(kp->clipcount, >clipcount) || + get_user(kp->global_alpha, >global_alpha)) return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; @@ -86,7 +88,8 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (copy_to_user(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || - put_user(kp->clipcount, >clipcount)) + put_user(kp->clipcount, >clipcount) || + put_user(kp->global_alpha, >global_alpha)) return -EFAULT; return 0; } -- 2.15.1
[PATCH for v4.1 02/14] vb2: V4L2_BUF_FLAG_DONE is set after DQBUF
From: Ricardo Ribaldacommit 3171cc2b4eb9831ab4df1d80d0410a945b8bc84e upstream. According to the doc, V4L2_BUF_FLAG_DONE is cleared after DQBUF: V4L2_BUF_FLAG_DONE 0x0004 ... After calling the VIDIOC_QBUF or VIDIOC_DQBUF it is always cleared ... Unfortunately, it seems that videobuf2 keeps it set after DQBUF. This can be tested with vivid and dev_debug: [257604.338082] video1: VIDIOC_DQBUF: 71:33:25.00260479 index=3, type=vid-cap, flags=0x2004, field=none, sequence=163, memory=userptr, bytesused=460800, offset/userptr=0x344b000, length=460800 This patch forces FLAG_DONE to 0 after calling DQBUF. Reported-by: Dimitrios Katsaros Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index fd9b252e2b34..079ee4ae9436 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2119,6 +2119,11 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n dprintk(1, "dqbuf of buffer %d, with state %d\n", vb->v4l2_buf.index, vb->state); + /* +* After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be +* cleared. +*/ + b->flags &= ~V4L2_BUF_FLAG_DONE; return 0; } -- 2.15.1
[PATCH for v4.1 06/14] media: v4l2-compat-ioctl32.c: avoid sizeof(type)
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 74 +-- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 2a116d671f92..03d1d92a2a8e 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -47,7 +47,7 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || get_user(kp->chromakey, >chromakey) || @@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (get_user(p, >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(>c, >c, sizeof(uclips->c))) @@ -152,14 +152,14 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us 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(>format, >format); @@ -199,14 +199,14 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us 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; @@ -225,7 +225,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, >index)) return -EFAULT; return 0; @@ -233,13 +233,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 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, >index) || copy_to_user(up->id, >id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, 24) || + copy_to_user(up->name, kp->name, sizeof(up->name)) || copy_to_user(>frameperiod, >frameperiod, sizeof(kp->frameperiod)) || put_user(kp->framelines, >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; } @@ -287,7 +287,7 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(>data_offset,
[PATCH for v4.1 08/14] media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 57 ++- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 25a61fc27a36..52205d37f97f 100644 --- 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) @@ -578,24 +580,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) +/* Return true if this control is a pointer type. */ +static inline bool ctrl_is_pointer(struct file *file, u32 id) { - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; + 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, >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.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; @@ -627,7 +644,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return -EFAULT; if (get_user(id, >id)) return -EFAULT; - if (ctrl_is_pointer(id)) { + if (ctrl_is_pointer(file, id)) { void __user *s; if (get_user(p, >string)) @@ -642,7 +659,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext 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 = @@ -674,7 +693,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext /* 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; @@ -887,7 +906,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(, up); + err = get_v4l2_ext_controls32(file, , up);
[PATCH for v4.1 11/14] media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 59 ++- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 88e4f5716387..25cf19193c13 100644 --- 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(>w, >w, sizeof(up->w)) || get_user(kp->field, >field) || @@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user 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, >clips)) + n = kp->clipcount; + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (n--) { + if (copy_in_user(>c, >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(>c, >c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, >next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else - kp->clips = NULL; + if (put_user(n ? kclips + 1 : NULL, >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(>w, >w, sizeof(kp->w)) || put_user(kp->field, >field) || put_user(kp->chromakey, >chromakey) || put_user(kp->clipcount, >clipcount) || put_user(kp->global_alpha, >global_alpha)) return -EFAULT; + + if (!kp->clipcount) + return 0; + + if (get_user(p, >clips)) + return -EFAULT; + uclips = compat_ptr(p); + while (n--) { + if (copy_in_user(>c, >c, sizeof(uclips->c))) + return -EFAULT; + uclips++; + kclips++; + } return 0; } -- 2.15.1
[PATCH for v4.1 01/14] media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-ioctl.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index aa407cb5f830..7004477e7ffc 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2552,8 +2552,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, /* 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); -- 2.15.1
[PATCH for v4.4 09/14] media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 2104d3af94f5..0c3949a00570 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -612,7 +612,7 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) 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, ) && -- 2.15.1
[PATCH for v4.4 08/14] media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
From: Hans Verkuilcommit 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 --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 57 ++- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index af197980ab8e..2104d3af94f5 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -587,24 +589,39 @@ struct v4l2_ext_control32 { }; } __attribute__ ((packed)); -/* The following function really belong in v4l2-common, but that causes - a circular dependency between modules. We need to think about this, but - for now this will do. */ - -/* Return non-zero if this control is a pointer type. Currently only - type STRING is a pointer type. */ -static inline int ctrl_is_pointer(u32 id) +/* Return true if this control is a pointer type. */ +static inline bool ctrl_is_pointer(struct file *file, u32 id) { - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; + 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, >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.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); } -static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int get_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; @@ -636,7 +653,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return -EFAULT; if (get_user(id, >id)) return -EFAULT; - if (ctrl_is_pointer(id)) { + if (ctrl_is_pointer(file, id)) { void __user *s; if (get_user(p, >string)) @@ -651,7 +668,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return 0; } -static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int put_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols = @@ -683,7 +702,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext /* Do not modify the pointer when copying a pointer control. The contents of the pointer was changed, not the pointer itself. */ - if (ctrl_is_pointer(id)) + if (ctrl_is_pointer(file, id)) size -= sizeof(ucontrols->value64); if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; @@ -897,7 +916,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(, up); + err = get_v4l2_ext_controls32(file, , up);
exposing a large-ish calibration table through V4L2?
Hello Hans, I've picked up work on the sur40 driver again recently. There is one major feature left that is currently unsupported by the Linux driver, which is the hardware-based calibration. The internal device memory contains a table with two bytes for each sensor pixel (i.e. 960x540x2 = 1036800 bytes) that basically provide individual black and white levels per-pixel that are used in preprocessing. The table can either be set externally, or the sensor can be covered with a black/white surface and a custom command triggers an internal calibration. AFAICT the usual V4L2 controls are unsuitable for this sort of data; do you have any suggestions on how to approach this? Maybe something like a custom IOCTL? Best regards, Florian -- SENT FROM MY DEC VT50 TERMINAL signature.asc Description: OpenPGP digital signature
[PATCH v2] videodev2.h: add helper to validate colorspace
There is no way for drivers to validate a colorspace value, which could be provided by user-space by VIDIOC_S_FMT for example. Add a helper to validate that the colorspace value is part of enum v4l2_colorspace. Signed-off-by: Niklas Söderlund--- include/uapi/linux/videodev2.h | 4 1 file changed, 4 insertions(+) Hi, I hope this is the correct header to add this helper to. I think it's since if it's in uapi not only can v4l2 drivers use it but tools like v4l-compliance gets access to it and can be updated to use this instead of the hard-coded check of just < 0xff as it was last time I checked. * Changes since v1 - Cast colorspace to u32 as suggested by Sakari and only check the upper boundary to address a potential issue brought up by Laurent if the data type tested is u32 which is not uncommon: enum.c:30:16: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits] return V4L2_COLORSPACE_IS_VALID(colorspace); diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 9827189651801e12..1f27c0f4187cbded 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -238,6 +238,10 @@ enum v4l2_colorspace { V4L2_COLORSPACE_DCI_P3= 12, }; +/* Determine if a colorspace is defined in enum v4l2_colorspace */ +#define V4L2_COLORSPACE_IS_VALID(colorspace) \ + ((u32)(colorspace) <= V4L2_COLORSPACE_DCI_P3) + /* * Determine how COLORSPACE_DEFAULT should map to a proper colorspace. * This depends on whether this is a SDTV image (use SMPTE 170M), an -- 2.16.1
Re: [PATCH v2] videodev2.h: add helper to validate colorspace
On Wed, Feb 14, 2018 at 11:36:43AM +0100, Niklas Söderlund wrote: > There is no way for drivers to validate a colorspace value, which could > be provided by user-space by VIDIOC_S_FMT for example. Add a helper to > validate that the colorspace value is part of enum v4l2_colorspace. > > Signed-off-by: Niklas SöderlundAcked-by: Sakari Ailus > --- > include/uapi/linux/videodev2.h | 4 > 1 file changed, 4 insertions(+) > > Hi, > > I hope this is the correct header to add this helper to. I think it's > since if it's in uapi not only can v4l2 drivers use it but tools like > v4l-compliance gets access to it and can be updated to use this instead > of the hard-coded check of just < 0xff as it was last time I checked. > > * Changes since v1 > - Cast colorspace to u32 as suggested by Sakari and only check the upper > boundary to address a potential issue brought up by Laurent if the > data type tested is u32 which is not uncommon: > > enum.c:30:16: warning: comparison of unsigned expression >= 0 is always > true > [-Wtype-limits] > return V4L2_COLORSPACE_IS_VALID(colorspace); > > diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h > index 9827189651801e12..1f27c0f4187cbded 100644 > --- a/include/uapi/linux/videodev2.h > +++ b/include/uapi/linux/videodev2.h > @@ -238,6 +238,10 @@ enum v4l2_colorspace { > V4L2_COLORSPACE_DCI_P3= 12, > }; > > +/* Determine if a colorspace is defined in enum v4l2_colorspace */ > +#define V4L2_COLORSPACE_IS_VALID(colorspace) \ > + ((u32)(colorspace) <= V4L2_COLORSPACE_DCI_P3) > + > /* > * Determine how COLORSPACE_DEFAULT should map to a proper colorspace. > * This depends on whether this is a SDTV image (use SMPTE 170M), an > -- > 2.16.1 > -- Sakari Ailus e-mail: sakari.ai...@iki.fi
Re: i.MX53 using imx-media to capture analog video through ADV7180
[Adding Steve and Philipp in case they could provide some suggestions] On Wed, Feb 14, 2018 at 1:21 PM, Matthew Starrwrote: > I have successfully modified device tree files in the mainline 4.15.1 kernel > to get a display product using the i.MX53 processor to initialize the > imx-media drivers. I think up to this point they have only been tested on > i.MX6 processors. I am using two ADV7180 analog capture chips, one per CSI > port, on this display product. > > I have everything initialize successfully at boot, but I am unable to get the > media-ctl command to link the ADV7180 devices to the CSI ports. I used the > following website as guidance of how to setup the links between media devices: > https://linuxtv.org/downloads/v4l-dvb-apis/v4l-drivers/imx.html > > When trying to link the ADV7180 chip to a CSI port, I use the following > command and get the result below: > > media-ctl -v -l "'adv7180 1-0021':0->'ipu1_csi0':0[1]" > > No link between "adv7180 1-0021":0 and "ipu1_csi0":0 > media_parse_setup_link: Unable to parse link > Unable to parse link: Invalid argument (22) > > How do I get the ADV7180 and CSI port on the i.MX53 processor to link? > > The difference for the i.MX53 compared to the i.MX6 processor is that there > is only one IPU and no mipi support, so my device tree does not use any > video-mux or mux devices. Could this have something to do with why I can't > link the ADV7180 to the CSI port? > > Here is the output of the "media-ctl -p -v" command: > > Opening media device /dev/media0 > Enumerating entities > looking up device: 81:10 > looking up device: 81:11 > looking up device: 81:12 > looking up device: 81:4 > looking up device: 81:13 > looking up device: 81:5 > looking up device: 81:14 > looking up device: 81:15 > looking up device: 81:16 > looking up device: 81:17 > looking up device: 81:6 > looking up device: 81:18 > looking up device: 81:7 > looking up device: 81:19 > looking up device: 81:20 > looking up device: 81:8 > looking up device: 81:21 > looking up device: 81:9 > Found 18 entities > Enumerating pads and links > Media controller API version 4.15.1 > > Media device information > > driver imx-media > model imx-media > serial > bus info > hw revision 0x0 > driver version 4.15.1 > > Device topology > - entity 1: adv7180 1-0021 (1 pad, 0 link) > type V4L2 subdev subtype Unknown flags 20004 > device node name /dev/v4l-subdev0 > pad0: Source > [fmt:UYVY8_2X8/720x480 field:interlaced] > > - entity 3: adv7180 1-0020 (1 pad, 0 link) > type V4L2 subdev subtype Unknown flags 20004 > device node name /dev/v4l-subdev1 > pad0: Source > [fmt:UYVY8_2X8/720x480 field:interlaced] > > - entity 5: ipu1_csi1 (3 pads, 3 links) > type V4L2 subdev subtype Unknown flags 0 > device node name /dev/v4l-subdev2 > pad0: Sink > [fmt:UYVY8_2X8/640x480 field:none > crop.bounds:(0,0)/640x480 > crop:(0,0)/640x480 > compose.bounds:(0,0)/640x480 > compose:(0,0)/640x480] > pad1: Source > [fmt:AYUV8_1X32/640x480 field:none] > -> "ipu1_ic_prp":0 [] > -> "ipu1_vdic":0 [] > pad2: Source > [fmt:AYUV8_1X32/640x480 field:none] > -> "ipu1_csi1 capture":0 [] > > - entity 9: ipu1_csi1 capture (1 pad, 1 link) > type Node subtype V4L flags 0 > device node name /dev/video4 > pad0: Sink > <- "ipu1_csi1":2 [] > > - entity 15: ipu1_csi0 (3 pads, 3 links) > type V4L2 subdev subtype Unknown flags 0 > device node name /dev/v4l-subdev3 > pad0: Sink > [fmt:UYVY8_2X8/640x480 field:none > crop.bounds:(0,0)/640x480 > crop:(0,0)/640x480 > compose.bounds:(0,0)/640x480 > compose:(0,0)/640x480] > pad1: Source > [fmt:AYUV8_1X32/640x480 field:none] > -> "ipu1_ic_prp":0 [] > -> "ipu1_vdic":0 [ENABLED] > pad2: Source > [fmt:AYUV8_1X32/640x480 field:none] > -> "ipu1_csi0 capture":0 [] > > - entity 19: ipu1_csi0 capture (1 pad, 1 link) > type Node subtype V4L flags 0 > device node name /dev/video5 > pad0: Sink > <- "ipu1_csi0":2 [] > > - entity 25: ipu1_ic_prp (3 pads, 5 links) > type V4L2 subdev subtype Unknown flags 0 > device node name /dev/v4l-subdev4 > pad0: Sink > [fmt:AYUV8_1X32/640x480 field:none] > <- "ipu1_csi1":1 [] > <- "ipu1_csi0":1 [] > <- "ipu1_vdic":2 [ENABLED] > pad1: Source >
Re: [PATCH v4 16/18] scripts: kernel-doc: improve nested logic to handle multiple identifiers
On Mon, 18 Dec 2017, Mauro Carvalho Chehabwrote: > It is possible to use nested structs like: > > struct { > struct { > void *arg1; > } st1, st2, *st3, st4; > }; > > Handling it requires to split each parameter. Change the logic > to allow such definitions. > > In order to test the new nested logic, the following file > was used to test Hi Mauro, resurrecting an old thread... So this was a great improvement to documenting nested structs. However, it looks like it only supports describing the nested structs at the top level comment, and fails for inline documentation comments. For example, in v4.16-rc1: $ scripts/kernel-doc -none drivers/gpu/drm/i915/intel_dpio_phy.c drivers/gpu/drm/i915/intel_dpio_phy.c:154: warning: Function parameter or member 'channel.port' not described in 'bxt_ddi_phy_info' The struct in question is: /** * struct bxt_ddi_phy_info - Hold info for a broxton DDI phy */ struct bxt_ddi_phy_info { /* [some members removed] */ /** * @channel: struct containing per channel information. */ struct { /** * @port: which port maps to this channel. */ enum port port; } channel[2]; }; Apparently the only way to currently do this is to add channel.port at the top level: /** * struct bxt_ddi_phy_info - Hold info for a broxton DDI phy * @channel.port: which port maps to this channel. */ Which is less than perfect if you have everything else described inline. :( BR, Jani. > > > struct foo { int a; }; /* Just to avoid errors if compiled */ > > /** > * struct my_struct - a struct with nested unions and structs > * @arg1: first argument of anonymous union/anonymous struct > * @arg2: second argument of anonymous union/anonymous struct > * @arg1b: first argument of anonymous union/anonymous struct > * @arg2b: second argument of anonymous union/anonymous struct > * @arg3: third argument of anonymous union/anonymous struct > * @arg4: fourth argument of anonymous union/anonymous struct > * @bar.st1.arg1: first argument of struct st1 on union bar > * @bar.st1.arg2: second argument of struct st1 on union bar > * @bar.st1.bar1: bar1 at st1 > * @bar.st1.bar2: bar2 at st1 > * @bar.st2.arg1: first argument of struct st2 on union bar > * @bar.st2.arg2: second argument of struct st2 on union bar > * @bar.st3.arg2: second argument of struct st3 on union bar > * @f1: nested function on anonimous union/struct > * @bar.st2.f2: nested function on named union/struct > */ > struct my_struct { >/* Anonymous union/struct*/ >union { > struct { > char arg1 : 1; > char arg2 : 3; > }; >struct { >int arg1b; >int arg2b; >}; >struct { >void *arg3; >int arg4; >int (*f1)(char foo, int bar); >}; >}; >union { >struct { >int arg1; >int arg2; > struct foo bar1, *bar2; >} st1; /* bar.st1 is undocumented, cause a warning */ >struct { >void *arg1; /* bar.st3.arg1 is undocumented, cause a warning */ > int arg2; > int (*f2)(char foo, int bar); /* bar.st3.fn2 is undocumented, cause > a warning */ >} st2, st3, *st4; >int (*f3)(char foo, int bar); /* f3 is undocumented, cause a warning */ >} bar; /* bar is undocumented, cause a warning */ > >/* private: */ >int undoc_privat;/* is undocumented but private, no warning */ > >/* public: */ >int undoc_public;/* is undocumented, cause a warning */ > }; > > > It produces the following warnings, as expected: > > test2.h:57: warning: Function parameter or member 'bar' not described in > 'my_struct' > test2.h:57: warning: Function parameter or member 'bar.st1' not described in > 'my_struct' > test2.h:57: warning: Function parameter or member 'bar.st2' not described in > 'my_struct' > test2.h:57: warning: Function parameter or member 'bar.st3' not described in > 'my_struct' > test2.h:57: warning: Function parameter or member 'bar.st3.arg1' not > described in 'my_struct' > test2.h:57: warning: Function parameter or member 'bar.st3.f2' not described > in 'my_struct' > test2.h:57: warning: Function parameter or member 'bar.st4' not described in > 'my_struct' > test2.h:57: warning: Function parameter or member 'bar.st4.arg1' not > described in 'my_struct' > test2.h:57: warning: Function parameter or member 'bar.st4.arg2' not > described in 'my_struct' > test2.h:57: warning: Function parameter or member 'bar.st4.f2' not described > in 'my_struct' > test2.h:57: warning: Function parameter or member 'bar.f3' not described in > 'my_struct' > test2.h:57: warning: Function parameter or member 'undoc_public' not > described in 'my_struct' > > Suggested-by: Markus Heiser >
Re: [PATCHv2 3/9] staging: atomisp: Kill subdev s_parm abuse
Sakari, Em Mon, 22 Jan 2018 13:31:19 +0100 Hans Verkuilescreveu: > From: Sakari Ailus > > Remove sensor driver's interface that made use of use case specific > knowledge of platform capabilities. Could you better describe it? What s_param abuse? What happens after this patch? It seems that atomISP relies on gc0310_res. So, I would be expecting that a patch removing s_param would be also adding/changing other parts of the code accordingly, in order to get rid of that as a hole (or initialize it somewhere else). Regards, Mauro > > Signed-off-by: Sakari Ailus > Signed-off-by: Hans Verkuil > --- > drivers/staging/media/atomisp/i2c/atomisp-gc0310.c | 26 - > drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 26 - > drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 29 - > drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 26 - > drivers/staging/media/atomisp/i2c/gc0310.h | 43 -- > drivers/staging/media/atomisp/i2c/gc2235.h | 1 - > drivers/staging/media/atomisp/i2c/ov2680.h | 68 > -- > .../media/atomisp/i2c/ov5693/atomisp-ov5693.c | 27 - > .../media/atomisp/pci/atomisp2/atomisp_cmd.c | 9 +-- > .../media/atomisp/pci/atomisp2/atomisp_subdev.c| 12 +--- > 10 files changed, 3 insertions(+), 264 deletions(-) > > diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c > b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c > index 61b7598469eb..572c9127c24d 100644 > --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c > +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c > @@ -1224,37 +1224,12 @@ static int gc0310_g_parm(struct v4l2_subdev *sd, > if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { > param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; > param->parm.capture.timeperframe.numerator = 1; > - param->parm.capture.capturemode = dev->run_mode; > param->parm.capture.timeperframe.denominator = > gc0310_res[dev->fmt_idx].fps; > } > return 0; > } > > -static int gc0310_s_parm(struct v4l2_subdev *sd, > - struct v4l2_streamparm *param) > -{ > - struct gc0310_device *dev = to_gc0310_sensor(sd); > - dev->run_mode = param->parm.capture.capturemode; > - > - mutex_lock(>input_lock); > - switch (dev->run_mode) { > - case CI_MODE_VIDEO: > - gc0310_res = gc0310_res_video; > - N_RES = N_RES_VIDEO; > - break; > - case CI_MODE_STILL_CAPTURE: > - gc0310_res = gc0310_res_still; > - N_RES = N_RES_STILL; > - break; > - default: > - gc0310_res = gc0310_res_preview; > - N_RES = N_RES_PREVIEW; > - } > - mutex_unlock(>input_lock); > - return 0; > -} > - > static int gc0310_g_frame_interval(struct v4l2_subdev *sd, > struct v4l2_subdev_frame_interval *interval) > { > @@ -1314,7 +1289,6 @@ static const struct v4l2_subdev_sensor_ops > gc0310_sensor_ops = { > static const struct v4l2_subdev_video_ops gc0310_video_ops = { > .s_stream = gc0310_s_stream, > .g_parm = gc0310_g_parm, > - .s_parm = gc0310_s_parm, > .g_frame_interval = gc0310_g_frame_interval, > }; > > diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c > b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c > index d8de46da64ae..2bc179f3afe5 100644 > --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c > +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c > @@ -964,37 +964,12 @@ static int gc2235_g_parm(struct v4l2_subdev *sd, > if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { > param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; > param->parm.capture.timeperframe.numerator = 1; > - param->parm.capture.capturemode = dev->run_mode; > param->parm.capture.timeperframe.denominator = > gc2235_res[dev->fmt_idx].fps; > } > return 0; > } > > -static int gc2235_s_parm(struct v4l2_subdev *sd, > - struct v4l2_streamparm *param) > -{ > - struct gc2235_device *dev = to_gc2235_sensor(sd); > - dev->run_mode = param->parm.capture.capturemode; > - > - mutex_lock(>input_lock); > - switch (dev->run_mode) { > - case CI_MODE_VIDEO: > - gc2235_res = gc2235_res_video; > - N_RES = N_RES_VIDEO; > - break; > - case CI_MODE_STILL_CAPTURE: > - gc2235_res = gc2235_res_still; > - N_RES = N_RES_STILL; > - break; > - default: > - gc2235_res = gc2235_res_preview; > - N_RES = N_RES_PREVIEW; > - } > - mutex_unlock(>input_lock); > - return 0; > -} > - > static int
Re: [PATCH v7 2/2] v4l: cadence: Add Cadence MIPI-CSI2 RX driver
Hi Maxime, On Wednesday, 14 February 2018 15:19:33 EET Maxime Ripard wrote: > On Thu, Feb 08, 2018 at 08:17:19PM +0200, Laurent Pinchart wrote: > >> + /* > >> + * Create a static mapping between the CSI virtual channels > >> + * and the output stream. > >> + * > >> + * This should be enhanced, but v4l2 lacks the support for > >> + * changing that mapping dynamically. > >> + * > >> + * We also cannot enable and disable independant streams here, > >> + * hence the reference counting. > >> + */ > > > > If you start all streams in one go, will s_stream(1) be called multiple > > times ? If not, you could possibly skip the whole reference counting and > > avoid locking. > > I guess that while we should expect the CSI-2 bus to be always > enabled, the downstream camera interface could be shutdown > independently, so I guess s_stream would be called each time one is > brought up or brought down? That's the idea. However, we don't have support for multiplexed streams in mainline yet, so there's no way it can be implemented today in your driver. -- Regards, Laurent Pinchart
Re: [PATCH v10 6/8] media: i2c: Add TDA1997x HDMI receiver driver
On Wed, Feb 14, 2018 at 6:08 AM, Hans Verkuilwrote: > Hi Tim, > > On 12/02/18 23:27, Tim Harvey wrote: >> On Fri, Feb 9, 2018 at 12:08 AM, Hans Verkuil wrote: >>> Hi Tim, >>> >>> We're almost there. Two more comments: >>> >>> On 02/09/2018 07:32 AM, Tim Harvey wrote: +static int +tda1997x_detect_std(struct tda1997x_state *state, + struct v4l2_dv_timings *timings) +{ + struct v4l2_subdev *sd = >sd; + u32 vper; + u16 hper; + u16 hsper; + int i; + + /* + * Read the FMT registers + * REG_V_PER: Period of a frame (or two fields) in MCLK(27MHz) cycles + * REG_H_PER: Period of a line in MCLK(27MHz) cycles + * REG_HS_WIDTH: Period of horiz sync pulse in MCLK(27MHz) cycles + */ + vper = io_read24(sd, REG_V_PER) & MASK_VPER; + hper = io_read16(sd, REG_H_PER) & MASK_HPER; + hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH; + if (!vper || !hper || !hsper) + return -ENOLINK; >>> >>> See my comment for g_input_status below. This condition looks more like a >>> ENOLCK. >>> >>> Or perhaps it should be: >>> >>> if (!vper && !hper && !hsper) >>> return -ENOLINK; >>> if (!vper || !hper || !hsper) >>> return -ENOLCK; >>> >>> I would recommend that you test a bit with no signal and a bad signal >>> (perhaps >>> one that uses a pixelclock that is too high for this device?). >> >> I can't figure out how to produce a signal that can't be locked onto >> with what I have available. > > Are you using a signal generator or just a laptop or something similar as the > source? > > Without a good signal generator it is tricky to test this. A very long HDMI > cable would likely do it. But for 1080p60 you probably need 20 meters or > more. > I'm using a Marshall V-SG4K-HDI (http://www.lcdracks.com/racks/DLW/V-SG4K-HDI-signal-generator.php). It does support 'user defined timings' (see http://www.lcdracks.com/racks/pdf-pages/instruction_sheets/V-SG4K-HDI_Manual-web.pdf Timings Details Menu page) and it looks like the max pixel-clock is 300MHz so perhaps I can create a timing that can't be locked onto that way. The TDA19971 datasheet (http://tharvey/src/nxp/tda1997x/TDA19971-datasheet-rev3.pdf) says it supports: - All HDTV formats up to 1920x1080p at 50/60 Hz with support for reduced blanking - 3D formats including all primary formats up to 1920x1080p at 30 Hz Frame Packing and 1920x1080p at 60 Hz Side-by-Side and Top-and-Bottom - PC formats up to UXGA (1600x1200p at 60 Hz) and WUXGA (1920x1200p at 60 Hz) >> >>> +static int +tda1997x_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + struct tda1997x_state *state = to_state(sd); + u32 vper; + u16 hper; + u16 hsper; + + mutex_lock(>lock); + v4l2_dbg(1, debug, sd, "inputs:%d/%d\n", + state->input_detect[0], state->input_detect[1]); + if (state->input_detect[0] || state->input_detect[1]) >>> >>> I'm confused. This device has two HDMI inputs? >>> >>> Does 'detecting input' equate to 'I see a signal and I am locked'? >>> I gather from the irq function that sets these values that it is closer >>> to 'I see a signal' and that 'I am locked' is something you would test >>> by looking at the vper/hper/hsper. >> >> The TDA19972 and/or TDA19973 has an A and B input but only a single >> output. I'm not entirely clear if/how to select between the two and I >> don't have proper documentation for the three chips. >> >> The TDA19971 which I have on my board only has 1 input which is >> reported as the 'A' input. I can likely nuke the stuff looking at the >> B input and/or put some qualifiers around it but I didn't want to >> remove code that was derived from some vendor code that might help >> support the other chips in the future. So I would rather like to leave >> the 'if A or B' stuff. > > OK. Can you add a comment somewhere in the driver about this? > > It sounds like it is similar to what the adv7604 has: several inputs but > only one is used for streaming. But the EDID is made available on both inputs. > sure, I will comment about it. I believe that is the way the it works as well. >>> + *status = 0; + else { + vper = io_read24(sd, REG_V_PER) & MASK_VPER; + hper = io_read16(sd, REG_H_PER) & MASK_HPER; + hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH; + v4l2_dbg(1, debug, sd, "timings:%d/%d/%d\n", vper, hper, hsper); + if (!vper || !hper || !hsper) + *status |= V4L2_IN_ST_NO_SYNC; + else + *status |= V4L2_IN_ST_NO_SIGNAL; >>> >>> So if we have valid vper, hper and hsper, then there is no signal? That >>>