Re: [PATCH libinput] evdev: drop relative x/y motion from a device not marked as pointer

2015-08-19 Thread Hans de Goede

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.hutte...@who-t.net


Looks good to me:

Reviewed-by: Hans de Goede hdego...@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;
+ 

Re: [PATCH libinput] evdev: drop relative x/y motion from a device not marked as pointer

2015-08-18 Thread Bill Spitzak
On Mon, Aug 17, 2015 at 10:08 PM, Peter Hutterer peter.hutte...@who-t.net
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.

 +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;
 +}


It seems like some kind of ratelimit_log(limit, format, ...) function
might be useful so this is not copied everywhere.

Also wondering if there is a direct test for pointer acceleration never
initializes and perhaps you should do that test instead.


 +
  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)


I think it would look better and be clearer if you put the
evdev_reject_relative call in the REL_X and REL_Y cases of the switch (you
could also remove the test for REL_X/Y from the function itself).
___
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel


Re: [PATCH libinput] evdev: drop relative x/y motion from a device not marked as pointer

2015-08-18 Thread Peter Hutterer
On Tue, Aug 18, 2015 at 06:06:56PM -0700, Bill Spitzak wrote:
 On Mon, Aug 17, 2015 at 10:08 PM, Peter Hutterer peter.hutte...@who-t.net
 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.
 
  +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;
  +}
 
 
 It seems like some kind of ratelimit_log(limit, format, ...) function
 might be useful so this is not copied everywhere.

good idea, patch is in flight.

 Also wondering if there is a direct test for pointer acceleration never
 initializes and perhaps you should do that test instead.

not the same, we can concievably have a device that is a pointer but does
not have pointer acceleration. So checking for the seat caps here is better,
even though the crash is casued by the accel filters missing.
 
  +
   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)
 
 
 I think it would look better and be clearer if you put the
 evdev_reject_relative call in the REL_X and REL_Y cases of the switch (you
 could also remove the test for REL_X/Y from the function itself).

it's a generic function even though it only handles one case at this
point, see evdev_reject_device() which is similar. The reason is simple:
mental capacity is limited, this approach separates the when do we reject
events from how do we handle events, you only need to care about one at a
time.

Cheers,
   Peter
___
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel


[PATCH libinput] evdev: drop relative x/y motion from a device not marked as pointer

2015-08-17 Thread Peter Hutterer
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.hutte...@who-t.net
---
 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 },
+