aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Kitt <steve@sk2.org>2009-08-25 19:24:22 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-08-27 22:01:39 -0700
commit999b874f4aa39b7abf45662ff0900f943ddb2d02 (patch)
treeeff35a1a2622dc976319fd52dab12f6bbdc8d3a1
parent4b61bb575b1fb42ab1df228ae7812e5135f656da (diff)
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>
-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 9a1d55b74d7..901b2525993 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;