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;