diff options
| author | Peter Hutterer <peter.hutterer@who-t.net> | 2014-03-05 10:57:01 +1000 |
|---|---|---|
| committer | Peter Hutterer <peter.hutterer@who-t.net> | 2014-03-06 14:30:03 +1000 |
| commit | 66fee1bec4c4b021e1b54adcd775cf6e2aa84869 (patch) | |
| tree | 416f1f2b156f783709d516eb84a86e760220b6f3 /libevdev/libevdev.c | |
| parent | 4ba56ac30995f85bc492b5154c40cb05e1053e57 (diff) | |
| download | libevdev-66fee1bec4c4b021e1b54adcd775cf6e2aa84869.tar.gz | |
Cap slot values to the announced maximum
A malicious device may announce N slots but then send a slot index >= N. The
slot state is almost always allocated (definitely the case in libevdev and
true for most callers), so providing a slot number higher than the announced
maximum is likely to lead to invalid dereferences. Don't allow that.
Likewise, don't allow negative slot numbers.
Note that the kernel filters these events anyway, the only way to trigger this
is to change the device fd to something outside the kernel's control.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
Diffstat (limited to 'libevdev/libevdev.c')
| -rw-r--r-- | libevdev/libevdev.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c index a77c466..d9e2517 100644 --- a/libevdev/libevdev.c +++ b/libevdev/libevdev.c @@ -809,6 +809,26 @@ read_more_events(struct libevdev *dev) return 0; } +/** + * Sanitize/modify events where needed. + * @return 0 if untouched, 1 if modified. + */ +static inline int +sanitize_event(const struct libevdev *dev, struct input_event *ev) +{ + if (unlikely(dev->num_slots > -1 && + libevdev_event_is_code(ev, EV_ABS, ABS_MT_SLOT) && + (ev->value < 0 || ev->value >= dev->num_slots))) { + log_bug("Device %s received an invalid slot index %d." + "Capping to announced max slot number %d.\n", + dev->name, ev->value, dev->num_slots - 1); + ev->value = dev->num_slots - 1; + return 1; + } + + return 0; +} + LIBEVDEV_EXPORT int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev) { @@ -875,6 +895,7 @@ libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event if (queue_shift(dev, ev) != 0) return -EAGAIN; + sanitize_event(dev, ev); update_state(dev, ev); /* if we disabled a code, get the next event instead */ @@ -1072,6 +1093,9 @@ libevdev_set_event_value(struct libevdev *dev, unsigned int type, unsigned int c e.code = code; e.value = value; + if (sanitize_event(dev, &e)) + return -1; + switch(type) { case EV_ABS: rc = update_abs_state(dev, &e); break; case EV_KEY: rc = update_key_state(dev, &e); break; |
