mi: reset the PointerWindows reference on screen switch

PointerWindows[] keeps a reference to the last window our sprite
entered - changes are usually handled by CheckMotion().

If we switch between screens via XWarpPointer our
dev->spriteInfo->sprite->win is set to the new screen's root window.
If there's another window at the cursor location CheckMotion() will
trigger the right enter/leave events later. If there is not, it skips
that process and we never trigger LeaveWindow() - PointerWindows[] for
the device still refers to the previous window.

If that window is destroyed we have a dangling reference that will
eventually cause a use-after-free bug when checking the window hierarchy
later.

To trigger this, we require:
- two protocol screens
- XWarpPointer to the other screen's root window
- XDestroyWindow before entering any other window

This is a niche bug so we hack around it by making sure we reset the
PointerWindows[] entry so we cannot have a dangling pointer. This
doesn't handle Enter/Leave events correctly but the previous code didn't
either.

CVE-2023-5380, ZDI-CAN-21608

This vulnerability was discovered by:
Sri working with Trend Micro Zero Day Initiative

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
Peter Hutterer 2023-10-05 12:19:45 +10:00
parent 541ab2ecd4
commit 564ccf2ce9
3 changed files with 18 additions and 4 deletions

View File

@ -58,8 +58,6 @@ extern void DeviceFocusEvent(DeviceIntPtr dev,
extern void EnterWindow(DeviceIntPtr dev, WindowPtr win, int mode); extern void EnterWindow(DeviceIntPtr dev, WindowPtr win, int mode);
extern void LeaveWindow(DeviceIntPtr dev);
extern void CoreFocusEvent(DeviceIntPtr kbd, extern void CoreFocusEvent(DeviceIntPtr kbd,
int type, int mode, int detail, WindowPtr pWin); int type, int mode, int detail, WindowPtr pWin);

View File

@ -335,4 +335,7 @@ union _InternalEvent {
GestureEvent gesture_event; GestureEvent gesture_event;
}; };
extern void
LeaveWindow(DeviceIntPtr dev);
#endif #endif

View File

@ -397,8 +397,21 @@ miPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
#ifdef PANORAMIX #ifdef PANORAMIX
&& noPanoramiXExtension && noPanoramiXExtension
#endif #endif
) ) {
UpdateSpriteForScreen(pDev, pScreen); DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
/* Hack for CVE-2023-5380: if we're moving
* screens PointerWindows[] keeps referring to the
* old window. If that gets destroyed we have a UAF
* bug later. Only happens when jumping from a window
* to the root window on the other screen.
* Enter/Leave events are incorrect for that case but
* too niche to fix.
*/
LeaveWindow(pDev);
if (master)
LeaveWindow(master);
UpdateSpriteForScreen(pDev, pScreen);
}
} }
/** /**