summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-10-15 11:12:38 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-28 21:04:15 -0700
commit0243e39b20b13072a9e16e615316859c4c6c7600 (patch)
tree0150ca6410c37b6b4336c3da2131d814c778b100
parent56b40aa2ea3788e9b8f8411868f0f35a6f8a14cf (diff)
v4l1: fix 32-bit compat microcode loading translation
commit 3e645d6b485446c54c6745c5e2cf5c528fe4deec upstream. The compat code for the VIDIOCSMICROCODE ioctl is totally buggered. It's only used by the VIDEO_STRADIS driver, and that one is scheduled to staging and eventually removed unless somebody steps up to maintain it (at which point it should use request_firmware() rather than some magic ioctl). So we'll get rid of it eventually. But in the meantime, the compatibility ioctl code is broken, and this tries to get it to at least limp along (even if Mauro suggested just deleting it entirely, which may be the right thing to do - I don't think the compatibility translation code has ever worked unless you were very lucky). Reported-by: Kees Cook <kees.cook@canonical.com> Cc: Mauro Carvalho Chehab <mchehab@infradead.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/media/video/compat_ioctl32.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index e6ca4012b5f0..ec850b55679b 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -499,17 +499,24 @@ struct video_code32
{
char loadwhat[16]; /* name or tag of file being passed */
compat_int_t datasize;
- unsigned char *data;
+ compat_uptr_t data;
};
-static inline int microcode32(struct video_code *kp, struct video_code32 __user *up)
+static struct video_code __user *get_microcode32(struct video_code32 *kp)
{
- if(!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
- copy_from_user(kp->loadwhat, up->loadwhat, sizeof (up->loadwhat)) ||
- get_user(kp->datasize, &up->datasize) ||
- copy_from_user(kp->data, up->data, up->datasize))
- return -EFAULT;
- return 0;
+ struct video_code __user *up;
+
+ up = compat_alloc_user_space(sizeof(*up));
+
+ /*
+ * NOTE! We don't actually care if these fail. If the
+ * user address is invalid, the native ioctl will do
+ * the error handling for us
+ */
+ (void) copy_to_user(up->loadwhat, kp->loadwhat, sizeof(up->loadwhat));
+ (void) put_user(kp->datasize, &up->datasize);
+ (void) put_user(compat_ptr(kp->data), &up->data);
+ return up;
}
#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32)
@@ -618,7 +625,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
struct video_tuner vt;
struct video_buffer vb;
struct video_window vw;
- struct video_code vc;
+ struct video_code32 vc;
struct video_audio va;
#endif
struct v4l2_format v2f;
@@ -745,8 +752,11 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
break;
#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCSMICROCODE:
- err = microcode32(&karg.vc, up);
- compatible_arg = 0;
+ /* Copy the 32-bit "video_code32" to kernel space */
+ if (copy_from_user(&karg.vc, up, sizeof(karg.vc)))
+ return -EFAULT;
+ /* Convert the 32-bit version to a 64-bit version in user space */
+ up = get_microcode32(&karg.vc);
break;
#endif
};