[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