Bug 2545922 (CVE-2026-93515)

Summary: CVE-2026-93515 xorg-x11-server: xorg-x11-server: Denial of Service via cross-window notification use-after-free
Product: [Other] Security Response Reporter: OSIDB Bzimport <bzimport>
Component: vulnerabilityAssignee: Product Security <prodsec-ir-bot>
Status: NEW --- QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: unspecifiedCC: rhel-process-autobot, security-response-team, watson-tool-maintainers
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
A flaw was found in xorg-x11-server. A use-after-free vulnerability, where the application accesses memory after it has already been released, occurs in the Present extension because window notification entries are not properly unlinked before cleaning up window resources. An authenticated local X client can exploit this flaw by creating cross-window notifications and subsequently destroying the target window. Successful exploitation primarily results in a Denial of Service (DoS) via an X server crash, and may potentially lead to information disclosure.
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Deadline: 2026-10-07   

Description OSIDB Bzimport 2026-10-05 14:30:15 UTC
present_clear_window_notifies() does not unlink notify entries from the
per-window list before freeing window_priv. When the window is
subsequently destroyed or reused, the stale list entries are traversed,
resulting in a use-after-free.

An authenticated X client can trigger this by creating cross-window
Present notifies and then destroying the target window. Both the
Present and SYNC extensions must be enabled (they are by default).

The use-after-free can lead to denial of service (crash) or potentially
information disclosure.

Fixed in: xorg-server-21.1.25 and xwayland-24.1.14



* Patch
From 4ce3e830831dbeae1a54e510b78c4e09fb294605 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <peter.hutterer>
Date: Wed, 26 Aug 2026 17:04:47 +1000
Subject: [PATCH xserver] present: unlink notifies from window list in
 present_clear_window_notifies

When a window is destroyed, present_clear_window_notifies()
does not remove the notify list node from the window. The notify
may then be freed as part of the window_priv, leaving dangling
pointers in place.

When the vblank owning the notify is later torn down,
present_free_window_notify() calls xorg_list_del() which
writes through these dangling pointers (use-after-free write).

This happens when Present cross-window notifies are used: a
PresentPixmap on window A can reference window B as a notify target.
An untriggered wait_fence keeps the vblank alive so that B can be
destroyed first, creating the dangling-pointer window.

Fix this by calling the free function we have (and moving the window
reset into that function too). present_clear_window_notifies is only
called from one place anyway.

This vulnerability was discovered by:
  Anonymous working with TrendAI Zero Day Initiative

ZDI-CAN-31830

CVE-2026-93515

Assisted-by: Claude:claude-opus-4-6
#+begin_src diff
---
 present/present_notify.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/present/present_notify.c b/present/present_notify.c
index 1f9ff7474145..7cb0ad5b2dc8 100644
--- a/present/present_notify.c
+++ b/present/present_notify.c
@@ -25,34 +25,35 @@
 /*
  ,* Mark all pending notifies for 'window' as invalid when
  ,* the window is destroyed
  ,*/
 
 void
 present_clear_window_notifies(WindowPtr window)
 {
-    present_notify_ptr          notify;
+    present_notify_ptr          notify, tmp;
     present_window_priv_ptr     window_priv = present_window_priv(window);
 
     if (!window_priv)
         return;
 
-    xorg_list_for_each_entry(notify, &window_priv->notifies, window_list) {
-        notify->window = NULL;
+    xorg_list_for_each_entry_safe(notify, tmp, &window_priv->notifies, window_list) {
+        present_free_window_notify(notify);
     }
 }
 
 /*
  ,* 'notify' is being freed; remove it from the window's notify list
  ,*/
 
 void
 present_free_window_notify(present_notify_ptr notify)
 {
+    notify->window = NULL;
     xorg_list_del(&notify->window_list);
 }
 
 /*
  ,* 'notify' is new; add it to the specified window
  ,*/
 
 int
-- 
2.55.0
#+end_src