|
@@ -97,6 +97,14 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi
|
|
return 0;
|
|
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)
|
|
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)))
|
|
if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
|
|
@@ -104,6 +112,14 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi
|
|
return 0;
|
|
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)
|
|
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)))
|
|
if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
|
|
@@ -136,6 +152,7 @@ struct v4l2_format32 {
|
|
enum v4l2_buf_type type;
|
|
enum v4l2_buf_type type;
|
|
union {
|
|
union {
|
|
struct v4l2_pix_format pix;
|
|
struct v4l2_pix_format pix;
|
|
|
|
+ struct v4l2_pix_format_mplane pix_mp;
|
|
struct v4l2_window32 win;
|
|
struct v4l2_window32 win;
|
|
struct v4l2_vbi_format vbi;
|
|
struct v4l2_vbi_format vbi;
|
|
struct v4l2_sliced_vbi_format sliced;
|
|
struct v4l2_sliced_vbi_format sliced;
|
|
@@ -152,6 +169,10 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
|
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
|
|
return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
|
|
|
|
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
|
|
|
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
|
|
|
+ return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
|
|
|
|
+ &up->fmt.pix_mp);
|
|
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
|
|
return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
|
|
@@ -181,6 +202,10 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
|
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
|
|
return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
|
|
|
|
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
|
|
|
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
|
|
|
+ return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
|
|
|
|
+ &up->fmt.pix_mp);
|
|
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
|
|
return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
|
|
@@ -232,6 +257,17 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+struct v4l2_plane32 {
|
|
|
|
+ __u32 bytesused;
|
|
|
|
+ __u32 length;
|
|
|
|
+ union {
|
|
|
|
+ __u32 mem_offset;
|
|
|
|
+ compat_long_t userptr;
|
|
|
|
+ } m;
|
|
|
|
+ __u32 data_offset;
|
|
|
|
+ __u32 reserved[11];
|
|
|
|
+};
|
|
|
|
+
|
|
struct v4l2_buffer32 {
|
|
struct v4l2_buffer32 {
|
|
__u32 index;
|
|
__u32 index;
|
|
enum v4l2_buf_type type;
|
|
enum v4l2_buf_type type;
|
|
@@ -247,14 +283,64 @@ struct v4l2_buffer32 {
|
|
union {
|
|
union {
|
|
__u32 offset;
|
|
__u32 offset;
|
|
compat_long_t userptr;
|
|
compat_long_t userptr;
|
|
|
|
+ compat_caddr_t planes;
|
|
} m;
|
|
} m;
|
|
__u32 length;
|
|
__u32 length;
|
|
__u32 input;
|
|
__u32 input;
|
|
__u32 reserved;
|
|
__u32 reserved;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
|
|
|
|
+ enum v4l2_memory memory)
|
|
|
|
+{
|
|
|
|
+ void __user *up_pln;
|
|
|
|
+ compat_long_t p;
|
|
|
|
+
|
|
|
|
+ if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
|
|
|
|
+ copy_in_user(&up->data_offset, &up32->data_offset,
|
|
|
|
+ sizeof(__u32)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ if (memory == V4L2_MEMORY_USERPTR) {
|
|
|
|
+ if (get_user(p, &up32->m.userptr))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ up_pln = compat_ptr(p);
|
|
|
|
+ if (put_user((unsigned long)up_pln, &up->m.userptr))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ } else {
|
|
|
|
+ if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
|
|
|
|
+ sizeof(__u32)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
|
|
|
|
+ enum v4l2_memory memory)
|
|
|
|
+{
|
|
|
|
+ if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
|
|
|
|
+ copy_in_user(&up32->data_offset, &up->data_offset,
|
|
|
|
+ sizeof(__u32)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ /* For MMAP, driver might've set up the offset, so copy it back.
|
|
|
|
+ * USERPTR stays the same (was userspace-provided), so no copying. */
|
|
|
|
+ if (memory == V4L2_MEMORY_MMAP)
|
|
|
|
+ if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
|
|
|
|
+ sizeof(__u32)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
|
|
static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
|
|
{
|
|
{
|
|
|
|
+ struct v4l2_plane32 __user *uplane32;
|
|
|
|
+ struct v4l2_plane __user *uplane;
|
|
|
|
+ compat_caddr_t p;
|
|
|
|
+ int num_planes;
|
|
|
|
+ int ret;
|
|
|
|
|
|
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
|
|
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
|
|
get_user(kp->index, &up->index) ||
|
|
get_user(kp->index, &up->index) ||
|
|
@@ -263,33 +349,84 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
|
|
get_user(kp->memory, &up->memory) ||
|
|
get_user(kp->memory, &up->memory) ||
|
|
get_user(kp->input, &up->input))
|
|
get_user(kp->input, &up->input))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
- switch (kp->memory) {
|
|
|
|
- case V4L2_MEMORY_MMAP:
|
|
|
|
- if (get_user(kp->length, &up->length) ||
|
|
|
|
- get_user(kp->m.offset, &up->m.offset))
|
|
|
|
|
|
+
|
|
|
|
+ if (V4L2_TYPE_IS_OUTPUT(kp->type))
|
|
|
|
+ if (get_user(kp->bytesused, &up->bytesused) ||
|
|
|
|
+ get_user(kp->field, &up->field) ||
|
|
|
|
+ get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
|
|
|
|
+ get_user(kp->timestamp.tv_usec,
|
|
|
|
+ &up->timestamp.tv_usec))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
- break;
|
|
|
|
- case V4L2_MEMORY_USERPTR:
|
|
|
|
- {
|
|
|
|
- compat_long_t tmp;
|
|
|
|
|
|
|
|
- if (get_user(kp->length, &up->length) ||
|
|
|
|
- get_user(tmp, &up->m.userptr))
|
|
|
|
|
|
+ if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
|
|
|
|
+ if (get_user(kp->length, &up->length))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
|
|
|
|
- kp->m.userptr = (unsigned long)compat_ptr(tmp);
|
|
|
|
|
|
+ num_planes = kp->length;
|
|
|
|
+ if (num_planes == 0) {
|
|
|
|
+ kp->m.planes = NULL;
|
|
|
|
+ /* num_planes == 0 is legal, e.g. when userspace doesn't
|
|
|
|
+ * need planes array on DQBUF*/
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
- break;
|
|
|
|
- case V4L2_MEMORY_OVERLAY:
|
|
|
|
- if (get_user(kp->m.offset, &up->m.offset))
|
|
|
|
|
|
+
|
|
|
|
+ if (get_user(p, &up->m.planes))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
- break;
|
|
|
|
|
|
+
|
|
|
|
+ uplane32 = compat_ptr(p);
|
|
|
|
+ if (!access_ok(VERIFY_READ, uplane32,
|
|
|
|
+ num_planes * sizeof(struct v4l2_plane32)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ /* We don't really care if userspace decides to kill itself
|
|
|
|
+ * by passing a very big num_planes value */
|
|
|
|
+ uplane = compat_alloc_user_space(num_planes *
|
|
|
|
+ sizeof(struct v4l2_plane));
|
|
|
|
+ kp->m.planes = uplane;
|
|
|
|
+
|
|
|
|
+ while (--num_planes >= 0) {
|
|
|
|
+ ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+ ++uplane;
|
|
|
|
+ ++uplane32;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ switch (kp->memory) {
|
|
|
|
+ case V4L2_MEMORY_MMAP:
|
|
|
|
+ if (get_user(kp->length, &up->length) ||
|
|
|
|
+ get_user(kp->m.offset, &up->m.offset))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ break;
|
|
|
|
+ case V4L2_MEMORY_USERPTR:
|
|
|
|
+ {
|
|
|
|
+ compat_long_t tmp;
|
|
|
|
+
|
|
|
|
+ if (get_user(kp->length, &up->length) ||
|
|
|
|
+ get_user(tmp, &up->m.userptr))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ kp->m.userptr = (unsigned long)compat_ptr(tmp);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case V4L2_MEMORY_OVERLAY:
|
|
|
|
+ if (get_user(kp->m.offset, &up->m.offset))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
|
|
static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
|
|
{
|
|
{
|
|
|
|
+ struct v4l2_plane32 __user *uplane32;
|
|
|
|
+ struct v4l2_plane __user *uplane;
|
|
|
|
+ compat_caddr_t p;
|
|
|
|
+ int num_planes;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
|
|
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
|
|
put_user(kp->index, &up->index) ||
|
|
put_user(kp->index, &up->index) ||
|
|
put_user(kp->type, &up->type) ||
|
|
put_user(kp->type, &up->type) ||
|
|
@@ -297,22 +434,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
|
|
put_user(kp->memory, &up->memory) ||
|
|
put_user(kp->memory, &up->memory) ||
|
|
put_user(kp->input, &up->input))
|
|
put_user(kp->input, &up->input))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
- switch (kp->memory) {
|
|
|
|
- case V4L2_MEMORY_MMAP:
|
|
|
|
- if (put_user(kp->length, &up->length) ||
|
|
|
|
- put_user(kp->m.offset, &up->m.offset))
|
|
|
|
- return -EFAULT;
|
|
|
|
- break;
|
|
|
|
- case V4L2_MEMORY_USERPTR:
|
|
|
|
- if (put_user(kp->length, &up->length) ||
|
|
|
|
- put_user(kp->m.userptr, &up->m.userptr))
|
|
|
|
- return -EFAULT;
|
|
|
|
- break;
|
|
|
|
- case V4L2_MEMORY_OVERLAY:
|
|
|
|
- if (put_user(kp->m.offset, &up->m.offset))
|
|
|
|
- return -EFAULT;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
if (put_user(kp->bytesused, &up->bytesused) ||
|
|
if (put_user(kp->bytesused, &up->bytesused) ||
|
|
put_user(kp->field, &up->field) ||
|
|
put_user(kp->field, &up->field) ||
|
|
put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
|
|
put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
|
|
@@ -321,6 +443,43 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
|
|
put_user(kp->sequence, &up->sequence) ||
|
|
put_user(kp->sequence, &up->sequence) ||
|
|
put_user(kp->reserved, &up->reserved))
|
|
put_user(kp->reserved, &up->reserved))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
|
|
+
|
|
|
|
+ if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
|
|
|
|
+ num_planes = kp->length;
|
|
|
|
+ if (num_planes == 0)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ uplane = kp->m.planes;
|
|
|
|
+ if (get_user(p, &up->m.planes))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ uplane32 = compat_ptr(p);
|
|
|
|
+
|
|
|
|
+ while (--num_planes >= 0) {
|
|
|
|
+ ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+ ++uplane;
|
|
|
|
+ ++uplane32;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ switch (kp->memory) {
|
|
|
|
+ case V4L2_MEMORY_MMAP:
|
|
|
|
+ if (put_user(kp->length, &up->length) ||
|
|
|
|
+ put_user(kp->m.offset, &up->m.offset))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ break;
|
|
|
|
+ case V4L2_MEMORY_USERPTR:
|
|
|
|
+ if (put_user(kp->length, &up->length) ||
|
|
|
|
+ put_user(kp->m.userptr, &up->m.userptr))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ break;
|
|
|
|
+ case V4L2_MEMORY_OVERLAY:
|
|
|
|
+ if (put_user(kp->m.offset, &up->m.offset))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -442,12 +601,13 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
|
|
if (get_user(p, &up->controls))
|
|
if (get_user(p, &up->controls))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
ucontrols = compat_ptr(p);
|
|
ucontrols = compat_ptr(p);
|
|
- if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control)))
|
|
|
|
|
|
+ if (!access_ok(VERIFY_READ, ucontrols,
|
|
|
|
+ n * sizeof(struct v4l2_ext_control32)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
|
|
kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
|
|
kp->controls = kcontrols;
|
|
kp->controls = kcontrols;
|
|
while (--n >= 0) {
|
|
while (--n >= 0) {
|
|
- if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
|
|
|
|
|
|
+ if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
if (ctrl_is_pointer(kcontrols->id)) {
|
|
if (ctrl_is_pointer(kcontrols->id)) {
|
|
void __user *s;
|
|
void __user *s;
|
|
@@ -483,7 +643,8 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
|
|
if (get_user(p, &up->controls))
|
|
if (get_user(p, &up->controls))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
ucontrols = compat_ptr(p);
|
|
ucontrols = compat_ptr(p);
|
|
- if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control)))
|
|
|
|
|
|
+ if (!access_ok(VERIFY_WRITE, ucontrols,
|
|
|
|
+ n * sizeof(struct v4l2_ext_control32)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
|
|
|
|
while (--n >= 0) {
|
|
while (--n >= 0) {
|