From f420c54a991f714d9821e054ae70f06cfc8894db Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Thu, 5 Feb 2015 14:33:31 +0100 Subject: [PATCH] Fix an abort if the device speed is NaN When using libinput with xf86-input-libinput, the device speed is represented as a float passed via X properties. If a buggy client gives a broken value, the conversions that occur can cause the value of speed to be NaN (not a number), aka infinity. In C, any comparison with NaN always gives false, whatever the value. So that test in libinput_device_config_accel_set_speed(): (speed < 1.0 || speed > 1.0) will necessarily return FALSE, defeating the test of range. However, since since any comparison with NaN is false, the opposite assert() in accelerator_set_speed(): (speed >= 1.0 && speed <= 1.0) will be false as well, thus triggering the abort() and the crash of the entire X server along with it. The solution is to use the same construct in both routines, so that it fails gracefully in libinput_device_config_accel_set_speed(). Signed-off-by: Olivier Fourdan Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- src/libinput.c | 3 ++- test/pointer.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/libinput.c b/src/libinput.c index 7456b90..ba60c13 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1534,7 +1534,8 @@ LIBINPUT_EXPORT enum libinput_config_status libinput_device_config_accel_set_speed(struct libinput_device *device, double speed) { - if (speed < -1.0 || speed > 1.0) + /* Need the negation in case speed is NaN */ + if (!(speed >= -1.0 && speed <= 1.0)) return LIBINPUT_CONFIG_STATUS_INVALID; if (!libinput_device_config_accel_is_available(device)) diff --git a/test/pointer.c b/test/pointer.c index 9a1e9d6..2e52a20 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -770,6 +770,23 @@ START_TEST(pointer_accel_defaults) } END_TEST +START_TEST(pointer_accel_invalid) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + enum libinput_config_status status; + + ck_assert(libinput_device_config_accel_is_available(device)); + + status = libinput_device_config_accel_set_speed(device, + NAN); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); + status = libinput_device_config_accel_set_speed(device, + INFINITY); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); +} +END_TEST + START_TEST(pointer_accel_defaults_absolute) { struct litest_device *dev = litest_current_device(); @@ -818,6 +835,7 @@ int main (int argc, char **argv) { litest_add("pointer:left-handed", pointer_left_handed_during_click_multiple_buttons, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY); litest_add("pointer:accel", pointer_accel_defaults, LITEST_RELATIVE, LITEST_ANY); + litest_add("pointer:accel", pointer_accel_invalid, LITEST_RELATIVE, LITEST_ANY); litest_add("pointer:accel", pointer_accel_defaults_absolute, LITEST_ABSOLUTE, LITEST_ANY); return litest_run(argc, argv); -- 2.7.4