Fedora Account System
Red Hat Associate
Red Hat Customer
GestureBuildSprite() copies raw WindowPtr values into the gesture sprite trace via CopySprite() without any reference counting or lifetime management. WindowGone() only repairs touch sprite traces when a window is destroyed -- gesture sprite traces are never checked or cleaned. This leaves stale WindowPtr references in gesture sprites. When DeliverOneGestureEvent() later dereferences the stale WindowPtr via DeepestSpriteWin(&gi->sprite)->drawable.id, it produces a use-after-free. The freed 4 bytes (drawable.id) can be read back, potentially leaking information about the contents of the freed memory region. Fixed in: xorg-server-21.1.25 and xwayland-24.1.14 * Patch From a4dd330114c58f760c141c84c7c01cc693181acf Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer> Date: Thu, 3 Sep 2026 14:57:31 +1000 Subject: [PATCH xserver] Xi: clean up gesture sprite traces in WindowGone Gesture sprite traces which have the same 'fixed sprite trace for the duration of the gesture' logic as touch sprite traces. Both copy WindowPtrs into the trace without refcounting them. If a device supports gestures but does not have a TouchClass, the cleanup skipped over the gesture sprite cleanup, leaving dangling pointers in place if a sprite trace is destroyed during an active gesture (i.e. window is removed). DeliverOneGestureEvent() then dereferences the stale pointer via DeepestSpriteWin(&gi->sprite)->drawable.id, causing a use-after-free. This vulnerability was discovered by: 4nibhal working with TrendAI Zero Day Initiative ZDI-CAN-32753 CVE-2026-93536 Assisted-by: Claude:claude-opus-4-6 #+begin_src diff --- Xi/exevents.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 2ee4fbc53c27..f17e519c2b09 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -2869,34 +2869,44 @@ InputClientGone(WindowPtr pWin, XID id) return Success; } prev = other; } FatalError("client not on device event list"); } /** - * Search for window in each touch trace for each device. Remove the window - * and all its subwindows from the trace when found. The initial window - * order is preserved. + * Search for window in each touch and gesture trace for each device. + * Truncate the trace when the window is found. ,*/ void WindowGone(WindowPtr win) { DeviceIntPtr dev; for (dev = inputInfo.devices; dev; dev = dev->next) { TouchClassPtr t = dev->touch; int i; - if (!t) - continue; + if (t) { + for (i = 0; i < t->num_touches; i++) { + SpritePtr sprite = &t->touches[i].sprite; + int j; - for (i = 0; i < t->num_touches; i++) { - SpritePtr sprite = &t->touches[i].sprite; + for (j = 0; j < sprite->spriteTraceGood; j++) { + if (sprite->spriteTrace[j] == win) { + sprite->spriteTraceGood = j; + break; + } + } + } + } + + if (dev->gesture) { + SpritePtr sprite = &dev->gesture->gesture.sprite; int j; for (j = 0; j < sprite->spriteTraceGood; j++) { if (sprite->spriteTrace[j] == win) { sprite->spriteTraceGood = j; break; } } -- 2.55.0 #+end_src