[PATCH xf86-input-libinput] Fix crash when using threaded input and the first device goes away

Hans de Goede hdegoede at redhat.com
Wed Oct 5 13:31:38 UTC 2016


When the xserver uses threaded input, it keeps a pointer to the InputInfo
passed into xf86AddEnabledDevice and calls pointer->read_input on events.

But when the first enabled device goes away the pInfo we've passed into
xf86AddEnabledDevice gets freed and eventually pInfo->read_input gets
overwritten (or pInfo points to unmapped memory) leading to a segfault.

This commit fixes this by replacing the pInfo passed into
xf86AddEnabledDevice with a pointer to a global InputInfo stored inside
the driver_context struct.

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 src/xf86libinput.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/src/xf86libinput.c b/src/xf86libinput.c
index 21f87f5..485e212 100644
--- a/src/xf86libinput.c
+++ b/src/xf86libinput.c
@@ -86,6 +86,7 @@
 
 struct xf86libinput_driver {
 	struct libinput *libinput;
+	struct _InputInfoRec InputInfo;
 	int device_enabled_count;
 };
 
@@ -582,7 +583,17 @@ xf86libinput_on(DeviceIntPtr dev)
 
 	if (driver_context.device_enabled_count == 0) {
 #if HAVE_THREADED_INPUT
-		xf86AddEnabledDevice(pInfo);
+		/*
+		 * The xserver keeps a pointer to the InputInfo passed into
+		 * xf86AddEnabledDevice and calls pointer->read_input on
+		 * events. Thus we cannot simply pass in our current pInfo
+		 * as that will be deleted when the current input device gets
+		 * unplugged. Instead pass in a pointer to a global
+		 * InputInfo inside the driver_context.
+		 */
+		driver_context.InputInfo.fd = pInfo->fd;
+		driver_context.InputInfo.read_input = pInfo->read_input;
+		xf86AddEnabledDevice(&driver_context.InputInfo);
 #else
 		/* Can't use xf86AddEnabledDevice on an epollfd */
 		AddEnabledDevice(pInfo->fd);
@@ -606,7 +617,7 @@ xf86libinput_off(DeviceIntPtr dev)
 
 	if (--driver_context.device_enabled_count == 0) {
 #if HAVE_THREADED_INPUT
-		xf86RemoveEnabledDevice(pInfo);
+		xf86RemoveEnabledDevice(&driver_context.InputInfo);
 #else
 		RemoveEnabledDevice(pInfo->fd);
 #endif
@@ -1923,7 +1934,7 @@ out:
 }
 
 static void
-xf86libinput_read_input(InputInfoPtr pInfo)
+xf86libinput_read_input(InputInfoPtr do_not_use)
 {
 	struct libinput *libinput = driver_context.libinput;
 	int rc;
@@ -1934,9 +1945,8 @@ xf86libinput_read_input(InputInfoPtr pInfo)
 		return;
 
 	if (rc < 0) {
-		xf86IDrvMsg(pInfo, X_ERROR,
-			    "Error reading events: %s\n",
-			    strerror(-rc));
+		xf86Msg(X_ERROR, "Error reading libinput events: %s\n",
+			strerror(-rc));
 		return;
 	}
 
-- 
2.9.3



More information about the xorg-devel mailing list