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

Reply via email to