summaryrefslogtreecommitdiff
path: root/drivers/input/joydev.c
diff options
context:
space:
mode:
authorStephen Kitt <steve@sk2.org>2009-08-26 06:24:22 +0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-08-28 09:01:39 +0400
commit999b874f4aa39b7abf45662ff0900f943ddb2d02 (patch)
treeeff35a1a2622dc976319fd52dab12f6bbdc8d3a1 /drivers/input/joydev.c
parent4b61bb575b1fb42ab1df228ae7812e5135f656da (diff)
downloadlinux-999b874f4aa39b7abf45662ff0900f943ddb2d02.tar.xz
Input: joydev - validate axis/button maps before clobbering current ones
Up to now axis and button map validation was done after the user-supplied values were copied over the driver's map. This patch copies the user-supplied values into temporary buffers and validated them before overwriting the driver's permanent maps. Also change JSIOCGBTNMAP and JSIOCGAXMAP to return number of bytes returned to userspace instead of 0. Signed-off-by: Stephen Kitt <steve@sk2.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/joydev.c')
-rw-r--r--drivers/input/joydev.c106
1 files changed, 74 insertions, 32 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 9a1d55b74d7a..901b2525993e 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -452,6 +452,76 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
(joydev->exist ? 0 : (POLLHUP | POLLERR));
}
+static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
+ void __user *argp, size_t len)
+{
+ __u8 *abspam;
+ int i;
+ int retval = 0;
+
+ len = min(len, sizeof(joydev->abspam));
+
+ /* Validate the map. */
+ abspam = kmalloc(len, GFP_KERNEL);
+ if (!abspam)
+ return -ENOMEM;
+
+ if (copy_from_user(abspam, argp, len)) {
+ retval = -EFAULT;
+ goto out;
+ }
+
+ for (i = 0; i < joydev->nabs; i++) {
+ if (abspam[i] > ABS_MAX) {
+ retval = -EINVAL;
+ goto out;
+ }
+ }
+
+ memcpy(joydev->abspam, abspam, len);
+
+ out:
+ kfree(abspam);
+ return retval;
+}
+
+static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
+ void __user *argp, size_t len)
+{
+ __u16 *keypam;
+ int i;
+ int retval = 0;
+
+ len = min(len, sizeof(joydev->keypam));
+
+ /* Validate the map. */
+ keypam = kmalloc(len, GFP_KERNEL);
+ if (!keypam)
+ return -ENOMEM;
+
+ if (copy_from_user(keypam, argp, len)) {
+ retval = -EFAULT;
+ goto out;
+ }
+
+ for (i = 0; i < joydev->nkey; i++) {
+ if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
+ retval = -EINVAL;
+ goto out;
+ }
+ }
+
+ memcpy(joydev->keypam, keypam, len);
+
+ for (i = 0; i < joydev->nkey; i++)
+ joydev->keymap[keypam[i] - BTN_MISC] = i;
+
+ out:
+ kfree(keypam);
+ return retval;
+}
+
+
static int joydev_ioctl_common(struct joydev *joydev,
unsigned int cmd, void __user *argp)
{
@@ -512,46 +582,18 @@ static int joydev_ioctl_common(struct joydev *joydev,
switch (cmd & ~IOCSIZE_MASK) {
case (JSIOCSAXMAP & ~IOCSIZE_MASK):
- len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
- /*
- * FIXME: we should not copy into our axis map before
- * validating the data.
- */
- if (copy_from_user(joydev->abspam, argp, len))
- return -EFAULT;
-
- for (i = 0; i < joydev->nabs; i++) {
- if (joydev->abspam[i] > ABS_MAX)
- return -EINVAL;
- joydev->absmap[joydev->abspam[i]] = i;
- }
- return 0;
+ return joydev_handle_JSIOCSAXMAP(joydev, argp, _IOC_SIZE(cmd));
case (JSIOCGAXMAP & ~IOCSIZE_MASK):
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
- return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : 0;
+ return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : len;
case (JSIOCSBTNMAP & ~IOCSIZE_MASK):
- len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
- /*
- * FIXME: we should not copy into our keymap before
- * validating the data.
- */
- if (copy_from_user(joydev->keypam, argp, len))
- return -EFAULT;
-
- for (i = 0; i < joydev->nkey; i++) {
- if (joydev->keypam[i] > KEY_MAX ||
- joydev->keypam[i] < BTN_MISC)
- return -EINVAL;
- joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
- }
-
- return 0;
+ return joydev_handle_JSIOCSBTNMAP(joydev, argp, _IOC_SIZE(cmd));
case (JSIOCGBTNMAP & ~IOCSIZE_MASK):
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
- return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : 0;
+ return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : len;
case JSIOCGNAME(0):
name = dev->name;