Commit f1c32afd authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '20160610_uvc_compat_for_linus' of...

Merge tag '20160610_uvc_compat_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/luto/linux

Pull uvc compat XU ioctl fixes from Andy Lutomirski:
 "uvc's compat XU ioctls go through tons of potentially buggy
  indirection.  The first patch removes the indirection.  The second one
  cleans up the code.

  Compile-tested only.  I have the hardware, but I have absolutely no
  idea what XU does, how to use it, what software to recompile as
  32-bit, or what to test in that software"

* tag '20160610_uvc_compat_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/luto/linux:
  uvc_v4l2: Simplify compat ioctl implementation
  uvc: Forward compat ioctls to their handlers directly
parents 3d0f0b6a f89dec72
...@@ -1274,8 +1274,6 @@ struct uvc_xu_control_mapping32 { ...@@ -1274,8 +1274,6 @@ struct uvc_xu_control_mapping32 {
static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp,
const struct uvc_xu_control_mapping32 __user *up) const struct uvc_xu_control_mapping32 __user *up)
{ {
struct uvc_menu_info __user *umenus;
struct uvc_menu_info __user *kmenus;
compat_caddr_t p; compat_caddr_t p;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
...@@ -1292,17 +1290,7 @@ static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, ...@@ -1292,17 +1290,7 @@ static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp,
if (__get_user(p, &up->menu_info)) if (__get_user(p, &up->menu_info))
return -EFAULT; return -EFAULT;
umenus = compat_ptr(p); kp->menu_info = compat_ptr(p);
if (!access_ok(VERIFY_READ, umenus, kp->menu_count * sizeof(*umenus)))
return -EFAULT;
kmenus = compat_alloc_user_space(kp->menu_count * sizeof(*kmenus));
if (kmenus == NULL)
return -EFAULT;
kp->menu_info = kmenus;
if (copy_in_user(kmenus, umenus, kp->menu_count * sizeof(*umenus)))
return -EFAULT;
return 0; return 0;
} }
...@@ -1310,10 +1298,6 @@ static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, ...@@ -1310,10 +1298,6 @@ static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp,
static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp, static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
struct uvc_xu_control_mapping32 __user *up) struct uvc_xu_control_mapping32 __user *up)
{ {
struct uvc_menu_info __user *umenus;
struct uvc_menu_info __user *kmenus = kp->menu_info;
compat_caddr_t p;
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
__copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) || __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) ||
__put_user(kp->menu_count, &up->menu_count)) __put_user(kp->menu_count, &up->menu_count))
...@@ -1322,16 +1306,6 @@ static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp, ...@@ -1322,16 +1306,6 @@ static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
if (__clear_user(up->reserved, sizeof(up->reserved))) if (__clear_user(up->reserved, sizeof(up->reserved)))
return -EFAULT; return -EFAULT;
if (kp->menu_count == 0)
return 0;
if (get_user(p, &up->menu_info))
return -EFAULT;
umenus = compat_ptr(p);
if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus)))
return -EFAULT;
return 0; return 0;
} }
...@@ -1346,8 +1320,6 @@ struct uvc_xu_control_query32 { ...@@ -1346,8 +1320,6 @@ struct uvc_xu_control_query32 {
static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp, static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp,
const struct uvc_xu_control_query32 __user *up) const struct uvc_xu_control_query32 __user *up)
{ {
u8 __user *udata;
u8 __user *kdata;
compat_caddr_t p; compat_caddr_t p;
if (!access_ok(VERIFY_READ, up, sizeof(*up)) || if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
...@@ -1361,17 +1333,7 @@ static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp, ...@@ -1361,17 +1333,7 @@ static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp,
if (__get_user(p, &up->data)) if (__get_user(p, &up->data))
return -EFAULT; return -EFAULT;
udata = compat_ptr(p); kp->data = compat_ptr(p);
if (!access_ok(VERIFY_READ, udata, kp->size))
return -EFAULT;
kdata = compat_alloc_user_space(kp->size);
if (kdata == NULL)
return -EFAULT;
kp->data = kdata;
if (copy_in_user(kdata, udata, kp->size))
return -EFAULT;
return 0; return 0;
} }
...@@ -1379,26 +1341,10 @@ static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp, ...@@ -1379,26 +1341,10 @@ static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp,
static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp,
struct uvc_xu_control_query32 __user *up) struct uvc_xu_control_query32 __user *up)
{ {
u8 __user *udata;
u8 __user *kdata = kp->data;
compat_caddr_t p;
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
__copy_to_user(up, kp, offsetof(typeof(*up), data))) __copy_to_user(up, kp, offsetof(typeof(*up), data)))
return -EFAULT; return -EFAULT;
if (kp->size == 0)
return 0;
if (get_user(p, &up->data))
return -EFAULT;
udata = compat_ptr(p);
if (!access_ok(VERIFY_READ, udata, kp->size))
return -EFAULT;
if (copy_in_user(udata, kdata, kp->size))
return -EFAULT;
return 0; return 0;
} }
...@@ -1408,47 +1354,44 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, ...@@ -1408,47 +1354,44 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp,
static long uvc_v4l2_compat_ioctl32(struct file *file, static long uvc_v4l2_compat_ioctl32(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct uvc_fh *handle = file->private_data;
union { union {
struct uvc_xu_control_mapping xmap; struct uvc_xu_control_mapping xmap;
struct uvc_xu_control_query xqry; struct uvc_xu_control_query xqry;
} karg; } karg;
void __user *up = compat_ptr(arg); void __user *up = compat_ptr(arg);
mm_segment_t old_fs;
long ret; long ret;
switch (cmd) { switch (cmd) {
case UVCIOC_CTRL_MAP32: case UVCIOC_CTRL_MAP32:
cmd = UVCIOC_CTRL_MAP;
ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up);
if (ret)
return ret;
ret = uvc_ioctl_ctrl_map(handle->chain, &karg.xmap);
if (ret)
return ret;
ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
if (ret)
return ret;
break; break;
case UVCIOC_CTRL_QUERY32: case UVCIOC_CTRL_QUERY32:
cmd = UVCIOC_CTRL_QUERY;
ret = uvc_v4l2_get_xu_query(&karg.xqry, up); ret = uvc_v4l2_get_xu_query(&karg.xqry, up);
if (ret)
return ret;
ret = uvc_xu_ctrl_query(handle->chain, &karg.xqry);
if (ret)
return ret;
ret = uvc_v4l2_put_xu_query(&karg.xqry, up);
if (ret)
return ret;
break; break;
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = video_ioctl2(file, cmd, (unsigned long)&karg);
set_fs(old_fs);
if (ret < 0)
return ret;
switch (cmd) {
case UVCIOC_CTRL_MAP:
ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
break;
case UVCIOC_CTRL_QUERY:
ret = uvc_v4l2_put_xu_query(&karg.xqry, up);
break;
}
return ret; return ret;
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment