[PATCH libinput] evdev: drop relative x/y motion from a device not marked as pointer
Hans de Goede
hdegoede at redhat.com
Wed Aug 19 06:25:05 PDT 2015
Hi,
On 18-08-15 07:08, Peter Hutterer wrote:
> 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 at who-t.net>
Looks good to me:
Reviewed-by: Hans de Goede <hdegoede at redhat.com>
Regards,
Hans
> ---
> src/evdev.c | 35 +++++++++++++
> src/evdev.h | 1 +
> test/device.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> test/litest.c | 2 +
> 4 files changed, 193 insertions(+)
>
> diff --git a/src/evdev.c b/src/evdev.c
> index 9414d9d..97c007c 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 9f026b8..e44a65d 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 59939d6..aff5ee2 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 3a16cd7..26c5e43 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
>
More information about the wayland-devel
mailing list