aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/joydev.c
diff options
context:
space:
mode:
authorStephen Kitt <steve@sk2.org>2009-08-25 22:24:22 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-08-28 01:01:39 -0400
commit999b874f4aa39b7abf45662ff0900f943ddb2d02 (patch)
treeeff35a1a2622dc976319fd52dab12f6bbdc8d3a1 /drivers/input/joydev.c
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>
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)
452 (joydev->exist ? 0 : (POLLHUP | POLLERR)); 452 (joydev->exist ? 0 : (POLLHUP | POLLERR));
453} 453}
454 454
455static 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
488static 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
455static int joydev_ioctl_common(struct joydev *joydev, 525static int joydev_ioctl_common(struct joydev *joydev,
456 unsigned int cmd, void __user *argp) 526 unsigned int cmd, void __user *argp)
457{ 527{
@@ -512,46 +582,18 @@ static int joydev_ioctl_common(struct joydev *joydev,
512 switch (cmd & ~IOCSIZE_MASK) { 582 switch (cmd & ~IOCSIZE_MASK) {
513 583
514 case (JSIOCSAXMAP & ~IOCSIZE_MASK): 584 case (JSIOCSAXMAP & ~IOCSIZE_MASK):
515 len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam)); 585 return joydev_handle_JSIOCSAXMAP(joydev, argp, _IOC_SIZE(cmd));
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;
529 586
530 case (JSIOCGAXMAP & ~IOCSIZE_MASK): 587 case (JSIOCGAXMAP & ~IOCSIZE_MASK):
531 len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam)); 588 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;
533 590
534 case (JSIOCSBTNMAP & ~IOCSIZE_MASK): 591 case (JSIOCSBTNMAP & ~IOCSIZE_MASK):
535 len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam)); 592 return joydev_handle_JSIOCSBTNMAP(joydev, argp, _IOC_SIZE(cmd));
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;
551 593
552 case (JSIOCGBTNMAP & ~IOCSIZE_MASK): 594 case (JSIOCGBTNMAP & ~IOCSIZE_MASK):
553 len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam)); 595 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;
555 597
556 case JSIOCGNAME(0): 598 case JSIOCGNAME(0):
557 name = dev->name; 599 name = dev->name;