Skip to content

Commit 999b874

Browse files
skittdtor
authored andcommitted
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 <[email protected]> Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent 4b61bb5 commit 999b874

File tree

1 file changed

+74
-32
lines changed

1 file changed

+74
-32
lines changed

drivers/input/joydev.c

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,76 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
452452
(joydev->exist ? 0 : (POLLHUP | POLLERR));
453453
}
454454

455+
static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
456+
void __user *argp, size_t len)
457+
{
458+
__u8 *abspam;
459+
int i;
460+
int retval = 0;
461+
462+
len = min(len, sizeof(joydev->abspam));
463+
464+
/* Validate the map. */
465+
abspam = kmalloc(len, GFP_KERNEL);
466+
if (!abspam)
467+
return -ENOMEM;
468+
469+
if (copy_from_user(abspam, argp, len)) {
470+
retval = -EFAULT;
471+
goto out;
472+
}
473+
474+
for (i = 0; i < joydev->nabs; i++) {
475+
if (abspam[i] > ABS_MAX) {
476+
retval = -EINVAL;
477+
goto out;
478+
}
479+
}
480+
481+
memcpy(joydev->abspam, abspam, len);
482+
483+
out:
484+
kfree(abspam);
485+
return retval;
486+
}
487+
488+
static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
489+
void __user *argp, size_t len)
490+
{
491+
__u16 *keypam;
492+
int i;
493+
int retval = 0;
494+
495+
len = min(len, sizeof(joydev->keypam));
496+
497+
/* Validate the map. */
498+
keypam = kmalloc(len, GFP_KERNEL);
499+
if (!keypam)
500+
return -ENOMEM;
501+
502+
if (copy_from_user(keypam, argp, len)) {
503+
retval = -EFAULT;
504+
goto out;
505+
}
506+
507+
for (i = 0; i < joydev->nkey; i++) {
508+
if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
509+
retval = -EINVAL;
510+
goto out;
511+
}
512+
}
513+
514+
memcpy(joydev->keypam, keypam, len);
515+
516+
for (i = 0; i < joydev->nkey; i++)
517+
joydev->keymap[keypam[i] - BTN_MISC] = i;
518+
519+
out:
520+
kfree(keypam);
521+
return retval;
522+
}
523+
524+
455525
static int joydev_ioctl_common(struct joydev *joydev,
456526
unsigned int cmd, void __user *argp)
457527
{
@@ -512,46 +582,18 @@ static int joydev_ioctl_common(struct joydev *joydev,
512582
switch (cmd & ~IOCSIZE_MASK) {
513583

514584
case (JSIOCSAXMAP & ~IOCSIZE_MASK):
515-
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
516-
/*
517-
* FIXME: we should not copy into our axis map before
518-
* validating the data.
519-
*/
520-
if (copy_from_user(joydev->abspam, argp, len))
521-
return -EFAULT;
522-
523-
for (i = 0; i < joydev->nabs; i++) {
524-
if (joydev->abspam[i] > ABS_MAX)
525-
return -EINVAL;
526-
joydev->absmap[joydev->abspam[i]] = i;
527-
}
528-
return 0;
585+
return joydev_handle_JSIOCSAXMAP(joydev, argp, _IOC_SIZE(cmd));
529586

530587
case (JSIOCGAXMAP & ~IOCSIZE_MASK):
531588
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
532-
return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : 0;
589+
return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : len;
533590

534591
case (JSIOCSBTNMAP & ~IOCSIZE_MASK):
535-
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
536-
/*
537-
* FIXME: we should not copy into our keymap before
538-
* validating the data.
539-
*/
540-
if (copy_from_user(joydev->keypam, argp, len))
541-
return -EFAULT;
542-
543-
for (i = 0; i < joydev->nkey; i++) {
544-
if (joydev->keypam[i] > KEY_MAX ||
545-
joydev->keypam[i] < BTN_MISC)
546-
return -EINVAL;
547-
joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
548-
}
549-
550-
return 0;
592+
return joydev_handle_JSIOCSBTNMAP(joydev, argp, _IOC_SIZE(cmd));
551593

552594
case (JSIOCGBTNMAP & ~IOCSIZE_MASK):
553595
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
554-
return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : 0;
596+
return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : len;
555597

556598
case JSIOCGNAME(0):
557599
name = dev->name;

0 commit comments

Comments
 (0)