diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-08-08 11:46:53 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-08-08 14:54:59 -0400 |
commit | f2afa7711f8585ffc088ba538b9a510e0d5dca12 (patch) | |
tree | 6f70bab8e58b23615e7b3505518b902d9407df80 /drivers/input | |
parent | 5402a7349d26875f69c184badf87b88541b1cf6c (diff) |
Input: paper over a bug in Synaptics X driver
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/evdev.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index ef8c2ed792c3..a92d81567559 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -647,8 +647,10 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) | |||
647 | return copy_to_user(p, str, len) ? -EFAULT : len; | 647 | return copy_to_user(p, str, len) ? -EFAULT : len; |
648 | } | 648 | } |
649 | 649 | ||
650 | #define OLD_KEY_MAX 0x1ff | ||
650 | static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode) | 651 | static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode) |
651 | { | 652 | { |
653 | static unsigned long keymax_warn_time; | ||
652 | unsigned long *bits; | 654 | unsigned long *bits; |
653 | int len; | 655 | int len; |
654 | 656 | ||
@@ -665,9 +667,26 @@ static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user | |||
665 | case EV_SW: bits = dev->swbit; len = SW_MAX; break; | 667 | case EV_SW: bits = dev->swbit; len = SW_MAX; break; |
666 | default: return -EINVAL; | 668 | default: return -EINVAL; |
667 | } | 669 | } |
670 | |||
671 | /* | ||
672 | * Work around bugs in userspace programs that like to do | ||
673 | * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len' | ||
674 | * should be in bytes, not in bits. | ||
675 | */ | ||
676 | if ((_IOC_NR(cmd) & EV_MAX) == EV_KEY && _IOC_SIZE(cmd) == OLD_KEY_MAX) { | ||
677 | len = OLD_KEY_MAX; | ||
678 | if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) | ||
679 | printk(KERN_WARNING | ||
680 | "evdev.c(EVIOCGBIT): Suspicious buffer size %d, " | ||
681 | "limiting output to %d bytes. See " | ||
682 | "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n", | ||
683 | OLD_KEY_MAX, | ||
684 | BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); | ||
685 | } | ||
686 | |||
668 | return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); | 687 | return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); |
669 | } | 688 | } |
670 | 689 | #undef OLD_KEY_MAX | |
671 | 690 | ||
672 | static long evdev_do_ioctl(struct file *file, unsigned int cmd, | 691 | static long evdev_do_ioctl(struct file *file, unsigned int cmd, |
673 | void __user *p, int compat_mode) | 692 | void __user *p, int compat_mode) |