summaryrefslogtreecommitdiff
path: root/libevdev/libevdev.c
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2014-03-05 10:57:01 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2014-03-06 14:30:03 +1000
commit66fee1bec4c4b021e1b54adcd775cf6e2aa84869 (patch)
tree416f1f2b156f783709d516eb84a86e760220b6f3 /libevdev/libevdev.c
parent4ba56ac30995f85bc492b5154c40cb05e1053e57 (diff)
downloadlibevdev-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.c24
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;