diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-08-08 19:46:53 +0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-08-08 22:54:59 +0400 |
commit | f2afa7711f8585ffc088ba538b9a510e0d5dca12 (patch) | |
tree | 6f70bab8e58b23615e7b3505518b902d9407df80 /drivers/input | |
parent | 5402a7349d26875f69c184badf87b88541b1cf6c (diff) | |
download | linux-f2afa7711f8585ffc088ba538b9a510e0d5dca12.tar.xz |
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) return copy_to_user(p, str, len) ? -EFAULT : len; } +#define OLD_KEY_MAX 0x1ff static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode) { + static unsigned long keymax_warn_time; unsigned long *bits; int len; @@ -665,9 +667,26 @@ static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user case EV_SW: bits = dev->swbit; len = SW_MAX; break; default: return -EINVAL; } + + /* + * Work around bugs in userspace programs that like to do + * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len' + * should be in bytes, not in bits. + */ + if ((_IOC_NR(cmd) & EV_MAX) == EV_KEY && _IOC_SIZE(cmd) == OLD_KEY_MAX) { + len = OLD_KEY_MAX; + if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) + printk(KERN_WARNING + "evdev.c(EVIOCGBIT): Suspicious buffer size %d, " + "limiting output to %d bytes. See " + "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n", + OLD_KEY_MAX, + BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); + } + return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); } - +#undef OLD_KEY_MAX static long evdev_do_ioctl(struct file *file, unsigned int cmd, void __user *p, int compat_mode) |