Except for a few axes where this may be correct, a min == max axis range indicates a broken kernel driver. To avoid potential divisions by zero when scaling this axis later, reject such a device outright.
Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net> --- src/evdev.c | 34 +++++++++++++++++++++++++ test/device.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index bcaf338..52b89d3 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1452,10 +1452,32 @@ evdev_fix_android_mt(struct evdev_device *device) libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y)); } +static inline int +evdev_check_min_max(struct evdev_device *device, unsigned int code) +{ + struct libevdev *evdev = device->evdev; + const struct input_absinfo *absinfo; + + if (!libevdev_has_event_code(evdev, EV_ABS, code)) + return 0; + + absinfo = libevdev_get_abs_info(evdev, code); + if (absinfo->minimum == absinfo->maximum) { + log_bug_kernel(device->base.seat->libinput, + "Device '%s' has min == max on %s\n", + device->devname, + libevdev_event_code_get_name(EV_ABS, code)); + return -1; + } + + return 0; +} + static int evdev_reject_device(struct evdev_device *device) { struct libevdev *evdev = device->evdev; + unsigned int code; if (libevdev_has_event_code(evdev, EV_ABS, ABS_X) ^ libevdev_has_event_code(evdev, EV_ABS, ABS_Y)) @@ -1465,6 +1487,18 @@ evdev_reject_device(struct evdev_device *device) libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y)) return -1; + for (code = 0; code < ABS_CNT; code++) { + switch (code) { + case ABS_MISC: + case ABS_MT_SLOT: + case ABS_MT_TOOL_TYPE: + break; + default: + if (evdev_check_min_max(device, code) == -1) + return -1; + } + } + return 0; } diff --git a/test/device.c b/test/device.c index a18ec82..c9d5255 100644 --- a/test/device.c +++ b/test/device.c @@ -814,6 +814,86 @@ START_TEST(abs_mt_device_no_absx) } END_TEST +START_TEST(abs_device_no_range) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_device *device; + int code; + /* set x/y so libinput doesn't just reject for missing axes */ + struct input_absinfo absinfo[] = { + { ABS_X, 0, 10, 0, 0, 0 }, + { ABS_Y, 0, 10, 0, 0, 0 }, + { -1, 0, 0, 0, 0, 0 }, + { -1, -1, -1, -1, -1, -1 } + }; + + li = litest_create_context(); + litest_disable_log_handler(li); + + for (code = 0; code < ABS_MT_SLOT; code++) { + if (code == ABS_MISC) + continue; + absinfo[2].value = code; + uinput = litest_create_uinput_abs_device("test device", NULL, + absinfo, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + -1); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device == NULL); + libevdev_uinput_destroy(uinput); + } + + litest_restore_log_handler(li); + libinput_unref(li); +} +END_TEST + +START_TEST(abs_mt_device_no_range) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_device *device; + int code; + /* set x/y so libinput doesn't just reject for missing axes */ + struct input_absinfo absinfo[] = { + { ABS_X, 0, 10, 0, 0, 0 }, + { ABS_Y, 0, 10, 0, 0, 0 }, + { ABS_MT_SLOT, 0, 10, 0, 0, 0 }, + { ABS_MT_TRACKING_ID, 0, 255, 0, 0, 0 }, + { ABS_MT_POSITION_X, 0, 10, 0, 0, 0 }, + { ABS_MT_POSITION_Y, 0, 10, 0, 0, 0 }, + { -1, 0, 0, 0, 0, 0 }, + { -1, -1, -1, -1, -1, -1 } + }; + + li = litest_create_context(); + litest_disable_log_handler(li); + + for (code = ABS_MT_SLOT + 1; code < ABS_CNT; code++) { + if (code == ABS_MT_TOOL_TYPE || + code == ABS_MT_TRACKING_ID) /* kernel overrides it */ + continue; + + absinfo[6].value = code; + uinput = litest_create_uinput_abs_device("test device", NULL, + absinfo, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + -1); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device == NULL); + libevdev_uinput_destroy(uinput); + } + + litest_restore_log_handler(li); + libinput_unref(li); +} +END_TEST + int main (int argc, char **argv) { litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_TOUCHPAD); @@ -846,6 +926,8 @@ int main (int argc, char **argv) litest_add_no_device("device:invalid devices", abs_device_no_absy); litest_add_no_device("device:invalid devices", abs_mt_device_no_absx); litest_add_no_device("device:invalid devices", abs_mt_device_no_absy); + litest_add_no_device("device:invalid devices", abs_device_no_range); + litest_add_no_device("device:invalid devices", abs_mt_device_no_range); return litest_run(argc, argv); } -- 2.3.2 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel