summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2014-05-21 10:07:31 +1000
committerKeith Packard <keithp@keithp.com>2014-06-04 22:16:28 -0700
commit9fb08310b51b46736f3ca8dbc04efdf502420403 (patch)
treefddf64286c57acf6eecee700600be67238e6966d
parente6f5d9d7b7efdacea0f22f1808efca849bcede4c (diff)
mi: don't process events from disabled devices (#77884)
Once a device is disabled, it doesn't have a sprite pointer anymore. If an event is still in the queue and processed after DisableDevice finished, a dereference causes a crash. Example backtrace (crash forced by injecting an event at the right time): (EE) 0: /opt/xorg/bin/Xorg (OsSigHandler+0x3c) [0x48d334] (EE) 1: /lib64/libpthread.so.0 (__restore_rt+0x0) [0x37fcc0f74f] (EE) 2: /opt/xorg/bin/Xorg (mieqMoveToNewScreen+0x38) [0x609240] (EE) 3: /opt/xorg/bin/Xorg (mieqProcessDeviceEvent+0xd4) [0x609389] (EE) 4: /opt/xorg/bin/Xorg (mieqProcessInputEvents+0x206) [0x609720] (EE) 5: /opt/xorg/bin/Xorg (ProcessInputEvents+0xd) [0x4aeb58] (EE) 6: /opt/xorg/bin/Xorg (xf86VTSwitch+0x1a6) [0x4af457] (EE) 7: /opt/xorg/bin/Xorg (xf86Wakeup+0x2bf) [0x4af0a7] (EE) 8: /opt/xorg/bin/Xorg (WakeupHandler+0x83) [0x4445cb] (EE) 9: /opt/xorg/bin/Xorg (WaitForSomething+0x3fe) [0x491bf6] (EE) 10: /opt/xorg/bin/Xorg (Dispatch+0x97) [0x435748] (EE) 11: /opt/xorg/bin/Xorg (dix_main+0x61d) [0x4438a9] (EE) 12: /opt/xorg/bin/Xorg (main+0x28) [0x49ba28] (EE) 13: /lib64/libc.so.6 (__libc_start_main+0xf5) [0x37fc821d65] (EE) 14: /opt/xorg/bin/Xorg (_start+0x29) [0x425e69] (EE) 15: ? (?+0x29) [0x29] xf86VTSwitch() calls ProcessInputEvents() before disabling a device, and DisableDevice() calls mieqProcessInputEvents() again when flushing touches and button events. Between that and disabling the device (which causes new events to be refused) there is a window where events may be triggered and enqueued. On the next call to PIE that event is processed on a now defunct device, causing the crash. The simplest fix to this is to discard events from disabled devices. We flush the queue often enough before disabling that when we get here, we really don't care about the events from this device. X.Org Bug 77884 <http://bugs.freedesktop.org/show_bug.cgi?id=77884> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reported-by: Maarten Lankhorst <maarten.lankhorst@canonical.com> Tested-by: Maarten Lankhorst <maarten.lankhorst@canonical.com> Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--mi/mieq.c4
-rw-r--r--test/input.c14
2 files changed, 17 insertions, 1 deletions
diff --git a/mi/mieq.c b/mi/mieq.c
index 36aa21357..0e27405cc 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -515,6 +515,10 @@ mieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
verify_internal_event(event);
+ /* refuse events from disabled devices */
+ if (!dev->enabled)
+ return 0;
+
/* Custom event handler */
handler = miEventQueue.handlers[event->any.type];
diff --git a/test/input.c b/test/input.c
index 9b5db8991..a4615c9c9 100644
--- a/test/input.c
+++ b/test/input.c
@@ -1712,6 +1712,18 @@ mieq_test_event_handler(int screenNum, InternalEvent *ie, DeviceIntPtr dev)
static void
_mieq_test_generate_events(uint32_t start, uint32_t count)
{
+ static DeviceIntRec dev;
+ static SpriteInfoRec spriteInfo;
+ static SpriteRec sprite;
+
+ memset(&dev, 0, sizeof(dev));
+ memset(&spriteInfo, 0, sizeof(spriteInfo));
+ memset(&sprite, 0, sizeof(sprite));
+ dev.spriteInfo = &spriteInfo;
+ spriteInfo.sprite = &sprite;
+
+ dev.enabled = 1;
+
count += start;
while (start < count) {
RawDeviceEvent e = { 0 };
@@ -1721,7 +1733,7 @@ _mieq_test_generate_events(uint32_t start, uint32_t count)
e.time = GetTimeInMillis();
e.flags = start;
- mieqEnqueue(NULL, (InternalEvent *) &e);
+ mieqEnqueue(&dev, (InternalEvent *) &e);
start++;
}