diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2015-08-18 13:00:15 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2015-08-20 07:56:59 +1000 |
commit | 6953b51b7ebe079b94322447f795e308b6ac8447 (patch) | |
tree | 7af8bb5fd5f7d8ad7a5be8c2c3175c571a51648b | |
parent | 5311d76ec19ce2cebf73cd4e49a58a4c08e216b5 (diff) |
evdev: drop relative x/y motion from a device not marked as pointer
A device with REL_X/Y and keys gets marked only as ID_INPUT_KEY, initializes
as keyboard and then segfaults when we send x/y coordinates - pointer
acceleration never initializes.
Ignore the events and log a bug instead. This intentionally only papers over
the underlying issue, let's wait for a real device to trigger this and then
look at the correct solution.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r-- | src/evdev.c | 35 | ||||
-rw-r--r-- | src/evdev.h | 1 | ||||
-rw-r--r-- | test/device.c | 155 | ||||
-rw-r--r-- | test/litest.c | 2 |
4 files changed, 193 insertions, 0 deletions
diff --git a/src/evdev.c b/src/evdev.c index 9414d9d6..97c007cd 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -638,6 +638,36 @@ evdev_notify_axis(struct evdev_device *device, &discrete); } +static inline bool +evdev_reject_relative(struct evdev_device *device, + const struct input_event *e, + uint64_t time) +{ + struct libinput *libinput = device->base.seat->libinput; + + if ((e->code == REL_X || e->code == REL_Y) && + (device->seat_caps & EVDEV_DEVICE_POINTER) == 0) { + switch (ratelimit_test(&device->nonpointer_rel_limit)) { + case RATELIMIT_PASS: + log_bug_libinput(libinput, + "REL_X/Y from device '%s', but this device is not a pointer\n", + device->devname); + break; + case RATELIMIT_THRESHOLD: + log_bug_libinput(libinput, + "REL_X/Y event flood from '%s'\n", + device->devname); + break; + case RATELIMIT_EXCEEDED: + break; + } + + return true; + } + + return false; +} + static inline void evdev_process_relative(struct evdev_device *device, struct input_event *e, uint64_t time) @@ -645,6 +675,9 @@ evdev_process_relative(struct evdev_device *device, struct normalized_coords wheel_degrees = { 0.0, 0.0 }; struct discrete_coords discrete = { 0.0, 0.0 }; + if (evdev_reject_relative(device, e, time)) + return; + switch (e->code) { case REL_X: if (device->pending_event != EVDEV_RELATIVE_MOTION) @@ -2157,6 +2190,8 @@ evdev_device_create(struct libinput_seat *seat, /* at most 5 SYN_DROPPED log-messages per 30s */ ratelimit_init(&device->syn_drop_limit, s2us(30), 5); + /* at most 5 log-messages per 5s */ + ratelimit_init(&device->nonpointer_rel_limit, s2us(5), 5); matrix_init_identity(&device->abs.calibration); matrix_init_identity(&device->abs.usermatrix); diff --git a/src/evdev.h b/src/evdev.h index 9f026b89..e44a65de 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -223,6 +223,7 @@ struct evdev_device { int dpi; /* HW resolution */ struct ratelimit syn_drop_limit; /* ratelimit for SYN_DROPPED logging */ + struct ratelimit nonpointer_rel_limit; /* ratelimit for REL_* events from non-pointer devices */ uint32_t model_flags; }; diff --git a/test/device.c b/test/device.c index 59939d67..aff5ee29 100644 --- a/test/device.c +++ b/test/device.c @@ -1030,6 +1030,156 @@ START_TEST(device_udev_tag_synaptics_serial) } END_TEST +START_TEST(device_nonpointer_rel) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_device *device; + int i; + + uinput = litest_create_uinput_device("test device", + NULL, + EV_KEY, KEY_A, + EV_KEY, KEY_B, + EV_REL, REL_X, + EV_REL, REL_Y, + -1); + li = litest_create_context(); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device != NULL); + + litest_disable_log_handler(li); + for (i = 0; i < 100; i++) { + libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1); + libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1); + libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + } + litest_restore_log_handler(li); + + libinput_unref(li); + libevdev_uinput_destroy(uinput); +} +END_TEST + +START_TEST(device_touchpad_rel) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_device *device; + const struct input_absinfo abs[] = { + { ABS_X, 0, 10, 0, 0, 10 }, + { ABS_Y, 0, 10, 0, 0, 10 }, + { ABS_MT_SLOT, 0, 2, 0, 0, 0 }, + { ABS_MT_TRACKING_ID, 0, 255, 0, 0, 0 }, + { ABS_MT_POSITION_X, 0, 10, 0, 0, 10 }, + { ABS_MT_POSITION_Y, 0, 10, 0, 0, 10 }, + { -1, -1, -1, -1, -1, -1 } + }; + int i; + + uinput = litest_create_uinput_abs_device("test device", + NULL, abs, + EV_KEY, BTN_TOOL_FINGER, + EV_KEY, BTN_TOUCH, + EV_REL, REL_X, + EV_REL, REL_Y, + -1); + li = litest_create_context(); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device != NULL); + + for (i = 0; i < 100; i++) { + libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1); + libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1); + libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + } + + libinput_unref(li); + libevdev_uinput_destroy(uinput); +} +END_TEST + +START_TEST(device_touch_rel) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_device *device; + const struct input_absinfo abs[] = { + { ABS_X, 0, 10, 0, 0, 10 }, + { ABS_Y, 0, 10, 0, 0, 10 }, + { ABS_MT_SLOT, 0, 2, 0, 0, 0 }, + { ABS_MT_TRACKING_ID, 0, 255, 0, 0, 0 }, + { ABS_MT_POSITION_X, 0, 10, 0, 0, 10 }, + { ABS_MT_POSITION_Y, 0, 10, 0, 0, 10 }, + { -1, -1, -1, -1, -1, -1 } + }; + int i; + + uinput = litest_create_uinput_abs_device("test device", + NULL, abs, + EV_KEY, BTN_TOUCH, + EV_REL, REL_X, + EV_REL, REL_Y, + -1); + li = litest_create_context(); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device != NULL); + + litest_disable_log_handler(li); + for (i = 0; i < 100; i++) { + libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1); + libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1); + libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + } + litest_restore_log_handler(li); + + libinput_unref(li); + libevdev_uinput_destroy(uinput); +} +END_TEST + +START_TEST(device_abs_rel) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_device *device; + const struct input_absinfo abs[] = { + { ABS_X, 0, 10, 0, 0, 10 }, + { ABS_Y, 0, 10, 0, 0, 10 }, + { -1, -1, -1, -1, -1, -1 } + }; + int i; + + uinput = litest_create_uinput_abs_device("test device", + NULL, abs, + EV_KEY, BTN_TOUCH, + EV_KEY, BTN_LEFT, + EV_REL, REL_X, + EV_REL, REL_Y, + -1); + li = litest_create_context(); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device != NULL); + + for (i = 0; i < 100; i++) { + libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1); + libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1); + libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + } + + libinput_unref(li); + libevdev_uinput_destroy(uinput); +} +END_TEST + void litest_setup_tests(void) { @@ -1077,4 +1227,9 @@ litest_setup_tests(void) litest_add("device:udev tags", device_udev_tag_wacom, LITEST_TOUCHPAD, LITEST_ANY); litest_add("device:udev tags", device_udev_tag_apple, LITEST_TOUCHPAD, LITEST_ANY); litest_add("device:udev tags", device_udev_tag_synaptics_serial, LITEST_TOUCHPAD, LITEST_ANY); + + litest_add_no_device("device:invalid rel events", device_nonpointer_rel); + litest_add_no_device("device:invalid rel events", device_touchpad_rel); + litest_add_no_device("device:invalid rel events", device_touch_rel); + litest_add_no_device("device:invalid rel events", device_abs_rel); } diff --git a/test/litest.c b/test/litest.c index 3a16cd7c..26c5e432 100644 --- a/test/litest.c +++ b/test/litest.c @@ -778,9 +778,11 @@ litest_log_handler(struct libinput *libinput, fprintf(stderr, "litest %s: ", priority); vfprintf(stderr, format, args); +#if 0 if (strstr(format, "client bug: ") || strstr(format, "libinput bug: ")) litest_abort_msg("libinput bug triggered, aborting.\n"); +#endif } static int |