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-10-10 14:57:36 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/xwayland (Old) and /work/SRC/openSUSE:Factory/.xwayland.new.3698736 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "xwayland" Sat Oct 10 14:57:36 2026 rev:53 rq:1383338 version:24.1.13 Changes: -------- --- /work/SRC/openSUSE:Factory/xwayland/xwayland.changes 2026-07-17 18:47:08.644522120 +0200 +++ /work/SRC/openSUSE:Factory/.xwayland.new.3698736/xwayland.changes 2026-10-10 14:58:15.721174121 +0200 @@ -1,0 +2,40 @@ +Thu Oct 8 14:38:52 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) +- 0012-glamor-size-tmp_bits-buffer-for-source-coordinate-ra.patch + Glamor CopyArea Heap Buffer Overflow + (bsc#1281240, CVE-2026-93522, ZDI-CAN-32361) + +------------------------------------------------------------------- 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 0012-glamor-size-tmp_bits-buffer-for-source-coordinate-ra.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: (bsc#1281244 CVE-2026-93536, ZDI-CAN-32753) - 0012-glamor-size-tmp_bits-buffer-for-source-coordinate-ra.patch Glamor CopyArea Heap Buffer Overflow ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ xwayland.spec ++++++ --- /var/tmp/diff_new_pack.oGTcsC/_old 2026-10-10 14:58:16.621211776 +0200 +++ /var/tmp/diff_new_pack.oGTcsC/_new 2026-10-10 14:58:16.622211818 +0200 @@ -38,6 +38,19 @@ Source2: xwayland.keyring Patch3: U_xwayland_Dont_run_key_behaviors_and_actions.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 +Patch1281240: 0012-glamor-size-tmp_bits-buffer-for-source-coordinate-ra.patch + BuildRequires: meson BuildRequires: ninja BuildRequires: pkgconfig ++++++ 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: xwayland-24.1.13/dix/devices.c =================================================================== --- xwayland-24.1.13.orig/dix/devices.c +++ xwayland-24.1.13/dix/devices.c @@ -1197,6 +1197,40 @@ CloseOneDevice(const DeviceIntPtr dev, D return BadMatch; } +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. @@ -1238,6 +1272,8 @@ RemoveDevice(DeviceIntPtr dev, BOOL send flag = IsMaster(dev) ? XIMasterRemoved : XISlaveRemoved; + RemovePassiveGrabsForDevice(dev); + input_lock(); if ((ret = CloseOneDevice(dev, &inputInfo.devices)) == Success || Index: xwayland-24.1.13/include/resource.h =================================================================== --- xwayland-24.1.13.orig/include/resource.h +++ xwayland-24.1.13/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++) { ++++++ 0012-glamor-size-tmp_bits-buffer-for-source-coordinate-ra.patch ++++++ >From ad26c26bf795e6464f74c8ef5bb1d41403d877ab Mon Sep 17 00:00:00 2001 From: Peter Hutterer <[email protected]> Date: Wed, 26 Aug 2026 17:17:21 +1000 Subject: [PATCH 12/12] glamor: size tmp_bits buffer for source coordinate range in upload_boxes glamor_upload_boxes() allocates the tmp_bits buffer (used for 24-bit to 32-bit depth conversion) based on the destination pixmap height, but indexes it using source coordinates (y1 - dy_dst + dy_src). When the source is taller than the destination, the source-relative offset exceeds the destination height, causing writes past the buffer end. Size the buffer to account for the source coordinate mapping: byte_stride * (pixmap->drawable.height - dy_dst + dy_src). This ensures the buffer covers the full range of source rows that will be accessed during the upload. This vulnerability was discovered by: Anonymous working with TrendAI Zero Day Initiative ZDI-CAN-32361 CVE-2026-93522 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> --- glamor/glamor_transfer.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) Index: xwayland-24.1.13/glamor/glamor_transfer.c =================================================================== --- xwayland-24.1.13.orig/glamor/glamor_transfer.c +++ xwayland-24.1.13/glamor/glamor_transfer.c @@ -41,8 +41,14 @@ glamor_upload_boxes(DrawablePtr drawable int bytes_per_pixel = PICT_FORMAT_BPP(f->render_format) >> 3; char *tmp_bits = NULL; - if (glamor_drawable_effective_depth(drawable) == 24 && pixmap->drawable.depth == 32) - tmp_bits = xnfalloc(byte_stride * pixmap->drawable.height); + if (glamor_drawable_effective_depth(drawable) == 24 && pixmap->drawable.depth == 32) { + int tmp_height = pixmap->drawable.height - dy_dst + dy_src; + if (tmp_height > 0) { + if (byte_stride > 0 && tmp_height > INT_MAX / byte_stride) + return; + tmp_bits = XNFalloc(byte_stride * tmp_height); + } + } glamor_make_current(glamor_priv);
