Skip to content

Commit

Permalink
Input: joydev - validate axis/button maps before clobbering current ones
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
skitt authored and dtor committed Aug 28, 2009
1 parent 4b61bb5 commit 999b874
Showing 1 changed file with 74 additions and 32 deletions.
106 changes: 74 additions & 32 deletions drivers/input/joydev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 999b874

Please sign in to comment.