031995
From 004f461c440cb6611eefb48fbbb4fa53a6d49f80 Mon Sep 17 00:00:00 2001
031995
From: Peter Hutterer <peter.hutterer@who-t.net>
031995
Date: Thu, 5 Oct 2023 12:19:45 +1000
031995
Subject: [PATCH xserver 2/4] mi: reset the PointerWindows reference on screen
031995
 switch
031995
031995
PointerWindows[] keeps a reference to the last window our sprite
031995
entered - changes are usually handled by CheckMotion().
031995
031995
If we switch between screens via XWarpPointer our
031995
dev->spriteInfo->sprite->win is set to the new screen's root window.
031995
If there's another window at the cursor location CheckMotion() will
031995
trigger the right enter/leave events later. If there is not, it skips
031995
that process and we never trigger LeaveWindow() - PointerWindows[] for
031995
the device still refers to the previous window.
031995
031995
If that window is destroyed we have a dangling reference that will
031995
eventually cause a use-after-free bug when checking the window hierarchy
031995
later.
031995
031995
To trigger this, we require:
031995
- two protocol screens
031995
- XWarpPointer to the other screen's root window
031995
- XDestroyWindow before entering any other window
031995
031995
This is a niche bug so we hack around it by making sure we reset the
031995
PointerWindows[] entry so we cannot have a dangling pointer. This
031995
doesn't handle Enter/Leave events correctly but the previous code didn't
031995
either.
031995
031995
CVE-2023-5380, ZDI-CAN-21608
031995
031995
This vulnerability was discovered by:
031995
Sri working with Trend Micro Zero Day Initiative
031995
031995
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
031995
Reviewed-by: Adam Jackson <ajax@redhat.com>
031995
---
031995
 dix/enterleave.h   |  2 --
031995
 include/eventstr.h |  3 +++
031995
 mi/mipointer.c     | 17 +++++++++++++++--
031995
 3 files changed, 18 insertions(+), 4 deletions(-)
031995
031995
diff --git a/dix/enterleave.h b/dix/enterleave.h
031995
index 4b833d8a3b..e8af924c68 100644
031995
--- a/dix/enterleave.h
031995
+++ b/dix/enterleave.h
031995
@@ -58,8 +58,6 @@ extern void DeviceFocusEvent(DeviceIntPtr dev,
031995
 
031995
 extern void EnterWindow(DeviceIntPtr dev, WindowPtr win, int mode);
031995
 
031995
-extern void LeaveWindow(DeviceIntPtr dev);
031995
-
031995
 extern void CoreFocusEvent(DeviceIntPtr kbd,
031995
                            int type, int mode, int detail, WindowPtr pWin);
031995
 
031995
diff --git a/include/eventstr.h b/include/eventstr.h
031995
index bf3b95fe4a..2bae3b0767 100644
031995
--- a/include/eventstr.h
031995
+++ b/include/eventstr.h
031995
@@ -296,4 +296,7 @@ union _InternalEvent {
031995
 #endif
031995
 };
031995
 
031995
+extern void
031995
+LeaveWindow(DeviceIntPtr dev);
031995
+
031995
 #endif
031995
diff --git a/mi/mipointer.c b/mi/mipointer.c
031995
index 75be1aeeb8..b12ae9be1d 100644
031995
--- a/mi/mipointer.c
031995
+++ b/mi/mipointer.c
031995
@@ -397,8 +397,21 @@ miPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
031995
 #ifdef PANORAMIX
031995
         && noPanoramiXExtension
031995
 #endif
031995
-        )
031995
-        UpdateSpriteForScreen(pDev, pScreen);
031995
+        ) {
031995
+            DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
031995
+            /* Hack for CVE-2023-5380: if we're moving
031995
+             * screens PointerWindows[] keeps referring to the
031995
+             * old window. If that gets destroyed we have a UAF
031995
+             * bug later. Only happens when jumping from a window
031995
+             * to the root window on the other screen.
031995
+             * Enter/Leave events are incorrect for that case but
031995
+             * too niche to fix.
031995
+             */
031995
+            LeaveWindow(pDev);
031995
+            if (master)
031995
+                LeaveWindow(master);
031995
+            UpdateSpriteForScreen(pDev, pScreen);
031995
+    }
031995
 }
031995
 
031995
 /**
031995
-- 
031995
2.41.0
031995