Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package xwayland for openSUSE:Factory 
checked in at 2026-06-02 19:46:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/xwayland (Old)
 and      /work/SRC/openSUSE:Factory/.xwayland.new.1937 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "xwayland"

Tue Jun  2 19:46:53 2026 rev:50 rq:1356605 version:24.1.11

Changes:
--------
--- /work/SRC/openSUSE:Factory/xwayland/xwayland.changes        2026-04-28 
14:30:49.459584841 +0200
+++ /work/SRC/openSUSE:Factory/.xwayland.new.1937/xwayland.changes      
2026-06-02 19:47:15.628983672 +0200
@@ -1,0 +2,18 @@
+Wed May 27 11:38:55 UTC 2026 - Stefan Dirsch <[email protected]>
+
+- 
bsc1266294_CVE-2026-XXXX1_0007-dix-increase-XLFDMAXFONTNAMELEN-to-match-libXfont2-s.patch
+  * Font Alias Stack-based Buffer Overflow (ZDI-CAN-30136, bsc#1266294)
+- bsc1266295_CVE-2026-XXXX2_0001-sync-fix-deletion-of-counters-and-fences.patch
+  * XSYNC Use-After-Free in miSyncDestroyFence() (ZDI-CAN-30159, 
ZDI-CAN-30163, bsc#1266295, bsc#1266298)
+- 
bsc1266296_CVE-2026-XXXX3_0003-xkb-reject-key-types-with-num_levels-exceeding-XkbMa.patch
+  * XKB Key Types Stack-based Buffer Overflow (ZDI-CAN-30160, bsc#1266296)
+- 
bsc1266297_CVE-2026-XXXX4_0004-xkb-clamp-nMaps-to-mapWidths-buffer-size-in-CheckKey.patch
+  * XKB SetMap Request Stack-based Buffer Overflow (ZDI-CAN-30161, bsc#1266297)
+- 
bsc1266299_CVE-2026-XXXX6_0002-sync-restart-trigger-list-iteration-in-SyncChangeCou.patch
+  * XSYNC Use-After-Free in SyncChangeCounter() (ZDI-CAN-30164, bsc#1266299)
+- 
bsc1266300_CVE-2026-XXXX7_0005-glx-fix-reversed-length-check-in-ChangeDrawableAttri.patch
+  * GLX ChangeDrawableAttributes Out-Of-Bounds Read/Write (ZDI-CAN-30165, 
bsc#1266300)
+- 
bsc1266301_CVE-2026-XXXX8_0006-saver-re-fetch-screen-private-after-CheckScreenPriva.patch
+  * CreateSaverWindow Use-After-Free Information Disclosure (ZDI-CAN-30168, 
bsc#1266301)
+
+-------------------------------------------------------------------

New:
----
  
bsc1266294_CVE-2026-XXXX1_0007-dix-increase-XLFDMAXFONTNAMELEN-to-match-libXfont2-s.patch
  bsc1266295_CVE-2026-XXXX2_0001-sync-fix-deletion-of-counters-and-fences.patch
  
bsc1266296_CVE-2026-XXXX3_0003-xkb-reject-key-types-with-num_levels-exceeding-XkbMa.patch
  
bsc1266297_CVE-2026-XXXX4_0004-xkb-clamp-nMaps-to-mapWidths-buffer-size-in-CheckKey.patch
  
bsc1266299_CVE-2026-XXXX6_0002-sync-restart-trigger-list-iteration-in-SyncChangeCou.patch
  
bsc1266300_CVE-2026-XXXX7_0005-glx-fix-reversed-length-check-in-ChangeDrawableAttri.patch
  
bsc1266301_CVE-2026-XXXX8_0006-saver-re-fetch-screen-private-after-CheckScreenPriva.patch

----------(New B)----------
  New:
- 
bsc1266294_CVE-2026-XXXX1_0007-dix-increase-XLFDMAXFONTNAMELEN-to-match-libXfont2-s.patch
  * Font Alias Stack-based Buffer Overflow (ZDI-CAN-30136, bsc#1266294)
  New:  * Font Alias Stack-based Buffer Overflow (ZDI-CAN-30136, bsc#1266294)
- bsc1266295_CVE-2026-XXXX2_0001-sync-fix-deletion-of-counters-and-fences.patch
  * XSYNC Use-After-Free in miSyncDestroyFence() (ZDI-CAN-30159, ZDI-CAN-30163, 
bsc#1266295, bsc#1266298)
  New:  * XSYNC Use-After-Free in miSyncDestroyFence() (ZDI-CAN-30159, 
ZDI-CAN-30163, bsc#1266295, bsc#1266298)
- 
bsc1266296_CVE-2026-XXXX3_0003-xkb-reject-key-types-with-num_levels-exceeding-XkbMa.patch
  * XKB Key Types Stack-based Buffer Overflow (ZDI-CAN-30160, bsc#1266296)
  New:  * XKB Key Types Stack-based Buffer Overflow (ZDI-CAN-30160, bsc#1266296)
- 
bsc1266297_CVE-2026-XXXX4_0004-xkb-clamp-nMaps-to-mapWidths-buffer-size-in-CheckKey.patch
  * XKB SetMap Request Stack-based Buffer Overflow (ZDI-CAN-30161, bsc#1266297)
  New:  * XKB SetMap Request Stack-based Buffer Overflow (ZDI-CAN-30161, 
bsc#1266297)
- 
bsc1266299_CVE-2026-XXXX6_0002-sync-restart-trigger-list-iteration-in-SyncChangeCou.patch
  * XSYNC Use-After-Free in SyncChangeCounter() (ZDI-CAN-30164, bsc#1266299)
  New:  * XSYNC Use-After-Free in SyncChangeCounter() (ZDI-CAN-30164, 
bsc#1266299)
- 
bsc1266300_CVE-2026-XXXX7_0005-glx-fix-reversed-length-check-in-ChangeDrawableAttri.patch
  * GLX ChangeDrawableAttributes Out-Of-Bounds Read/Write (ZDI-CAN-30165, 
bsc#1266300)
  New:  * GLX ChangeDrawableAttributes Out-Of-Bounds Read/Write (ZDI-CAN-30165, 
bsc#1266300)
- 
bsc1266301_CVE-2026-XXXX8_0006-saver-re-fetch-screen-private-after-CheckScreenPriva.patch
  * CreateSaverWindow Use-After-Free Information Disclosure (ZDI-CAN-30168, 
bsc#1266301)
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ xwayland.spec ++++++
--- /var/tmp/diff_new_pack.cQOga3/_old  2026-06-02 19:47:16.473018631 +0200
+++ /var/tmp/diff_new_pack.cQOga3/_new  2026-06-02 19:47:16.481018963 +0200
@@ -37,7 +37,13 @@
 Source1:        %{url}/archive/individual/xserver/%{name}-%{version}.tar.xz.sig
 Source2:        xwayland.keyring
 Patch3:         U_xwayland_Dont_run_key_behaviors_and_actions.patch
-
+Patch1266294:   
bsc1266294_CVE-2026-XXXX1_0007-dix-increase-XLFDMAXFONTNAMELEN-to-match-libXfont2-s.patch
+Patch1266295:   
bsc1266295_CVE-2026-XXXX2_0001-sync-fix-deletion-of-counters-and-fences.patch
+Patch1266296:   
bsc1266296_CVE-2026-XXXX3_0003-xkb-reject-key-types-with-num_levels-exceeding-XkbMa.patch
+Patch1266297:   
bsc1266297_CVE-2026-XXXX4_0004-xkb-clamp-nMaps-to-mapWidths-buffer-size-in-CheckKey.patch
+Patch1266299:   
bsc1266299_CVE-2026-XXXX6_0002-sync-restart-trigger-list-iteration-in-SyncChangeCou.patch
+Patch1266300:   
bsc1266300_CVE-2026-XXXX7_0005-glx-fix-reversed-length-check-in-ChangeDrawableAttri.patch
+Patch1266301:   
bsc1266301_CVE-2026-XXXX8_0006-saver-re-fetch-screen-private-after-CheckScreenPriva.patch
 BuildRequires:  meson
 BuildRequires:  ninja
 BuildRequires:  pkgconfig

++++++ 
bsc1266294_CVE-2026-XXXX1_0007-dix-increase-XLFDMAXFONTNAMELEN-to-match-libXfont2-s.patch
 ++++++
>From 9ef535c0010a3064380905de804ef7617002e063 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Wed, 29 Apr 2026 05:40:33 +0000
Subject: [PATCH xserver 7/9] dix: increase XLFDMAXFONTNAMELEN to match
 libXfont2's MAXFONTNAMELEN

XLFDMAXFONTNAMELEN was 256 bytes, but libXfont2 defines MAXFONTNAMELEN
as 1024 and allows font names and alias targets up to that length in
fonts.alias files.

doListFontsAndAliases copies the resolved alias target into a
stack-allocated tmp_pattern[XLFDMAXFONTNAMELEN] and then into
c->current.pattern[XLFDMAXFONTNAMELEN] (defined in LFWIstateRec).
doListFontsWithInfo has the same pattern, copying the resolved name into
c->current.pattern[]. With the old 256-byte limit, a fonts.alias entry
with a target name between 257 and 1023 bytes would overflow both
buffers.

An attacker can exploit this by:
  1. Creating a font directory with a fonts.alias containing an alias
     whose target name exceeds 256 bytes
  2. Using SetFontPath to add the malicious directory
  3. Calling ListFonts with the alias name to trigger alias resolution
  4. The oversized resolved name overflows the 256-byte stack buffer

Increase XLFDMAXFONTNAMELEN from 256 to 1024 to match libXfont2's
MAXFONTNAMELEN, ensuring the server can handle any name the font library
produces.

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

ZDI-CAN-30136

Assisted-by: Claude:claude-opus-4-6
---
 include/closestr.h | 7 ++++++-
 dix/dixfonts.c | 8 ++++++++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git ./include/closestr.h ../include/closestr.h
index 60e6f09bc871..7567ac6ea2b9 100644
--- ./include/closestr.h
+++ ../include/closestr.h
@@ -52,17 +52,22 @@ typedef struct _OFclosure {
     XID fontid;
     char *fontname;
     int fnamelen;
     FontPtr non_cachable_font;
 } OFclosureRec;
 
 /* ListFontsWithInfo */
 
-#define XLFDMAXFONTNAMELEN     256
+/* libXfont2 allows font names/aliases up to MAXFONTNAMELEN (1024) bytes in
+ * fonts.alias files.  The server's pattern buffers must be large enough to
+ * hold resolved alias targets returned by the font library.
+ * ZDI-CAN-30136
+ */
+#define XLFDMAXFONTNAMELEN     1024
 typedef struct _LFWIstate {
     char pattern[XLFDMAXFONTNAMELEN];
     int patlen;
     int current_fpe;
     int max_names;
     Bool list_started;
     void *private;
 } LFWIstateRec, *LFWIstatePtr;
diff --git ./dix/dixfonts.c ../dix/dixfonts.c
index 21f067c10e1f..3c6c9d5949b0 100644
--- ./dix/dixfonts.c
+++ ../dix/dixfonts.c
@@ -665,16 +665,20 @@ doListFontsAndAliases(ClientPtr client, LFclosurePtr c)
 
                 /*
                  * when an alias recurses, we need to give
                  * the last FPE a chance to clean up; so we call
                  * it again, and assume that the error returned
                  * is BadFontName, indicating the alias resolution
                  * is complete.
                  */
+                if (resolvedlen > XLFDMAXFONTNAMELEN) {
+                    err = BadFontName;
+                    goto ContBadFontName;
+                }
                 memcpy(tmp_pattern, resolved, resolvedlen);
                 if (c->haveSaved) {
                     char *tmpname;
                     int tmpnamelen;
 
                     tmpname = 0;
                     (void) (*fpe_functions[fpe->type]->list_next_font_or_alias)
                         ((void *) c->client, fpe, &tmpname, &tmpnamelen,
@@ -927,16 +931,20 @@ doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c)
                 c->saved = c->current;
                 c->haveSaved = TRUE;
                 c->savedNumFonts = numFonts;
                 free(c->savedName);
                 c->savedName = XNFalloc(namelen + 1);
                 memcpy(c->savedName, name, namelen + 1);
                 aliascount = 20;
             }
+            if (namelen > XLFDMAXFONTNAMELEN) {
+                err = BadFontName;
+                goto ContBadFontName;
+            }
             memmove(c->current.pattern, name, namelen);
             c->current.patlen = namelen;
             c->current.max_names = 1;
             c->current.current_fpe = 0;
             c->current.private = 0;
             c->current.list_started = FALSE;
         }
         /*
-- 
2.53.0


++++++ 
bsc1266295_CVE-2026-XXXX2_0001-sync-fix-deletion-of-counters-and-fences.patch 
++++++
>From e692c9a8f45bfa88b4b62b320cabaf3e7504c934 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Mon, 20 Apr 2026 11:16:13 +1000
Subject: [PATCH xserver 1/9] sync: fix deletion of counters and fences

Both FreeCounter() and miSyncDestroyFence() iterate over the trigger list
and invoke the CounterDestroyed callback on each trigger.

The CounterDestroyed callback (e.g. SyncAwaitTriggerFired) may call
FreeResource/FreeAwait, which frees the SyncAwaitUnion containing all
SyncAwait structs in the same Await group.

When multiple conditions in a single Await reference the same sync
object (counter or fence), the first callback frees all SyncAwait
structs while subsequent trigger list nodes still reference them. On the
next iteration, reading ptl->next or ptl->pTrigger dereferences freed
memory, leading to a use-after-free.

We need separate fixes for separate issues here to fix this in one go
- use our null-terminated list macro to make sure our next pointer stays
  valid (the code accessed ptl->next after freeing it)
- update the list head before deleting the trigger, eventually this ends
  up being NULL anyway but meanwhile the list head is a valid list
  during CounterDestroyed
- check if we actually do have a trigger before dereferencing the
  callback
- Set all triggers to NULL if they are shared so we don't dereference
  potentially freed memory

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

ZDI-CAN-30159 (miSyncDestroyFence), ZDI-CAN-30163 (FreeCounter)

Assisted-by: Claude:claude-opus-4-6
---
 Xext/sync.c         | 32 +++++++++++++++++++++++++-------
 miext/sync/misync.c | 12 ++++++++----
 2 files changed, 33 insertions(+), 11 deletions(-)

Index: xwayland-24.1.11/Xext/sync.c
===================================================================
--- xwayland-24.1.11.orig/Xext/sync.c
+++ xwayland-24.1.11/Xext/sync.c
@@ -1163,9 +1163,12 @@ FreeCounter(void *env, XID id)
         SyncTriggerList *ptl, *pnext;
 
         /* tell all the counter's triggers that counter has been destroyed */
-        for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) {
-            (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger);
-            pnext = ptl->next;
+        nt_list_for_each_entry_safe(ptl, pnext, pCounter->sync.pTriglist, 
next) {
+            /* Remove it from the list first so CounterDestroyed
+             * callbacks have a valid list to iterate */
+            pCounter->sync.pTriglist = pnext;
+            if (ptl->pTrigger)
+                (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger);
             free(ptl); /* destroy the trigger list as we go */
         }
         if (IsSystemCounter(pCounter)) {
@@ -1197,13 +1200,28 @@ FreeAwait(void *addr, XID id)
 
     for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
          numwaits--, pAwait++) {
-        /* If the counter is being destroyed, FreeCounter will delete
-         * the trigger list itself, so don't do it here.
+        /* If the counter is being destroyed, FreeCounter/miSyncDestroyFence
+         * will delete the trigger list itself, so don't do it here.
+         * However, we must NULL out the pTrigger pointer in the trigger list
+         * node so the destroy loop knows not to dereference it - the backing
+         * SyncAwait memory is about to be freed below.
          */
         SyncObject *pSync = pAwait->trigger.pSync;
 
-        if (pSync && !pSync->beingDestroyed)
-            SyncDeleteTriggerFromSyncObject(&pAwait->trigger);
+        if (pSync) {
+            if (!pSync->beingDestroyed) {
+                SyncDeleteTriggerFromSyncObject(&pAwait->trigger);
+            } else {
+                SyncTriggerList *ptl;
+
+                nt_list_for_each_entry(ptl, pSync->pTriglist, next) {
+                    if (ptl->pTrigger == &pAwait->trigger) {
+                        ptl->pTrigger = NULL;
+                        break;
+                    }
+                }
+            }
+        }
     }
     free(pAwaitUnion);
     return Success;
Index: xwayland-24.1.11/miext/sync/misync.c
===================================================================
--- xwayland-24.1.11.orig/miext/sync/misync.c
+++ xwayland-24.1.11/miext/sync/misync.c
@@ -115,10 +115,14 @@ miSyncDestroyFence(SyncFence * pFence)
         SyncScreenPrivPtr pScreenPriv = SYNC_SCREEN_PRIV(pScreen);
         SyncTriggerList *ptl, *pNext;
 
-        /* tell all the fence's triggers that the counter has been destroyed */
-        for (ptl = pFence->sync.pTriglist; ptl; ptl = pNext) {
-            (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger);
-            pNext = ptl->next;
+        /* tell all the fence's triggers that the fence has been destroyed.
+         * Update pTriglist before each callback and free so that FreeAwait
+         * sees a valid list head when scanning for triggers to NULL out.
+         */
+        nt_list_for_each_entry_safe(ptl, pNext, pFence->sync.pTriglist, next) {
+            pFence->sync.pTriglist = pNext;
+            if (ptl->pTrigger)
+                (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger);
             free(ptl); /* destroy the trigger list as we go */
         }
 

++++++ 
bsc1266296_CVE-2026-XXXX3_0003-xkb-reject-key-types-with-num_levels-exceeding-XkbMa.patch
 ++++++
>From 4a9709e23b1b32512d16eb6b037429b8a2c15ca8 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Mon, 20 Apr 2026 11:17:41 +1000
Subject: [PATCH xserver 3/9] xkb: reject key types with num_levels exceeding
 XkbMaxShiftLevel

CheckKeyTypes validates incoming key type definitions from XkbSetMap
requests but does not enforce an upper bound on numLevels. A client can set
numLevels up to 255 on a non-canonical key type, which is stored in the
server's type table.

When ChangeKeyboardMapping later triggers XkbUpdateKeyTypesFromCore, the
function XkbKeyTypesForCoreSymbols computes groupsWidth from num_levels and
uses the XKB_OFFSET(g, l) = (g * groupsWidth) + l macro to index into
tsyms[], a stack-allocated buffer of XkbMaxSymsPerKey (252) entries. With
num_levels=255, groupsWidth=255, and indices reach up to 3*255+254 = 1019,
overflowing the 252-element stack buffer by 767 KeySym-sized entries.

Fix by rejecting numLevels values greater than XkbMaxShiftLevel (63) in
CheckKeyTypes, alongside the existing lower-bound check for numLevels < 1.

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

ZDI-CAN-30160

Assisted-by: Claude:claude-opus-4-6
---
 xkb/xkb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git ./xkb/xkb.c ../xkb/xkb.c
index 6613519d392c..49c69a933761 100644
--- ./xkb/xkb.c
+++ ../xkb/xkb.c
@@ -1647,17 +1647,17 @@ CheckKeyTypes(ClientPtr client,
             *nMapsRtrn = _XkbErrCode3(0x0b, req->nTypes, i);
             return 0;
         }
         if (client->swapped && doswap) {
             swaps(&wire->virtualMods);
         }
         n = i + req->firstType;
         width = wire->numLevels;
-        if (width < 1) {
+        if (width < 1 || width > XkbMaxShiftLevel) {
             *nMapsRtrn = _XkbErrCode3(0x04, n, width);
             return 0;
         }
         else if ((n == XkbOneLevelIndex) && (width != 1)) {     /* must be 
width 1 */
             *nMapsRtrn = _XkbErrCode3(0x05, n, width);
             return 0;
         }
         else if ((width != 2) &&
-- 
2.53.0


++++++ 
bsc1266297_CVE-2026-XXXX4_0004-xkb-clamp-nMaps-to-mapWidths-buffer-size-in-CheckKey.patch
 ++++++
>From b9c08b30ea54b8bc1c5142304a6eb0ea1bc33a97 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Mon, 20 Apr 2026 11:18:13 +1000
Subject: [PATCH xserver 4/9] xkb: clamp nMaps to mapWidths buffer size in
 CheckKeyTypes

CheckKeyTypes computes nMaps = firstType + nTypes from client-controlled
request fields when XkbSetMapResizeTypes is set. This value is used to
index mapWidths[], a stack-allocated CARD8 array of XkbMaxLegalKeyCode + 1
(256) elements. No upper bound is enforced on nMaps.

An attacker can first send SetMap(firstType=0, nTypes=255, ResizeTypes) to
set the server's num_types to 255, then send SetMap(firstType=255,
nTypes=10, ResizeTypes). The firstType > num_types check passes because
255 > 255 is false (the check uses > rather than >=). nMaps is then
computed as 265, and the loop writes mapWidths[255..264], overflowing 9
bytes past the stack buffer into adjacent stack variables (symsPerKey[]).

Fix by rejecting requests where firstType + nTypes would exceed the
mapWidths buffer size (XkbMaxLegalKeyCode + 1).

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

ZDI-CAN-30161

Assisted-by: Claude:claude-opus-4-6
---
 xkb/xkb.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git ./xkb/xkb.c ../xkb/xkb.c
index 49c69a933761..7ee11bcd8b33 100644
--- ./xkb/xkb.c
+++ ../xkb/xkb.c
@@ -1616,16 +1616,21 @@ CheckKeyTypes(ClientPtr client,
         return 0;
     }
     if (req->flags & XkbSetMapResizeTypes) {
         nMaps = req->firstType + req->nTypes;
         if (nMaps < XkbNumRequiredTypes) {      /* canonical types must be 
there */
             *nMapsRtrn = _XkbErrCode4(0x02, req->firstType, req->nTypes, 4);
             return 0;
         }
+        if (nMaps > XkbMaxLegalKeyCode + 1) {
+            *nMapsRtrn = _XkbErrCode4(0x02, req->firstType, req->nTypes,
+                                      XkbMaxLegalKeyCode + 1);
+            return 0;
+        }
     }
     else if (req->present & XkbKeyTypesMask) {
         nMaps = xkb->map->num_types;
         if ((req->firstType + req->nTypes) > nMaps) {
             *nMapsRtrn = req->firstType + req->nTypes;
             return 0;
         }
     }
-- 
2.53.0


++++++ 
bsc1266299_CVE-2026-XXXX6_0002-sync-restart-trigger-list-iteration-in-SyncChangeCou.patch
 ++++++
>From 72010daffe03cb7f2ff3fe4f1272abfba709515e Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Mon, 20 Apr 2026 11:17:08 +1000
Subject: [PATCH xserver 2/9] sync: restart trigger list iteration in
 SyncChangeCounter after TriggerFired

This is the equivalent check to miSyncTriggerFence() from
commit f19ab94ba9c8 ("miext/sync: Fix use-after-free in miSyncTriggerFence()")

When a trigger fires via SyncAwaitTriggerFired, the resulting
FreeResource/FreeAwait call invokes SyncDeleteTriggerFromSyncObject for
every trigger in the same Await group. This unlinks and frees the
corresponding trigger list nodes - potentially including the node pnext
points to.

Fix by restarting iteration from the list head after a trigger fires, since
TriggerFired may have arbitrarily mutated the list. Triggers that have fired
are removed from the list by FreeAwait, so restarting cannot cause infinite
loops.

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

ZDI-CAN-30164

Assisted-by: Claude:claude-opus-4-6
---
 Xext/sync.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git ./Xext/sync.c ../Xext/sync.c
index 20ee8f620aef..d6bb5b4b6ce7 100644
--- ./Xext/sync.c
+++ ../Xext/sync.c
@@ -718,18 +718,39 @@ SyncChangeCounter(SyncCounter * pCounter, int64_t newval)
     SyncTriggerList *ptl, *pnext;
     int64_t oldval;
 
     oldval = SyncUpdateCounter(pCounter, newval);
 
     /* run through triggers to see if any become true */
     for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) {
         pnext = ptl->next;
-        if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval))
+        if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval)) {
             (*ptl->pTrigger->TriggerFired) (ptl->pTrigger);
+            /* TriggerFired may have called SyncDeleteTriggerFromSyncObject
+             * for sibling triggers in the same Await group, freeing their
+             * trigger list nodes - potentially including pnext. Verify
+             * pnext is still on the counter's trigger list; if not,
+             * restart from the list head.
+             *
+             * Unlike miSyncTriggerFence() we cannot use a do/while
+             * restart loop here: counter trigger lists may contain alarm
+             * triggers which are not removed after firing and would cause
+             * an infinite loop when delta is 0.
+             */
+            if (pnext) {
+                SyncTriggerList *tmp;
+                for (tmp = pCounter->sync.pTriglist; tmp; tmp = tmp->next) {
+                    if (tmp == pnext)
+                        break;
+                }
+                if (!tmp)
+                    pnext = pCounter->sync.pTriglist;
+            }
+        }
     }
 
     if (IsSystemCounter(pCounter)) {
         SyncComputeBracketValues(pCounter);
     }
 }
 
 /* loosely based on dix/events.c/EventSelectForWindow */
-- 
2.53.0


++++++ 
bsc1266300_CVE-2026-XXXX7_0005-glx-fix-reversed-length-check-in-ChangeDrawableAttri.patch
 ++++++
>From f96e21359f03121daf97d7a10f8e56195f1e8b4d Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Mon, 20 Apr 2026 11:18:48 +1000
Subject: [PATCH xserver 5/9] glx: fix reversed length check in
 ChangeDrawableAttributes

The request length validation in __glXDisp_ChangeDrawableAttributes and
__glXDispSwap_ChangeDrawableAttributes uses the wrong comparison direction.
The check tests whether the computed request size is LESS THAN
client->req_len, but should test whether it is GREATER THAN. With the
reversed operator, an undersized request (where numAttribs claims more
attribute pairs than the request actually contains) passes validation.

DoChangeDrawableAttributes then iterates numAttribs attribute pairs starting
from the end of the request header, reading past the actual request data
into adjacent memory. This is an out-of-bounds read that can also cause
an out-of-bounds write when a GLX_EVENT_MASK attribute key is found in the
overread data and its corresponding value is written to pGlxDraw->eventMask.

This patch effectively reverts commit 402b329c3aa8 ("glx: Work around
wrong request lengths sent by mesa"). This was fixed in mesa commit
4324d6fdfbba1 in 2011 (mesa 7.11).

Fixes: 402b329c3aa8 ("glx: Work around wrong request lengths sent by mesa")

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

ZDI-CAN-30165

Assisted-by: Claude:claude-opus-4-6
---
 glx/glxcmds.c     | 21 +++++----------------
 glx/glxcmdsswap.c | 12 +++++-------
 2 files changed, 10 insertions(+), 23 deletions(-)

diff --git ./glx/glxcmds.c ../glx/glxcmds.c
index 3971809d4e2c..c7d32ab3a416 100644
--- ./glx/glxcmds.c
+++ ../glx/glxcmds.c
@@ -1135,18 +1135,17 @@ __glXDisp_GetFBConfigs(__GLXclientState * cl, GLbyte * 
pc)
 }
 
 int
 __glXDisp_GetFBConfigsSGIX(__GLXclientState * cl, GLbyte * pc)
 {
     ClientPtr client = cl->client;
     xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *) pc;
 
-    /* work around mesa bug, don't use REQUEST_SIZE_MATCH */
-    REQUEST_AT_LEAST_SIZE(xGLXGetFBConfigsSGIXReq);
+    REQUEST_SIZE_MATCH(xGLXGetFBConfigsSGIXReq);
     return DoGetFBConfigs(cl, req->screen);
 }
 
 GLboolean
 __glXDrawableInit(__GLXdrawable * drawable,
                   __GLXscreen * screen, DrawablePtr pDraw, int type,
                   XID drawId, __GLXconfig * config)
 {
@@ -1357,19 +1356,17 @@ __glXDisp_DestroyGLXPixmap(__GLXclientState * cl, 
GLbyte * pc)
 }
 
 int
 __glXDisp_DestroyPixmap(__GLXclientState * cl, GLbyte * pc)
 {
     ClientPtr client = cl->client;
     xGLXDestroyPixmapReq *req = (xGLXDestroyPixmapReq *) pc;
 
-    /* should be REQUEST_SIZE_MATCH, but mesa's glXDestroyPixmap used to set
-     * length to 3 instead of 2 */
-    REQUEST_AT_LEAST_SIZE(xGLXDestroyPixmapReq);
+    REQUEST_SIZE_MATCH(xGLXDestroyPixmapReq);
 
     return DoDestroyDrawable(cl, req->glxpixmap, GLX_DRAWABLE_PIXMAP);
 }
 
 static int
 DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId,
                 int width, int height, XID glxDrawableId)
 {
@@ -1515,24 +1512,18 @@ __glXDisp_ChangeDrawableAttributes(__GLXclientState * 
cl, GLbyte * pc)
     xGLXChangeDrawableAttributesReq *req =
         (xGLXChangeDrawableAttributesReq *) pc;
 
     REQUEST_AT_LEAST_SIZE(xGLXChangeDrawableAttributesReq);
     if (req->numAttribs > (UINT32_MAX >> 3)) {
         client->errorValue = req->numAttribs;
         return BadValue;
     }
-#if 0
-    /* mesa sends an additional 8 bytes */
+
     REQUEST_FIXED_SIZE(xGLXChangeDrawableAttributesReq, req->numAttribs << 3);
-#else
-    if (((sizeof(xGLXChangeDrawableAttributesReq) +
-          (req->numAttribs << 3)) >> 2) < client->req_len)
-        return BadLength;
-#endif
 
     return DoChangeDrawableAttributes(cl->client, req->drawable,
                                       req->numAttribs, (CARD32 *) (req + 1));
 }
 
 int
 __glXDisp_ChangeDrawableAttributesSGIX(__GLXclientState * cl, GLbyte * pc)
 {
@@ -1589,18 +1580,17 @@ __glXDisp_CreateWindow(__GLXclientState * cl, GLbyte * 
pc)
 }
 
 int
 __glXDisp_DestroyWindow(__GLXclientState * cl, GLbyte * pc)
 {
     ClientPtr client = cl->client;
     xGLXDestroyWindowReq *req = (xGLXDestroyWindowReq *) pc;
 
-    /* mesa's glXDestroyWindow used to set length to 3 instead of 2 */
-    REQUEST_AT_LEAST_SIZE(xGLXDestroyWindowReq);
+    REQUEST_SIZE_MATCH(xGLXDestroyWindowReq);
 
     return DoDestroyDrawable(cl, req->glxwindow, GLX_DRAWABLE_WINDOW);
 }
 
 /*****************************************************************************/
 
 /*
 ** NOTE: There is no portable implementation for swap buffers as of
@@ -1952,18 +1942,17 @@ DoGetDrawableAttributes(__GLXclientState * cl, XID 
drawId)
 }
 
 int
 __glXDisp_GetDrawableAttributes(__GLXclientState * cl, GLbyte * pc)
 {
     ClientPtr client = cl->client;
     xGLXGetDrawableAttributesReq *req = (xGLXGetDrawableAttributesReq *) pc;
 
-    /* this should be REQUEST_SIZE_MATCH, but mesa sends an additional 4 bytes 
*/
-    REQUEST_AT_LEAST_SIZE(xGLXGetDrawableAttributesReq);
+    REQUEST_SIZE_MATCH(xGLXGetDrawableAttributesReq);
 
     return DoGetDrawableAttributes(cl, req->drawable);
 }
 
 int
 __glXDisp_GetDrawableAttributesSGIX(__GLXclientState * cl, GLbyte * pc)
 {
     ClientPtr client = cl->client;
diff --git ./glx/glxcmdsswap.c ../glx/glxcmdsswap.c
index dc38ff3ad87e..3f7880f41c3c 100644
--- ./glx/glxcmdsswap.c
+++ ../glx/glxcmdsswap.c
@@ -231,17 +231,17 @@ __glXDispSwap_GetFBConfigs(__GLXclientState * cl, GLbyte 
* pc)
 int
 __glXDispSwap_GetFBConfigsSGIX(__GLXclientState * cl, GLbyte * pc)
 {
     ClientPtr client = cl->client;
     xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_AT_LEAST_SIZE(xGLXGetFBConfigsSGIXReq);
+    REQUEST_SIZE_MATCH(xGLXGetFBConfigsSGIXReq);
 
     __GLX_SWAP_INT(&req->screen);
     return __glXDisp_GetFBConfigsSGIX(cl, pc);
 }
 
 int
 __glXDispSwap_CreateGLXPixmap(__GLXclientState * cl, GLbyte * pc)
 {
@@ -323,17 +323,17 @@ __glXDispSwap_DestroyGLXPixmap(__GLXclientState * cl, 
GLbyte * pc)
 int
 __glXDispSwap_DestroyPixmap(__GLXclientState * cl, GLbyte * pc)
 {
     ClientPtr client = cl->client;
     xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_AT_LEAST_SIZE(xGLXDestroyGLXPixmapReq);
+    REQUEST_SIZE_MATCH(xGLXDestroyGLXPixmapReq);
 
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->glxpixmap);
 
     return __glXDisp_DestroyGLXPixmap(cl, pc);
 }
 
 int
@@ -436,19 +436,17 @@ __glXDispSwap_ChangeDrawableAttributes(__GLXclientState * 
cl, GLbyte * pc)
 
     __GLX_SWAP_INT(&req->drawable);
     __GLX_SWAP_INT(&req->numAttribs);
 
     if (req->numAttribs > (UINT32_MAX >> 3)) {
         client->errorValue = req->numAttribs;
         return BadValue;
     }
-    if (((sizeof(xGLXChangeDrawableAttributesReq) +
-          (req->numAttribs << 3)) >> 2) < client->req_len)
-        return BadLength;
+    REQUEST_FIXED_SIZE(xGLXChangeDrawableAttributesReq, req->numAttribs << 3);
 
     attribs = (CARD32 *) (req + 1);
     __GLX_SWAP_INT_ARRAY(attribs, req->numAttribs << 1);
 
     return __glXDisp_ChangeDrawableAttributes(cl, pc);
 }
 
 int
@@ -510,17 +508,17 @@ __glXDispSwap_CreateWindow(__GLXclientState * cl, GLbyte 
* pc)
 int
 __glXDispSwap_DestroyWindow(__GLXclientState * cl, GLbyte * pc)
 {
     ClientPtr client = cl->client;
     xGLXDestroyWindowReq *req = (xGLXDestroyWindowReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_AT_LEAST_SIZE(xGLXDestroyWindowReq);
+    REQUEST_SIZE_MATCH(xGLXDestroyWindowReq);
 
     __GLX_SWAP_INT(&req->glxwindow);
 
     return __glXDisp_DestroyWindow(cl, pc);
 }
 
 int
 __glXDispSwap_SwapBuffers(__GLXclientState * cl, GLbyte * pc)
@@ -719,17 +717,17 @@ __glXDispSwap_GetDrawableAttributesSGIX(__GLXclientState 
* cl, GLbyte * pc)
 int
 __glXDispSwap_GetDrawableAttributes(__GLXclientState * cl, GLbyte * pc)
 {
     ClientPtr client = cl->client;
     xGLXGetDrawableAttributesReq *req = (xGLXGetDrawableAttributesReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_AT_LEAST_SIZE(xGLXGetDrawableAttributesReq);
+    REQUEST_SIZE_MATCH(xGLXGetDrawableAttributesReq);
 
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->drawable);
 
     return __glXDisp_GetDrawableAttributes(cl, pc);
 }
 
 /************************************************************************/
-- 
2.53.0


++++++ 
bsc1266301_CVE-2026-XXXX8_0006-saver-re-fetch-screen-private-after-CheckScreenPriva.patch
 ++++++
>From 16c0c0ab92fdeccca9791209d90826f76159b134 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Mon, 20 Apr 2026 11:19:20 +1000
Subject: [PATCH xserver 6/9] saver: re-fetch screen private after
 CheckScreenPrivate in CreateSaverWindow
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

CreateSaverWindow stores pPriv (the ScreenSaverScreenPrivatePtr) in a local
variable via the SetupScreen macro at function entry. When an existing saver
window is being replaced, the function sets pPriv->hasWindow = FALSE and
calls CheckScreenPrivate(). If at this point pPriv->attr is NULL (cleared
by a prior UnsetAttributes call), pPriv->events is NULL, and
pPriv->installedMap is None, then CheckScreenPrivate determines the screen
private is unused, frees it, and sets the screen private pointer to NULL.

The function then continues to dereference the now-freed pPriv on the very
next line (pPriv->attr), resulting in a use-after-free. On glibc 2.34+,
the tcache key at offset 8 within the freed block makes pPriv->attr appear
non-NULL, causing the function to continue operating on garbage data and
eventually crash.

The attack sequence is:
  1. SetAttributes (creates pPriv with pPriv->attr set)
  2. ForceScreenSaver(Active) (creates saver window, pPriv->hasWindow=TRUE)
  3. UnsetAttributes (sets pPriv->attr = NULL)
  4. ForceScreenSaver(Active) (re-enters CreateSaverWindow → UAF)

Fix by re-fetching pPriv from the screen private after CheckScreenPrivate
returns, so the subsequent NULL check correctly detects the freed state.

ScreenSaverFreeAttr has the same pattern, force pPriv to NULL there too
even though it has no real effect.

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

ZDI-CAN-30168

Assisted-by: Claude:claude-opus-4-6
---
 Xext/saver.c | 5 +++++
 1 file changed, 5 insertions(+)

Index: xwayland-24.1.11/Xext/saver.c
===================================================================
--- xwayland-24.1.11.orig/Xext/saver.c
+++ xwayland-24.1.11/Xext/saver.c
@@ -348,6 +348,9 @@ ScreenSaverFreeAttr(void *value, XID id)
         dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverActive);
     }
     CheckScreenPrivate(pScreen);
+    /* CheckScreenPrivate may have freed pPriv (same pattern as
+     * CreateSaverWindow fix for ZDI-CAN-30168). */
+    pPriv = NULL;
     return TRUE;
 }
 
@@ -479,6 +482,8 @@ CreateSaverWindow(ScreenPtr pScreen)
             UninstallSaverColormap(pScreen);
             pPriv->hasWindow = FALSE;
             CheckScreenPrivate(pScreen);
+            /* Re-fetch pPriv since CheckScreenPrivate may have freed it */
+            pPriv = GetScreenPrivate(pScreen);
         }
     }
 

Reply via email to