Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package xorg-x11-server for openSUSE:Factory
checked in at 2026-10-10 14:57:33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/xorg-x11-server (Old)
and /work/SRC/openSUSE:Factory/.xorg-x11-server.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "xorg-x11-server"
Sat Oct 10 14:57:33 2026 rev:454 rq:1383336 version:21.1.24
Changes:
--------
--- /work/SRC/openSUSE:Factory/xorg-x11-server/xorg-x11-server.changes
2026-07-17 18:48:18.122868896 +0200
+++
/work/SRC/openSUSE:Factory/.xorg-x11-server.new.3698736/xorg-x11-server.changes
2026-10-10 14:58:12.744049565 +0200
@@ -1,0 +2,37 @@
+Thu Oct 8 01:41:51 UTC 2026 - Stefan Dirsch <[email protected]>
+
+- 0001-xkb-NULL-text-pointer-after-free-in-_CheckSetDoodad-.patch
+ XKB SetGeometry TextDoodad Double Free
+ (bsc#1281213, CVE-2026-88812, ZDI-CAN-31221)
+- 0002-xkb-allocate-names-keys-to-MAP_LENGTH-in-XkbAllocNam.patch
+ XKB ChangeKeycodeRange Heap Out-of-Bounds Write
+ (bsc#1281236, CVE-2026-93520, ZDI-CAN-31941)
+- 0003-xkb-widen-size_syms-num_syms-size_acts-num_acts-to-u.patch
+ XKB ResizeKeyType Numeric Truncation
+ (bsc#1281227, CVE-2026-93518, ZDI-CAN-31834)
+- 0004-xkb-fix-CheckKeySyms-overwriting-request-range-symsP.patch
+ XKB SetMap Key Width/Action Count Desync Out-Of-Bounds Read
+ (bsc#1281242, CVE-2026-93524, ZDI-CAN-32408)
+- 0005-randr-fix-size-and-offset-in-RRChangeProviderPropert.patch
+ RandR ChangeProviderProperty Heap Buffer Overflow
+ (bsc#1281238, CVE-2026-93521, ZDI-CAN-31944)
+- 0006-Xi-validate-modifier-values-in-ProcXIPassiveUngrabDe.patch
+ XInput2 PassiveUngrabDevice Out-of-Bounds Write
+ (bsc#1281241, CVE-2026-93523, ZDI-CAN-32366)
+- 0007-glx-validate-dataBytes-against-cmdlen-in-RenderLarge.patch
+ GLX RenderLarge Heap Buffer Overflow
+ (bsc#1281225, CVE-2026-93517, ZDI-CAN-31833)
+- 0008-present-unlink-notifies-from-window-list-in-present_.patch
+ X.Org Server Present Extension Use-After-Free
+ (bsc#1281218, CVE-2026-93515, ZDI-CAN-31830)
+- 0009-dix-remove-passive-grabs-referencing-a-device-on-rem.patch
+ X.Org Server XInput Passive Grab Use-After-Free
+ (bsc#1281220, CVE-2026-93516, ZDI-CAN-31832)
+- 0010-Xi-add-bounds-check-for-barrier-events-in-input_cons.patch
+ XFixes Pointer Barrier Event List Buffer Overflow
+ (bsc#1281233, CVE-2026-93519, ZDI-CAN-31938)
+- 0011-Xi-clean-up-gesture-sprite-traces-in-WindowGone.patch
+ GestureBuildSprite Use-After-Free
+ (bsc#1281244 CVE-2026-93536, ZDI-CAN-32753)
+
+-------------------------------------------------------------------
New:
----
0001-xkb-NULL-text-pointer-after-free-in-_CheckSetDoodad-.patch
0002-xkb-allocate-names-keys-to-MAP_LENGTH-in-XkbAllocNam.patch
0003-xkb-widen-size_syms-num_syms-size_acts-num_acts-to-u.patch
0004-xkb-fix-CheckKeySyms-overwriting-request-range-symsP.patch
0005-randr-fix-size-and-offset-in-RRChangeProviderPropert.patch
0006-Xi-validate-modifier-values-in-ProcXIPassiveUngrabDe.patch
0007-glx-validate-dataBytes-against-cmdlen-in-RenderLarge.patch
0008-present-unlink-notifies-from-window-list-in-present_.patch
0009-dix-remove-passive-grabs-referencing-a-device-on-rem.patch
0010-Xi-add-bounds-check-for-barrier-events-in-input_cons.patch
0011-Xi-clean-up-gesture-sprite-traces-in-WindowGone.patch
----------(New B)----------
New:
- 0001-xkb-NULL-text-pointer-after-free-in-_CheckSetDoodad-.patch
XKB SetGeometry TextDoodad Double Free
New: (bsc#1281213, CVE-2026-88812, ZDI-CAN-31221)
- 0002-xkb-allocate-names-keys-to-MAP_LENGTH-in-XkbAllocNam.patch
XKB ChangeKeycodeRange Heap Out-of-Bounds Write
New: (bsc#1281236, CVE-2026-93520, ZDI-CAN-31941)
- 0003-xkb-widen-size_syms-num_syms-size_acts-num_acts-to-u.patch
XKB ResizeKeyType Numeric Truncation
New: (bsc#1281227, CVE-2026-93518, ZDI-CAN-31834)
- 0004-xkb-fix-CheckKeySyms-overwriting-request-range-symsP.patch
XKB SetMap Key Width/Action Count Desync Out-Of-Bounds Read
New: (bsc#1281242, CVE-2026-93524, ZDI-CAN-32408)
- 0005-randr-fix-size-and-offset-in-RRChangeProviderPropert.patch
RandR ChangeProviderProperty Heap Buffer Overflow
New: (bsc#1281238, CVE-2026-93521, ZDI-CAN-31944)
- 0006-Xi-validate-modifier-values-in-ProcXIPassiveUngrabDe.patch
XInput2 PassiveUngrabDevice Out-of-Bounds Write
New: (bsc#1281241, CVE-2026-93523, ZDI-CAN-32366)
- 0007-glx-validate-dataBytes-against-cmdlen-in-RenderLarge.patch
GLX RenderLarge Heap Buffer Overflow
New: (bsc#1281225, CVE-2026-93517, ZDI-CAN-31833)
- 0008-present-unlink-notifies-from-window-list-in-present_.patch
X.Org Server Present Extension Use-After-Free
New: (bsc#1281218, CVE-2026-93515, ZDI-CAN-31830)
- 0009-dix-remove-passive-grabs-referencing-a-device-on-rem.patch
X.Org Server XInput Passive Grab Use-After-Free
New: (bsc#1281220, CVE-2026-93516, ZDI-CAN-31832)
- 0010-Xi-add-bounds-check-for-barrier-events-in-input_cons.patch
XFixes Pointer Barrier Event List Buffer Overflow
New: (bsc#1281233, CVE-2026-93519, ZDI-CAN-31938)
- 0011-Xi-clean-up-gesture-sprite-traces-in-WindowGone.patch
GestureBuildSprite Use-After-Free
----------(New E)----------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ xorg-x11-server.spec ++++++
--- /var/tmp/diff_new_pack.Y9McP0/_old 2026-10-10 14:58:14.731132700 +0200
+++ /var/tmp/diff_new_pack.Y9McP0/_new 2026-10-10 14:58:14.732132742 +0200
@@ -242,6 +242,18 @@
Patch1218176: u_miCloseScreen_check_for_null_pScreen_dev_private.patch
+Patch1281213: 0001-xkb-NULL-text-pointer-after-free-in-_CheckSetDoodad-.patch
+Patch1281236: 0002-xkb-allocate-names-keys-to-MAP_LENGTH-in-XkbAllocNam.patch
+Patch1281227: 0003-xkb-widen-size_syms-num_syms-size_acts-num_acts-to-u.patch
+Patch1281242: 0004-xkb-fix-CheckKeySyms-overwriting-request-range-symsP.patch
+Patch1281238: 0005-randr-fix-size-and-offset-in-RRChangeProviderPropert.patch
+Patch1281241: 0006-Xi-validate-modifier-values-in-ProcXIPassiveUngrabDe.patch
+Patch1281225: 0007-glx-validate-dataBytes-against-cmdlen-in-RenderLarge.patch
+Patch1281218: 0008-present-unlink-notifies-from-window-list-in-present_.patch
+Patch1281220: 0009-dix-remove-passive-grabs-referencing-a-device-on-rem.patch
+Patch1281233: 0010-Xi-add-bounds-check-for-barrier-events-in-input_cons.patch
+Patch1281244: 0011-Xi-clean-up-gesture-sprite-traces-in-WindowGone.patch
+
%description
This package contains the X.Org Server.
@@ -395,6 +407,18 @@
%patch -P 1218176 -p1
+%patch -P 1281213 -p1
+%patch -P 1281236 -p1
+%patch -P 1281227 -p1
+%patch -P 1281242 -p1
+%patch -P 1281238 -p1
+%patch -P 1281241 -p1
+%patch -P 1281225 -p1
+%patch -P 1281218 -p1
+%patch -P 1281220 -p1
+%patch -P 1281233 -p1
+%patch -P 1281244 -p1
+
%build
# We have some -z now related errors during X default startup (boo#1197994):
# - when loading modesetting: gbm_bo_get_plane_count
++++++ 0001-xkb-NULL-text-pointer-after-free-in-_CheckSetDoodad-.patch ++++++
>From 0d1b1b0bad86c9ea2a3b7ca5a70e681dc69f1ecc Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Wed, 26 Aug 2026 16:53:56 +1000
Subject: [PATCH 01/12] xkb: NULL text pointer after free in _CheckSetDoodad
error path
_CheckSetDoodad() allocates doodad->text.text via _GetCountedString()
and then attempts to allocate doodad->text.font. If the font string
allocation fails (e.g. because the font string length extends past
the request boundary), the error handler frees doodad->text.text but
does not NULL the pointer. The doodad was already added to the geometry
by XkbAddGeomDoodad() before the string allocations, so when
XkbFreeGeometry() runs cleanup, _XkbClearDoodad() frees the same
dangling pointer again, resulting in a double-free.
NULL the pointer after freeing it to prevent the double-free.
This vulnerability was discovered by:
Anonymous working with TrendAI Zero Day Initiative
ZDI-CAN-31221
CVE-2026-88812
Signed-off-by: Peter Hutterer <[email protected]>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
test/pyxtest/proto/xkb.py | 62 +++++++++++++++++++++++++++++++++++++++
test/pyxtest/test_xkb.py | 60 +++++++++++++++++++++++++++++++++++++
xkb/xkb.c | 3 +-
3 files changed, 124 insertions(+), 1 deletion(-)
diff --git a/xkb/xkb.c b/xkb/xkb.c
index 67c9b3dbe..961ce9ca3 100644
--- a/xkb/xkb.c
+++ b/xkb/xkb.c
@@ -5312,7 +5312,8 @@ _CheckSetDoodad(char **wire_inout, xkbSetGeometryReq *req,
return status;
status = _GetCountedString(&wire, client, &doodad->text.font);
if (status != Success) {
- free (doodad->text.text);
+ free(doodad->text.text);
+ doodad->text.text = NULL;
return status;
}
break;
--
2.51.0
++++++ 0002-xkb-allocate-names-keys-to-MAP_LENGTH-in-XkbAllocNam.patch ++++++
>From b941a473e06f26a407a9adb15759be79f7418e86 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Wed, 26 Aug 2026 17:04:03 +1000
Subject: [PATCH 02/12] xkb: allocate names->keys to MAP_LENGTH in
XkbAllocNames
Commit a3171732d ("xkb: Always use MAP_LENGTH keymap size") converted
most XKB allocation functions to use MAP_LENGTH (256) instead of
max_key_code + 1. It also removed the per-array reallocarray() calls in
XkbChangeKeycodeRange(), replacing them with a memset up to MAP_LENGTH.
However, XkbAllocNames() was missed and still allocates names->keys to
max_key_code + 1.
When a keycodes component with max_key_code < 255 is loaded (e.g.
sun(type6) with max_key_code=132) and then a SetMap request extends
maxKeyCode to 255, XkbChangeKeycodeRange() memsets names->keys from
max_key_code to MAP_LENGTH-1, writing past the undersized allocation.
Fix by allocating names->keys to MAP_LENGTH, consistent with all other
keymap arrays after a3171732d.
This vulnerability was discovered by:
Anonymous working with TrendAI Zero Day Initiative
ZDI-CAN-31941
CVE-2026-93520
Fixes: a3171732da50 ("xkb: Always use MAP_LENGTH keymap size")
Signed-off-by: Peter Hutterer <[email protected]>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
test/pyxtest/test_xkb.py | 75 ++++++++++++++++++++++++++++++++++++++++
xkb/XKBAlloc.c | 2 +-
2 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/xkb/XKBAlloc.c b/xkb/XKBAlloc.c
index dced42eeb..314a858dd 100644
--- a/xkb/XKBAlloc.c
+++ b/xkb/XKBAlloc.c
@@ -148,7 +148,7 @@ XkbAllocNames(XkbDescPtr xkb, unsigned which, int nTotalRG,
int nTotalAliases)
(!XkbIsLegalKeycode(xkb->max_key_code)) ||
(xkb->max_key_code < xkb->min_key_code))
return BadValue;
- names->keys = calloc((xkb->max_key_code + 1), sizeof(XkbKeyNameRec));
+ names->keys = calloc(MAP_LENGTH, sizeof(XkbKeyNameRec));
if (names->keys == NULL)
return BadAlloc;
}
--
2.51.0
++++++ 0003-xkb-widen-size_syms-num_syms-size_acts-num_acts-to-u.patch ++++++
>From 89101a6c6618f543d7502f2077c7ef1a507af256 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Wed, 26 Aug 2026 16:57:38 +1000
Subject: [PATCH 03/12] xkb: widen size_syms, num_syms, size_acts, num_acts to
unsigned int
Fields in XkbClientMapRec and XkbServerMapRec that denote size/num
and are unsigned short can result in truncations. For example
when XkbResizeKeyType() computes the new size_syms value as
(nTotal * 15) / 10, the result may be implicitly truncated to 16
bits on assignment. This causes an undersized calloc allocation, and the
subsequent copy loop writes based on the actual (untruncated) key count,
resulting in a heap buffer overflow. A similar truncation may happen
in XkbResizeKeySyms() and XkbResizeKeyActions().
Widen the fields from unsigned short to unsigned int. These are internal
server structures, not wire protocol types.
This vulnerability was discovered by:
Anonymous working with TrendAI Zero Day Initiative
ZDI-CAN-31834
CVE-2026-93518
Signed-off-by: Peter Hutterer <[email protected]>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
include/xkbstr.h | 8 +--
test/pyxtest/test_xkb.py | 104 +++++++++++++++++++++++++++++++++++++++
xkb/XKBMAlloc.c | 3 +-
3 files changed, 110 insertions(+), 5 deletions(-)
diff --git a/include/xkbstr.h b/include/xkbstr.h
index 749f1f26e..45a15f376 100644
--- a/include/xkbstr.h
+++ b/include/xkbstr.h
@@ -312,8 +312,8 @@ typedef struct _XkbControls {
XkbAX_NeedOption((c), (w)))
typedef struct _XkbServerMapRec {
- unsigned short num_acts;
- unsigned short size_acts;
+ unsigned int num_acts;
+ unsigned int size_acts;
XkbAction *acts;
XkbBehavior *behaviors;
@@ -346,8 +346,8 @@ typedef struct _XkbClientMapRec {
unsigned char num_types;
XkbKeyTypePtr types;
- unsigned short size_syms;
- unsigned short num_syms;
+ unsigned int size_syms;
+ unsigned int num_syms;
KeySym *syms;
XkbSymMapPtr key_sym_map;
diff --git a/xkb/XKBMAlloc.c b/xkb/XKBMAlloc.c
index 78e597f3d..8f8ac28fa 100644
--- a/xkb/XKBMAlloc.c
+++ b/xkb/XKBMAlloc.c
@@ -385,7 +385,8 @@ XkbResizeKeyType(XkbDescPtr xkb,
}
if (nResize > 0) {
int nextMatch;
-
+ if (nTotal > INT_MAX / 15)
+ return BadAlloc;
xkb->map->size_syms = (nTotal * 15) / 10;
newSyms = calloc(xkb->map->size_syms, sizeof(KeySym));
if (newSyms == NULL)
--
2.51.0
++++++ 0004-xkb-fix-CheckKeySyms-overwriting-request-range-symsP.patch ++++++
>From cea71d0273e4d5092aa9c6a8a770734c8935c02e Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Thu, 3 Sep 2026 14:55:27 +1000
Subject: [PATCH 04/12] xkb: fix CheckKeySyms overwriting request-range
symsPerKey entries
CheckKeySyms() has two loops: the first processes keys in the SetMap
request range, the second fills in any missing keys from the existing
map.
The indexing between the two was inconsistent: the first loop
uses a zero-based index + req->firstKeySym, the second loop used it just
as zero-based index.
Example:
req->firstKeySym = 50
req->nKeySyms = 10
i goes from 0 to 10,
loop 1 checks [50, 60), changes the width but finishes with i at 10.
loop 2 then runs over [10, 255(, copying the old keymap width
The second loop overwrites the new widths with the width of the
existing keymap. The subsequent SetKeySyms worked on the new width
and may write fewer actions than the map width.
A subsequent XkbGetMap request would then read XkbKeyNumActions()
entries (derived from the new wider key_sym_map.width) from the shorter
action allocation, causing an out-of-bounds heap read. The overread
bytes would be copied into the GetMap reply and sent back to the client,
producing a bounded heap information disclosure.
This vulnerability was discovered by:
WONJOON HWANG (@joon1337) working with TrendAI Zero Day Initiative
ZDI-CAN-32408
CVE-2026-93524
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
test/pyxtest/test_xkb.py | 161 +++++++++++++++++++++++++++++++++++++++
xkb/xkb.c | 1 +
2 files changed, 162 insertions(+)
diff --git a/xkb/xkb.c b/xkb/xkb.c
index 961ce9ca3..f0fa89be7 100644
--- a/xkb/xkb.c
+++ b/xkb/xkb.c
@@ -1813,6 +1813,7 @@ CheckKeySyms(ClientPtr client,
wire = (xkbSymMapWireDesc *) &pSyms[wire->nSyms];
}
+ i = req->firstKeySym + req->nKeySyms;
map = &xkb->map->key_sym_map[i];
for (; i <= (unsigned) xkb->max_key_code; i++, map++) {
register int g, nG, w;
--
2.51.0
++++++ 0005-randr-fix-size-and-offset-in-RRChangeProviderPropert.patch ++++++
>From 5dc9efd5a199717b53f70b9c6cd336a522370e46 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Wed, 26 Aug 2026 17:04:35 +1000
Subject: [PATCH 05/12] randr: fix size and offset in RRChangeProviderProperty
PrependMode
RRChangeProviderProperty() has two bugs in the PropModePrepend case:
1. new_value.size is set to 'len' (the new data length) instead of
'total_len' (len + prop_value->size), losing track of the existing
data. This also affects PropModeAppend.
2. The old_data offset is computed using prop_value->size instead of
len. For PrependMode, the layout should be [new(len)][old(size)],
so old_data should start at len * size_in_bytes.
These bugs are analogous to the ones fixed in RRChangeOutputProperty(),
see commit 541ab2ecd41d ("Xi/randr: fix handling of PropModeAppend/Prepend").
This vulnerability was discovered by:
Anonymous working with TrendAI Zero Day Initiative
ZDI-CAN-31944
CVE-2026-93521
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Peter Hutterer <[email protected]>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
randr/rrproviderproperty.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/randr/rrproviderproperty.c b/randr/rrproviderproperty.c
index a14865583..2e53291ee 100644
--- a/randr/rrproviderproperty.c
+++ b/randr/rrproviderproperty.c
@@ -191,7 +191,7 @@ RRChangeProviderProperty(RRProviderPtr provider, Atom
property, Atom type,
RRDestroyProviderProperty(prop);
return BadAlloc;
}
- new_value.size = len;
+ new_value.size = total_len;
new_value.type = type;
new_value.format = format;
@@ -208,7 +208,7 @@ RRChangeProviderProperty(RRProviderPtr provider, Atom
property, Atom type,
case PropModePrepend:
new_data = new_value.data;
old_data = (void *) (((char *) new_value.data) +
- (prop_value->size * size_in_bytes));
+ (len * size_in_bytes));
break;
}
if (new_data)
--
2.51.0
++++++ 0006-Xi-validate-modifier-values-in-ProcXIPassiveUngrabDe.patch ++++++
>From 37a1847a60c6799aecf163a5cfa40077a9002675 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Wed, 26 Aug 2026 17:04:20 +1000
Subject: [PATCH 06/12] Xi: validate modifier values in
ProcXIPassiveUngrabDevice
ProcXIPassiveUngrabDevice() passes client-supplied modifier values
directly to DeletePassiveGrabFromList() without validating them.
DeletePassiveGrabFromList() may reach DeleteDetailFromMask() which uses
BITCLEAR(mask, modifier). The mask is allocated as 8 Mask words (256
bits). A modifier value > 255 causes BITCLEAR to index mask[modifier>>5]
past the allocation, resulting in a controlled single-bit-clear at an
attacker-chosen heap offset.
Add the same modifier validation that CheckGrabValues() uses: reject
modifiers that are not XIAnyModifier and have bits set outside
AllModifiersMask.
This vulnerability was discovered by:
Anonymous working with TrendAI Zero Day Initiative
ZDI-CAN-32366
CVE-2026-93523
Signed-off-by: Peter Hutterer <[email protected]>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
Xi/xipassivegrab.c | 12 ++++++++++
test/pyxtest/test_xi.py | 51 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 63 insertions(+)
diff --git a/Xi/xipassivegrab.c b/Xi/xipassivegrab.c
index 65b7b805a..181f430a4 100644
--- a/Xi/xipassivegrab.c
+++ b/Xi/xipassivegrab.c
@@ -46,6 +46,10 @@
#include "misc.h"
#include "inpututils.h"
+#define AllModifiersMask ( \
+ ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \
+ Mod3Mask | Mod4Mask | Mod5Mask )
+
int _X_COLD
SProcXIPassiveGrabDevice(ClientPtr client)
{
@@ -350,6 +354,14 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
if (rc != Success)
return rc;
+ modifiers = (uint32_t *) &stuff[1];
+ for (i = 0; i < stuff->num_modifiers; i++, modifiers++) {
+ if (*modifiers != XIAnyModifier && (*modifiers & ~AllModifiersMask)) {
+ client->errorValue = *modifiers;
+ return BadValue;
+ }
+ }
+
mod_dev = (IsFloating(dev)) ? dev : GetMaster(dev, MASTER_KEYBOARD);
tempGrab = AllocGrab(NULL);
--
2.51.0
++++++ 0007-glx-validate-dataBytes-against-cmdlen-in-RenderLarge.patch ++++++
>From 2abe4632d793314d3d5f28c19583fb76019f5ce4 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Wed, 26 Aug 2026 17:16:49 +1000
Subject: [PATCH 07/12] glx: validate dataBytes against cmdlen in RenderLarge
first request
__glXDisp_RenderLarge() allocates the large command buffer based on
cmdlen (from hdr->length, the total command size embedded in the
payload), but copies dataBytes (from req->dataBytes, the payload size
of the current sub-request) into it. The existing length check only
validates that the X11 request length is consistent with dataBytes,
not that dataBytes fits within the cmdlen-sized buffer.
A malicious client can set hdr->length to a small value (e.g. 12 bytes)
while sending a large dataBytes (up to ~256KB or more with
BIG-REQUESTS), causing the memcpy to overflow the cmdlen-sized buffer.
Add a check that dataBytes <= cmdlen before the buffer allocation and
copy on the first request.
This vulnerability was discovered by:
Anonymous working with TrendAI Zero Day Initiative
ZDI-CAN-31833
CVE-2026-93517
Signed-off-by: Peter Hutterer <[email protected]>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
glx/glxcmds.c | 3 ++
test/pyxtest/proto/glx.py | 50 +++++++++++++++++++++
test/pyxtest/test_glx.py | 94 +++++++++++++++++++++++++++++++++++++++
3 files changed, 147 insertions(+)
diff --git a/glx/glxcmds.c b/glx/glxcmds.c
index 58ef861f5..39b187fd9 100644
--- a/glx/glxcmds.c
+++ b/glx/glxcmds.c
@@ -2187,6 +2187,9 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
return BadLength;
}
+ if (dataBytes > cmdlen)
+ return BadLength;
+
/*
** Make enough space in the buffer, then copy the entire request.
*/
--
2.51.0
++++++ 0008-present-unlink-notifies-from-window-list-in-present_.patch ++++++
>From 1b6955c3108e6b43433aefe860070708e6f43d1b Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Wed, 26 Aug 2026 17:04:47 +1000
Subject: [PATCH 08/12] 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
Signed-off-by: Peter Hutterer <[email protected]>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
present/present_notify.c | 7 +--
test/pyxtest/proto/x11.py | 90 ++++++++++++++++++++++++++++++++++++
test/pyxtest/test_present.py | 87 +++++++++++++++++++++++++++++++++-
3 files changed, 180 insertions(+), 4 deletions(-)
diff --git a/present/present_notify.c b/present/present_notify.c
index 1f9ff7474..7cb0ad5b2 100644
--- a/present/present_notify.c
+++ b/present/present_notify.c
@@ -30,14 +30,14 @@
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);
}
}
@@ -48,6 +48,7 @@ present_clear_window_notifies(WindowPtr window)
void
present_free_window_notify(present_notify_ptr notify)
{
+ notify->window = NULL;
xorg_list_del(¬ify->window_list);
}
--
2.51.0
++++++ 0009-dix-remove-passive-grabs-referencing-a-device-on-rem.patch ++++++
>From be572634158850fff4e9829cee88db08d30c9743 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Wed, 26 Aug 2026 17:16:59 +1000
Subject: [PATCH 09/12] dix: remove passive grabs referencing a device on
removal
Passive grabs (GrabRec) store raw DeviceIntPtr values for both the
grabbed device and the modifier device without any lifetime management.
When a device is removed via XIRemoveMaster, CloseDevice() frees the
device struct, but leaves dangling pointers in grab->modifierDevice
for any grab that used this device.
Subsequent pointer events trigger CheckPassiveGrab() which dereferences
the dangling modifierDevice pointer for XI grabs (the CORE and XI2 paths
reassign it, but the XI path does not).
This vulnerability was discovered by:
Anonymous working with TrendAI Zero Day Initiative
ZDI-CAN-31832
CVE-2026-93516
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
dix/devices.c | 36 +++++
test/pyxtest/proto/xi.py | 309 +++++++++++++++++++++++++++++++++++++++
test/pyxtest/test_xi.py | 109 ++++++++++++++
3 files changed, 454 insertions(+)
Index: xorg-server-21.1.24/dix/devices.c
===================================================================
--- xorg-server-21.1.24.orig/dix/devices.c
+++ xorg-server-21.1.24/dix/devices.c
@@ -1160,6 +1160,40 @@ UndisplayDevices(void)
screen->DisplayCursor(dev, screen, NullCursor);
}
+static Bool
+GrabReferencesDevice(void *value, XID id, void *cdata)
+{
+ GrabPtr grab = value;
+ DeviceIntPtr dev = cdata;
+
+ return grab->device == dev || grab->modifierDevice == dev;
+}
+
+/**
+ * Remove all passive grabs that reference the given device, either as
+ * the grabbed device or as the modifier device. This must be called
+ * before the device is freed to avoid dangling pointers in GrabRec.
+ */
+static void
+RemovePassiveGrabsForDevice(DeviceIntPtr dev)
+{
+ int i;
+
+ for (i = 0; i < currentMaxClients; i++) {
+ GrabPtr grab;
+
+ if (!clients[i])
+ continue;
+
+ while ((grab = LookupClientResourceComplex(clients[i],
+ X11_RESTYPE_PASSIVEGRAB,
+ GrabReferencesDevice,
+ dev))) {
+ FreeResource(grab->resource, X11_RESTYPE_NONE);
+ }
+ }
+}
+
/**
* Remove a device from the device list, closes it and thus frees all
* resources.
@@ -1199,6 +1233,8 @@ RemoveDevice(DeviceIntPtr dev, BOOL send
flags[dev->id] = XIDeviceDisabled;
}
+ RemovePassiveGrabsForDevice(dev);
+
input_lock();
prev = NULL;
Index: xorg-server-21.1.24/include/resource.h
===================================================================
--- xorg-server-21.1.24.orig/include/resource.h
+++ xorg-server-21.1.24/include/resource.h
@@ -71,6 +71,19 @@ typedef uint32_t RESTYPE;
/* types for Resource routines */
+// prevent namespace clash with Windows
+#define X11_RESTYPE_NONE ((RESTYPE)0)
+#define X11_RESTYPE_WINDOW ((RESTYPE)1|RC_DRAWABLE)
+#define X11_RESTYPE_PIXMAP ((RESTYPE)2|RC_DRAWABLE)
+#define X11_RESTYPE_GC ((RESTYPE)3)
+#define X11_RESTYPE_FONT ((RESTYPE)4)
+#define X11_RESTYPE_CURSOR ((RESTYPE)5)
+#define X11_RESTYPE_COLORMAP ((RESTYPE)6)
+#define X11_RESTYPE_CMAPENTRY ((RESTYPE)7)
+#define X11_RESTYPE_OTHERCLIENT ((RESTYPE)8|RC_NEVERRETAIN)
+#define X11_RESTYPE_PASSIVEGRAB ((RESTYPE)9|RC_NEVERRETAIN)
+#define X11_RESTYPE_LASTPREDEF ((RESTYPE)9)
+
#define RT_WINDOW ((RESTYPE)1|RC_DRAWABLE)
#define RT_PIXMAP ((RESTYPE)2|RC_DRAWABLE)
#define RT_GC ((RESTYPE)3)
++++++ 0010-Xi-add-bounds-check-for-barrier-events-in-input_cons.patch ++++++
>From 1f42cc1f00d9c6d46978ae82dba8a52f4d902369 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Wed, 26 Aug 2026 17:17:12 +1000
Subject: [PATCH 10/12] Xi: add bounds check for barrier events in
input_constrain_cursor
input_constrain_cursor() writes barrier hit and leave events into the
InputEventList buffer without checking how many slots remain.
The buffer is allocated by the DDX at GetMaximumEventsNum() (100) entries
and may contain one raw event already. A client can create more than 100
pointer barriers, pre-arm them as released via XIBarrierReleasePointer,
and then trigger a single pointer motion that crosses all barriers
simultaneously. The leave event loop iterates every hit barrier and
writes one event per barrier, overflowing the 100-slot buffer.
In an ideal world we'd change the InternalEvent* pointer to a struct
that contains allocated size, number of events and the pointer itself
but we're crossing public APIs here and that requires an ABI bump.
So we make do with cutting off the number of barrier events at 64 which
should be low enough to not trigger the issue. However, for the 100+
barrier case this means we only send BarierHit events, not BarrierRelease.
Potentially leaving a client stuck.
We mitigate that problem by simply refusing to create more than 32
barriers per screen (which on its own would also fix the issue, but hey,
'doppelt gemoppelt' as they say).
This vulnerability was discovered by:
Anonymous working with TrendAI Zero Day Initiative
ZDI-CAN-31938
CVE-2026-93519
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
Xi/xibarriers.c | 82 ++++++++++++++++++----------
test/pyxtest/proto/xfixes.py | 99 ++++++++++++++++++++++++++++++++++
test/pyxtest/proto/xi.py | 49 +++++++++++++++++
test/pyxtest/proto/xtest.py | 77 ++++++++++++++++++++++++++
test/pyxtest/test_xi.py | 102 ++++++++++++++++++++++++++++++++++-
5 files changed, 381 insertions(+), 28 deletions(-)
create mode 100644 test/pyxtest/proto/xfixes.py
create mode 100644 test/pyxtest/proto/xtest.py
diff --git a/Xi/xibarriers.c b/Xi/xibarriers.c
index 2d84d3fb7..354d6d783 100644
--- a/Xi/xibarriers.c
+++ b/Xi/xibarriers.c
@@ -416,6 +416,18 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
InternalEvent *barrier_events = events;
DeviceIntPtr master;
+ /* We cannot know how many events are available in *events, but
+ * we know it all DDX very protbably allocated them with
+ * GetMaximumEventsNum() and fill_pointer_events() may have added one.
+ *
+ * Let's cap at a maximum of 64 barrier events which is way more than
+ * we'll need but low enough that we shouldn't OOB on *events.
+ *
+ * Changing the signatures to get some sz_events in here is an ABI change
+ * through miPointerSetPosition so... weeping face.
+ */
+ const int MAX_BARRIER_EVENTS = 64;
+
if (nevents)
*nevents = 0;
@@ -460,7 +472,6 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
if (pbd->barrier_event_id == pbd->release_event_id)
continue;
- ev.type = ET_BarrierHit;
barrier_clamp_to_barrier(nearest, dir, &x, &y);
if (barrier_is_vertical(nearest)) {
@@ -472,19 +483,22 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
current_y = y;
}
- ev.flags = 0;
- ev.event_id = pbd->barrier_event_id;
- ev.barrierid = c->id;
+ if (*nevents < MAX_BARRIER_EVENTS) {
+ ev.type = ET_BarrierHit;
+ ev.flags = 0;
+ ev.event_id = pbd->barrier_event_id;
+ ev.barrierid = c->id;
- ev.dt = new_sequence ? 0 : ms - pbd->last_timestamp;
- ev.window = c->window;
- pbd->last_timestamp = ms;
+ ev.dt = new_sequence ? 0 : ms - pbd->last_timestamp;
+ ev.window = c->window;
- /* root x/y is filled in later */
+ /* root x/y is filled in later */
- barrier_events->barrier_event = ev;
- barrier_events++;
- *nevents += 1;
+ barrier_events->barrier_event = ev;
+ barrier_events++;
+ *nevents += 1;
+ }
+ pbd->last_timestamp = ms;
}
xorg_list_for_each_entry(c, &cs->barriers, entry) {
@@ -503,29 +517,31 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
continue;
pbd->hit = FALSE;
+ pbd->last_timestamp = ms;
+ /* If we've left the hit box, this is the
+ * start of a new event ID. */
+ pbd->barrier_event_id++;
- ev.type = ET_BarrierLeave;
+ if (*nevents < MAX_BARRIER_EVENTS) {
+ ev.type = ET_BarrierLeave;
- if (pbd->barrier_event_id == pbd->release_event_id)
- flags |= XIBarrierPointerReleased;
+ if (pbd->barrier_event_id == pbd->release_event_id)
+ flags |= XIBarrierPointerReleased;
- ev.flags = flags;
- ev.event_id = pbd->barrier_event_id;
- ev.barrierid = c->id;
+ ev.flags = flags;
+ ev.event_id = pbd->barrier_event_id;
+ ev.barrierid = c->id;
- ev.dt = ms - pbd->last_timestamp;
- ev.window = c->window;
- pbd->last_timestamp = ms;
+ ev.dt = ms - pbd->last_timestamp;
+ ev.window = c->window;
- /* root x/y is filled in later */
+ /* root x/y is filled in later */
- barrier_events->barrier_event = ev;
- barrier_events++;
- *nevents += 1;
+ barrier_events->barrier_event = ev;
+ barrier_events++;
+ *nevents += 1;
+ }
- /* If we've left the hit box, this is the
- * start of a new event ID. */
- pbd->barrier_event_id++;
}
out:
@@ -557,8 +573,10 @@ CreatePointerBarrierClient(ClientPtr client,
int size;
int i;
struct PointerBarrierClient *ret;
+ struct PointerBarrierClient *counter;
CARD16 *in_devices;
DeviceIntPtr dev;
+ size_t nbarriers = 0;
size = sizeof(*ret) + sizeof(DeviceIntPtr) * stuff->num_devices;
ret = malloc(size);
@@ -578,6 +596,16 @@ CreatePointerBarrierClient(ClientPtr client,
screen = pWin->drawable.pScreen;
cs = GetBarrierScreen(screen);
+ /* Only allow for a maximum of 32 barriers to be created. This
+ * should be more than enough and prevents issues in
+ * input_constrain_cursor, see MAX_BARRIER_EVENTS in that
+ * function */
+ xorg_list_for_each_entry(counter, &cs->barriers, entry) {
+ nbarriers++;
+ if (nbarriers >= 32)
+ return BadAlloc;
+ }
+
ret->screen = screen;
ret->window = stuff->window;
ret->num_devices = stuff->num_devices;
diff --git a/test/pyxtest/proto/xfixes.py b/test/pyxtest/proto/xfixes.py
new file mode 100644
index 000000000..8c7b022a5
diff --git a/test/pyxtest/proto/xtest.py b/test/pyxtest/proto/xtest.py
new file mode 100644
index 000000000..ef23f8601
--
2.51.0
++++++ 0011-Xi-clean-up-gesture-sprite-traces-in-WindowGone.patch ++++++
>From efcfd8acc754c5ac4b2555ff375dd5101d735b0a Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
Date: Thu, 3 Sep 2026 14:57:31 +1000
Subject: [PATCH 11/12] 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
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
---
Xi/exevents.c | 24 +++-
test/pyxtest/inputtest.py | 295 ++++++++++++++++++++++++++++++++++++++
test/pyxtest/proto/xi.py | 76 ++++++++++
test/pyxtest/test_xi.py | 188 +++++++++++++++++++++++-
4 files changed, 575 insertions(+), 8 deletions(-)
create mode 100644 test/pyxtest/inputtest.py
Index: xorg-server-21.1.24/Xi/exevents.c
===================================================================
--- xorg-server-21.1.24.orig/Xi/exevents.c
+++ xorg-server-21.1.24/Xi/exevents.c
@@ -2871,9 +2871,8 @@ InputClientGone(WindowPtr pWin, XID id)
}
/**
- * 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)
@@ -2884,11 +2883,22 @@ WindowGone(WindowPtr win)
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++) {