--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bookworm d-i
X-Debbugs-Cc: [email protected], [email protected],
[email protected], [email protected], [email protected], [email protected],
[email protected], [email protected]
Control: affects -1 + src:xorg-server
User: [email protected]
Usertags: pu
Hi
Same as for #1134330: xorg-server is affected by some CVEs recently disclosed
but we
discussed in the team that they do not warrant a DSA, so proposing
those to be fixed via the next trixie point release:
* xkb: fix buffer re-use in _XkbSetCompatMap (CVE-2026-33999)
* xkb: Fix bounds check in _CheckSetGeom() (CVE-2026-34000)
* miext/sync: Fix use-after-free in miSyncTriggerFence() (CVE-2026-34001)
* xkb: Fix out-of-bounds read in CheckModifierMap() (CVE-2026-34002)
* xkb: Add additional bound checking in CheckKeyTypes() (CVE-2026-34003)
* xkb: Add more _XkbCheckRequestBounds() (CVE-2026-34003)
They are already fixed in unstable and exposed there, afaik there are
no regressions reported. Currently debusine tests are still running,
which I'm using to augment confidence:
https://debusine.debian.net/debian/developers/work-request/611326/
Regards,
Salvatore
diff -u xorg-server-21.1.7/debian/changelog xorg-server-21.1.7/debian/changelog
--- xorg-server-21.1.7/debian/changelog
+++ xorg-server-21.1.7/debian/changelog
@@ -1,3 +1,15 @@
+xorg-server (2:21.1.7-3+deb12u12) bookworm; urgency=medium
+
+ * Non-maintainer upload.
+ * xkb: fix buffer re-use in _XkbSetCompatMap (CVE-2026-33999)
+ * xkb: Fix bounds check in _CheckSetGeom() (CVE-2026-34000)
+ * miext/sync: Fix use-after-free in miSyncTriggerFence() (CVE-2026-34001)
+ * xkb: Fix out-of-bounds read in CheckModifierMap() (CVE-2026-34002)
+ * xkb: Add additional bound checking in CheckKeyTypes() (CVE-2026-34003)
+ * xkb: Add more _XkbCheckRequestBounds() (CVE-2026-34003)
+
+ -- Salvatore Bonaccorso <[email protected]> Sat, 11 Apr 2026 02:48:00 +0200
+
xorg-server (2:21.1.7-3+deb12u11) bookworm-security; urgency=high
* Non-maintainer upload by the Security Team.
diff -u xorg-server-21.1.7/debian/patches/series
xorg-server-21.1.7/debian/patches/series
--- xorg-server-21.1.7/debian/patches/series
+++ xorg-server-21.1.7/debian/patches/series
@@ -49,3 +49,9 @@
CVE-2025-62230/0001-xkb-Make-the-RT_XKBCLIENT-resource-private.patch
CVE-2025-62230/0002-xkb-Free-the-XKB-resource-when-freeing-XkbInterest.patch
CVE-2025-62231/0001-xkb-Prevent-overflow-in-XkbSetCompatMap.patch
+CVE-2026-33999/0001-xkb-fix-buffer-re-use-in-_XkbSetCompatMap.patch
+CVE-2026-34000/0001-xkb-Fix-bounds-check-in-_CheckSetGeom.patch
+CVE-2026-34001/0001-miext-sync-Fix-use-after-free-in-miSyncTriggerFence.patch
+CVE-2026-34002/0001-xkb-Fix-out-of-bounds-read-in-CheckModifierMap.patch
+CVE-2026-34003/0001-xkb-Add-additional-bound-checking-in-CheckKeyTypes.patch
+CVE-2026-34003/0002-xkb-Add-more-_XkbCheckRequestBounds.patch
only in patch2:
unchanged:
---
xorg-server-21.1.7.orig/debian/patches/CVE-2026-33999/0001-xkb-fix-buffer-re-use-in-_XkbSetCompatMap.patch
+++
xorg-server-21.1.7/debian/patches/CVE-2026-33999/0001-xkb-fix-buffer-re-use-in-_XkbSetCompatMap.patch
@@ -0,0 +1,44 @@
+From d4a18e229af79917d09b2a24f38df95374c536e2 Mon Sep 17 00:00:00 2001
+From: Peter Harris <[email protected]>
+Date: Thu, 15 Jan 2026 15:54:09 -0500
+Subject: [PATCH xserver] xkb: fix buffer re-use in _XkbSetCompatMap
+
+If the "compat" buffer has previously been truncated, there will be
+unused space in the buffer. The code uses this space, but does not
+update the number of valid entries in the buffer.
+
+In the best case, this leads to the new compat entries being ignored. In the
+worst case, if there are any "skipped" compat entries, the number of
+valid entries will be corrupted, potentially leading to a buffer read
+overrun when processing a future request.
+
+Set the number of used "compat" entries when re-using previously
+allocated space in the buffer.
+
+CVE-2026-33999, ZDI-CAN-28593
+
+This vulnerability was discovered by:
+Jan-Niklas Sohn working with TrendAI Zero Day Initiative
+
+Signed-off-by: Peter Harris <[email protected]>
+Acked-by: Olivier Fourdan <[email protected]>
+---
+ xkb/xkb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/xkb/xkb.c b/xkb/xkb.c
+index c4ed3fb1e..d31c64113 100644
+--- a/xkb/xkb.c
++++ b/xkb/xkb.c
+@@ -3008,7 +3008,7 @@ _XkbSetCompatMap(ClientPtr client, DeviceIntPtr dev,
+ return BadAlloc;
+ }
+ }
+- else if (req->truncateSI) {
++ else if (req->truncateSI || req->firstSI + req->nSI > compat->num_si)
{
+ compat->num_si = req->firstSI + req->nSI;
+ }
+ sym = &compat->sym_interpret[req->firstSI];
+--
+2.53.0
+
only in patch2:
unchanged:
---
xorg-server-21.1.7.orig/debian/patches/CVE-2026-34000/0001-xkb-Fix-bounds-check-in-_CheckSetGeom.patch
+++
xorg-server-21.1.7/debian/patches/CVE-2026-34000/0001-xkb-Fix-bounds-check-in-_CheckSetGeom.patch
@@ -0,0 +1,67 @@
+From b81454f29d7e408d682ef1371ae1df63871cd7ed Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <[email protected]>
+Date: Wed, 18 Feb 2026 16:03:11 +0100
+Subject: [PATCH xserver] xkb: Fix bounds check in _CheckSetGeom()
+
+As reported by valgrind:
+
+ == Conditional jump or move depends on uninitialised value(s)
+ == at 0x5CBE66: SrvXkbAddGeomKeyAlias (XKBGAlloc.c:585)
+ == by 0x5AC7D5: _CheckSetGeom (xkb.c:5607)
+ == by 0x5AC952: _XkbSetGeometry (xkb.c:5643)
+ == by 0x5ACB58: ProcXkbSetGeometry (xkb.c:5684)
+ == by 0x5B0DAC: ProcXkbDispatch (xkb.c:7070)
+ == by 0x4A28C5: Dispatch (dispatch.c:553)
+ == by 0x4B0B24: dix_main (main.c:274)
+ == by 0x42915E: main (stubmain.c:34)
+ == Uninitialised value was created by a heap allocation
+ == at 0x4840B26: malloc (vg_replace_malloc.c:447)
+ == by 0x5E13B0: AllocateInputBuffer (io.c:981)
+ == by 0x5E05CD: InsertFakeRequest (io.c:516)
+ == by 0x4AA860: NextAvailableClient (dispatch.c:3629)
+ == by 0x5DE0D7: AllocNewConnection (connection.c:628)
+ == by 0x5DE2C6: EstablishNewConnections (connection.c:692)
+ == by 0x5DE600: HandleNotifyFd (connection.c:809)
+ == by 0x5E2598: ospoll_wait (ospoll.c:660)
+ == by 0x5DA00C: WaitForSomething (WaitFor.c:208)
+ == by 0x4A26E5: Dispatch (dispatch.c:493)
+ == by 0x4B0B24: dix_main (main.c:274)
+ == by 0x42915E: main (stubmain.c:34)
+
+Each key alias entry contains two key names (the alias and the real key
+name), each of size XkbKeyNameLength.
+
+The current bounds check only validates the first name, allowing
+XkbAddGeomKeyAlias to potentially read uninitialized memory when
+accessing the second name at &wire[XkbKeyNameLength].
+
+To fix this, change the value to check to use 2 * XkbKeyNameLength to
+validate the bounds.
+
+CVE-2026-34000, ZDI-CAN-28679
+
+This vulnerability was discovered by:
+Jan-Niklas Sohn working with TrendAI Zero Day Initiative
+
+Signed-off-by: Olivier Fourdan <[email protected]>
+Acked-by: Peter Hutterer <[email protected]>
+---
+ xkb/xkb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/xkb/xkb.c b/xkb/xkb.c
+index d31c64113..d2b15b485 100644
+--- a/xkb/xkb.c
++++ b/xkb/xkb.c
+@@ -5613,7 +5613,7 @@ _CheckSetGeom(XkbGeometryPtr geom, xkbSetGeometryReq *
req, ClientPtr client)
+ }
+
+ for (i = 0; i < req->nKeyAliases; i++) {
+- if (!_XkbCheckRequestBounds(client, req, wire, wire +
XkbKeyNameLength))
++ if (!_XkbCheckRequestBounds(client, req, wire, wire + 2 *
XkbKeyNameLength))
+ return BadLength;
+
+ if (XkbAddGeomKeyAlias(geom, &wire[XkbKeyNameLength], wire) == NULL)
+--
+2.53.0
+
only in patch2:
unchanged:
---
xorg-server-21.1.7.orig/debian/patches/CVE-2026-34001/0001-miext-sync-Fix-use-after-free-in-miSyncTriggerFence.patch
+++
xorg-server-21.1.7/debian/patches/CVE-2026-34001/0001-miext-sync-Fix-use-after-free-in-miSyncTriggerFence.patch
@@ -0,0 +1,100 @@
+From e684fb34a858191769ff1c064bd4ab40f6ff7189 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <[email protected]>
+Date: Wed, 18 Feb 2026 16:23:23 +0100
+Subject: [PATCH xserver] miext/sync: Fix use-after-free in
+ miSyncTriggerFence()
+
+As reported by valgrind:
+
+ == Invalid read of size 8
+ == at 0x568C14: miSyncTriggerFence (misync.c:140)
+ == by 0x540688: ProcSyncTriggerFence (sync.c:1957)
+ == by 0x540CCC: ProcSyncDispatch (sync.c:2152)
+ == by 0x4A28C5: Dispatch (dispatch.c:553)
+ == by 0x4B0B24: dix_main (main.c:274)
+ == by 0x42915E: main (stubmain.c:34)
+ == Address 0x17e35488 is 8 bytes inside a block of size 16 free'd
+ == at 0x4843E43: free (vg_replace_malloc.c:990)
+ == by 0x53D683: SyncDeleteTriggerFromSyncObject (sync.c:169)
+ == by 0x53F14D: FreeAwait (sync.c:1208)
+ == by 0x4DFB06: doFreeResource (resource.c:888)
+ == by 0x4DFC59: FreeResource (resource.c:918)
+ == by 0x53E349: SyncAwaitTriggerFired (sync.c:701)
+ == by 0x568C52: miSyncTriggerFence (misync.c:142)
+ == by 0x540688: ProcSyncTriggerFence (sync.c:1957)
+ == by 0x540CCC: ProcSyncDispatch (sync.c:2152)
+ == by 0x4A28C5: Dispatch (dispatch.c:553)
+ == by 0x4B0B24: dix_main (main.c:274)
+ == by 0x42915E: main (stubmain.c:34)
+ == Block was alloc'd at
+ == at 0x4840B26: malloc (vg_replace_malloc.c:447)
+ == by 0x5E50E1: XNFalloc (utils.c:1129)
+ == by 0x53D772: SyncAddTriggerToSyncObject (sync.c:206)
+ == by 0x53DCA8: SyncInitTrigger (sync.c:414)
+ == by 0x5409C7: ProcSyncAwaitFence (sync.c:2089)
+ == by 0x540D04: ProcSyncDispatch (sync.c:2160)
+ == by 0x4A28C5: Dispatch (dispatch.c:553)
+ == by 0x4B0B24: dix_main (main.c:274)
+ == by 0x42915E: main (stubmain.c:34)
+
+When walking the list of fences to trigger, miSyncTriggerFence() may
+call TriggerFence() for the current trigger, which end up calling the
+function SyncAwaitTriggerFired().
+
+SyncAwaitTriggerFired() frees the entire await resource, which removes
+all triggers from that await - including pNext which may be another
+trigger from the same await attached to the same fence.
+
+On the next iteration, ptl = pNext points to freed memory...
+
+To avoid the issue, we need to restart the iteration from the beginning
+of the list each time a trigger fires, since the callback can modify the
+list.
+
+CVE-2026-34001, ZDI-CAN-28706
+
+This vulnerability was discovered by:
+Jan-Niklas Sohn working with TrendAI Zero Day Initiative
+
+Signed-off-by: Olivier Fourdan <[email protected]>
+Acked-by: Peter Hutterer <[email protected]>
+---
+ miext/sync/misync.c | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/miext/sync/misync.c b/miext/sync/misync.c
+index 0931803f6..9a6fbbd4a 100644
+--- a/miext/sync/misync.c
++++ b/miext/sync/misync.c
+@@ -131,16 +131,22 @@ miSyncDestroyFence(SyncFence * pFence)
+ void
+ miSyncTriggerFence(SyncFence * pFence)
+ {
+- SyncTriggerList *ptl, *pNext;
++ SyncTriggerList *ptl;
++ Bool triggered;
+
+ pFence->funcs.SetTriggered(pFence);
+
+ /* run through triggers to see if any fired */
+- for (ptl = pFence->sync.pTriglist; ptl; ptl = pNext) {
+- pNext = ptl->next;
+- if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, 0))
+- (*ptl->pTrigger->TriggerFired) (ptl->pTrigger);
+- }
++ do {
++ triggered = FALSE;
++ for (ptl = pFence->sync.pTriglist; ptl; ptl = ptl->next) {
++ if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, 0)) {
++ (*ptl->pTrigger->TriggerFired) (ptl->pTrigger);
++ triggered = TRUE;
++ break;
++ }
++ }
++ } while (triggered);
+ }
+
+ SyncScreenFuncsPtr
+--
+2.53.0
+
only in patch2:
unchanged:
---
xorg-server-21.1.7.orig/debian/patches/CVE-2026-34002/0001-xkb-Fix-out-of-bounds-read-in-CheckModifierMap.patch
+++
xorg-server-21.1.7/debian/patches/CVE-2026-34002/0001-xkb-Fix-out-of-bounds-read-in-CheckModifierMap.patch
@@ -0,0 +1,88 @@
+From 822657b357048ddedfb4e8313c7f1a69295240c5 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <[email protected]>
+Date: Wed, 18 Feb 2026 17:02:09 +0100
+Subject: [PATCH xserver] xkb: Fix out-of-bounds read in CheckModifierMap()
+
+As reported by valgrind:
+
+ == Conditional jump or move depends on uninitialised value(s)
+ == at 0x547E5B: CheckModifierMap (xkb.c:1972)
+ == by 0x54A086: _XkbSetMapChecks (xkb.c:2574)
+ == by 0x54A845: ProcXkbSetMap (xkb.c:2741)
+ == by 0x556EF4: ProcXkbDispatch (xkb.c:7048)
+ == by 0x454A8C: Dispatch (dispatch.c:553)
+ == by 0x462CEB: dix_main (main.c:274)
+ == by 0x405EA7: main (stubmain.c:34)
+ == Uninitialised value was created by a heap allocation
+ == at 0x4840B26: malloc (vg_replace_malloc.c:447)
+ == by 0x592D5A: AllocateInputBuffer (io.c:981)
+ == by 0x591F77: InsertFakeRequest (io.c:516)
+ == by 0x45CA27: NextAvailableClient (dispatch.c:3629)
+ == by 0x58FA81: AllocNewConnection (connection.c:628)
+ == by 0x58FC70: EstablishNewConnections (connection.c:692)
+ == by 0x58FFAA: HandleNotifyFd (connection.c:809)
+ == by 0x593F42: ospoll_wait (ospoll.c:660)
+ == by 0x58B9B6: WaitForSomething (WaitFor.c:208)
+ == by 0x4548AC: Dispatch (dispatch.c:493)
+ == by 0x462CEB: dix_main (main.c:274)
+ == by 0x405EA7: main (stubmain.c:34)
+
+The issue is that the loop in CheckModifierMap() reads from wire without
+verifying that the data is within the request bounds.
+
+The req->totalModMapKeys value could exceed the actual data provided,
+causing reads of uninitialized memory.
+
+To fix that issue, we add a bounds check using _XkbCheckRequestBounds,
+but for that, we need to also pass a ClientPtr parameter, which is not
+a problem since CheckModifierMap() is a private, static function.
+
+CVE-2026-34002, ZDI-CAN-28737
+
+This vulnerability was discovered by:
+Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
+
+Signed-off-by: Olivier Fourdan <[email protected]>
+Acked-by: Peter Hutterer <[email protected]>
+---
+ xkb/xkb.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/xkb/xkb.c b/xkb/xkb.c
+index d2b15b485..b03d6a264 100644
+--- a/xkb/xkb.c
++++ b/xkb/xkb.c
+@@ -1944,8 +1944,8 @@ CheckKeyExplicit(XkbDescPtr xkb,
+ }
+
+ static int
+-CheckModifierMap(XkbDescPtr xkb, xkbSetMapReq * req, CARD8 **wireRtrn,
+- int *errRtrn)
++CheckModifierMap(ClientPtr client, XkbDescPtr xkb, xkbSetMapReq * req,
++ CARD8 **wireRtrn, int *errRtrn)
+ {
+ register CARD8 *wire = *wireRtrn;
+ CARD8 *start;
+@@ -1969,6 +1969,10 @@ CheckModifierMap(XkbDescPtr xkb, xkbSetMapReq * req,
CARD8 **wireRtrn,
+ }
+ start = wire;
+ for (i = 0; i < req->totalModMapKeys; i++, wire += 2) {
++ if (!_XkbCheckRequestBounds(client, req, wire, wire + 2)) {
++ *errRtrn = _XkbErrCode3(0x64, req->totalModMapKeys, i);
++ return 0;
++ }
+ if ((wire[0] < first) || (wire[0] > last)) {
+ *errRtrn = _XkbErrCode4(0x63, first, last, wire[0]);
+ return 0;
+@@ -2571,7 +2575,7 @@ _XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev,
xkbSetMapReq * req,
+ return BadValue;
+ }
+ if ((req->present & XkbModifierMapMask) &&
+- (!CheckModifierMap(xkb, req, (CARD8 **) &values, &error))) {
++ (!CheckModifierMap(client, xkb, req, (CARD8 **) &values, &error))) {
+ client->errorValue = error;
+ return BadValue;
+ }
+--
+2.53.0
+
only in patch2:
unchanged:
---
xorg-server-21.1.7.orig/debian/patches/CVE-2026-34003/0001-xkb-Add-additional-bound-checking-in-CheckKeyTypes.patch
+++
xorg-server-21.1.7/debian/patches/CVE-2026-34003/0001-xkb-Add-additional-bound-checking-in-CheckKeyTypes.patch
@@ -0,0 +1,109 @@
+From d41409dfc193d1a2ca84f19ad59b2b84de68c3e0 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <[email protected]>
+Date: Mon, 23 Feb 2026 15:52:49 +0100
+Subject: [PATCH xserver 1/2] xkb: Add additional bound checking in
+ CheckKeyTypes()
+
+The function CheckKeyTypes() will loop over the client's request but
+won't perform any additional bound checking to ensure that the data
+read remains within the request bounds.
+
+As a result, a specifically crafted request may cause CheckKeyTypes() to
+read past the request data, as reported by valgrind:
+
+ == Invalid read of size 2
+ == at 0x5A3D1D: CheckKeyTypes (xkb.c:1694)
+ == by 0x5A6A9C: _XkbSetMapChecks (xkb.c:2515)
+ == by 0x5A759E: ProcXkbSetMap (xkb.c:2736)
+ == by 0x5BF832: SProcXkbSetMap (xkbSwap.c:245)
+ == by 0x5C05ED: SProcXkbDispatch (xkbSwap.c:501)
+ == by 0x4A20DF: Dispatch (dispatch.c:551)
+ == by 0x4B03B4: dix_main (main.c:277)
+ == by 0x428941: main (stubmain.c:34)
+ == Address is 30 bytes after a block of size 28,672 in arena "client"
+ ==
+ == Invalid read of size 2
+ == at 0x5A3AB6: CheckKeyTypes (xkb.c:1669)
+ == by 0x5A6A9C: _XkbSetMapChecks (xkb.c:2515)
+ == by 0x5A759E: ProcXkbSetMap (xkb.c:2736)
+ == by 0x5BF832: SProcXkbSetMap (xkbSwap.c:245)
+ == by 0x5C05ED: SProcXkbDispatch (xkbSwap.c:501)
+ == by 0x4A20DF: Dispatch (dispatch.c:551)
+ == by 0x4B03B4: dix_main (main.c:277)
+ == by 0x428941: main (stubmain.c:34)
+ == Address is 2 bytes after a block of size 28,672 alloc'd
+ == at 0x4848897: realloc (vg_replace_malloc.c:1804)
+ == by 0x5E357A: ReadRequestFromClient (io.c:336)
+ == by 0x4A1FAB: Dispatch (dispatch.c:519)
+ == by 0x4B03B4: dix_main (main.c:277)
+ == by 0x428941: main (stubmain.c:34)
+ ==
+ == Invalid write of size 2
+ == at 0x5A3AD7: CheckKeyTypes (xkb.c:1669)
+ == by 0x5A6A9C: _XkbSetMapChecks (xkb.c:2515)
+ == by 0x5A759E: ProcXkbSetMap (xkb.c:2736)
+ == by 0x5BF832: SProcXkbSetMap (xkbSwap.c:245)
+ == by 0x5C05ED: SProcXkbDispatch (xkbSwap.c:501)
+ == by 0x4A20DF: Dispatch (dispatch.c:551)
+ == by 0x4B03B4: dix_main (main.c:277)
+ == by 0x428941: main (stubmain.c:34)
+ == Address is 2 bytes after a block of size 28,672 alloc'd
+ == at 0x4848897: realloc (vg_replace_malloc.c:1804)
+ == by 0x5E357A: ReadRequestFromClient (io.c:336)
+ == by 0x4A1FAB: Dispatch (dispatch.c:519)
+ == by 0x4B03B4: dix_main (main.c:277)
+ == by 0x428941: main (stubmain.c:34)
+ ==
+
+To avoid that issue, add additional bounds checking within the loops by
+calling _XkbCheckRequestBounds() and report an error if we are to read
+past the client's request.
+
+CVE-2026-34003, ZDI-CAN-28736
+
+This vulnerability was discovered by:
+Jan-Niklas Sohn working with TrendAI Zero Day Initiative
+
+Signed-off-by: Olivier Fourdan <[email protected]>
+Acked-by: Peter Hutterer <[email protected]>
+---
+ xkb/xkb.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/xkb/xkb.c b/xkb/xkb.c
+index b03d6a264..a90845230 100644
+--- a/xkb/xkb.c
++++ b/xkb/xkb.c
+@@ -1643,6 +1643,10 @@ CheckKeyTypes(ClientPtr client,
+ for (i = 0; i < req->nTypes; i++) {
+ unsigned width;
+
++ if (!_XkbCheckRequestBounds(client, req, wire, wire + 1)) {
++ *nMapsRtrn = _XkbErrCode3(0x0b, req->nTypes, i);
++ return 0;
++ }
+ if (client->swapped && doswap) {
+ swaps(&wire->virtualMods);
+ }
+@@ -1668,7 +1672,18 @@ CheckKeyTypes(ClientPtr client,
+ xkbModsWireDesc *preWire;
+
+ mapWire = (xkbKTSetMapEntryWireDesc *) &wire[1];
++ if (!_XkbCheckRequestBounds(client, req, mapWire,
++ &mapWire[wire->nMapEntries])) {
++ *nMapsRtrn = _XkbErrCode3(0x0c, i, wire->nMapEntries);
++ return 0;
++ }
+ preWire = (xkbModsWireDesc *) &mapWire[wire->nMapEntries];
++ if (wire->preserve &&
++ !_XkbCheckRequestBounds(client, req, preWire,
++ &preWire[wire->nMapEntries])) {
++ *nMapsRtrn = _XkbErrCode3(0x0d, i, wire->nMapEntries);
++ return 0;
++ }
+ for (n = 0; n < wire->nMapEntries; n++) {
+ if (client->swapped && doswap) {
+ swaps(&mapWire[n].virtualMods);
+--
+2.53.0
+
only in patch2:
unchanged:
---
xorg-server-21.1.7.orig/debian/patches/CVE-2026-34003/0002-xkb-Add-more-_XkbCheckRequestBounds.patch
+++
xorg-server-21.1.7/debian/patches/CVE-2026-34003/0002-xkb-Add-more-_XkbCheckRequestBounds.patch
@@ -0,0 +1,218 @@
+From a44b3d0bc1b80beeac50f5b52fb3f4cc07e77f64 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <[email protected]>
+Date: Mon, 2 Mar 2026 14:09:57 +0100
+Subject: [PATCH xserver 2/2] xkb: Add more _XkbCheckRequestBounds()
+
+Similar to the recent fixes, add more _XkbCheckRequestBounds() to the
+functions that loop over the request data, i.e.:
+
+ * CheckKeySyms()
+ * CheckKeyActions()
+ * CheckKeyBehaviors()
+ * CheckVirtualMods()
+ * CheckKeyExplicit()
+ * CheckVirtualModMap()
+ * _XkbSetMapChecks()
+
+All these are static functions so we can add the client to the parameters
+without breaking any API.
+
+See also:
+CVE-2026-34003, ZDI-CAN-28736, CVE-2026-34002, ZDI-CAN-28737
+
+v2: Check for "nSyms != 0" in CheckKeySyms() to avoid false positives.
+
+Signed-off-by: Olivier Fourdan <[email protected]>
+Acked-by: Peter Hutterer <[email protected]>
+---
+ xkb/xkb.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 55 insertions(+), 14 deletions(-)
+
+diff --git a/xkb/xkb.c b/xkb/xkb.c
+index a90845230..652996946 100644
+--- a/xkb/xkb.c
++++ b/xkb/xkb.c
+@@ -1756,6 +1756,11 @@ CheckKeySyms(ClientPtr client,
+ KeySym *pSyms;
+ register unsigned nG;
+
++ /* Check we received enough data to read the next xkbSymMapWireDesc */
++ if (!_XkbCheckRequestBounds(client, req, wire, wire + 1)) {
++ *errorRtrn = _XkbErrCode3(0x18, i + req->firstKeySym, i);
++ return 0;
++ }
+ if (client->swapped && doswap) {
+ swaps(&wire->nSyms);
+ }
+@@ -1794,6 +1799,12 @@ CheckKeySyms(ClientPtr client,
+ return 0;
+ }
+ pSyms = (KeySym *) &wire[1];
++ if (wire->nSyms != 0) {
++ if (!_XkbCheckRequestBounds(client, req, pSyms,
&pSyms[wire->nSyms])) {
++ *errorRtrn = _XkbErrCode3(0x19, i + req->firstKeySym,
wire->nSyms);
++ return 0;
++ }
++ }
+ wire = (xkbSymMapWireDesc *) &pSyms[wire->nSyms];
+ }
+
+@@ -1817,11 +1828,12 @@ CheckKeySyms(ClientPtr client,
+ }
+
+ static int
+-CheckKeyActions(XkbDescPtr xkb,
+- xkbSetMapReq * req,
+- int nTypes,
+- CARD8 *mapWidths,
+- CARD16 *symsPerKey, CARD8 **wireRtrn, int *nActsRtrn)
++CheckKeyActions(ClientPtr client,
++ XkbDescPtr xkb,
++ xkbSetMapReq * req,
++ int nTypes,
++ CARD8 *mapWidths,
++ CARD16 *symsPerKey, CARD8 **wireRtrn, int *nActsRtrn)
+ {
+ int nActs;
+ CARD8 *wire = *wireRtrn;
+@@ -1832,6 +1844,11 @@ CheckKeyActions(XkbDescPtr xkb,
+ CHK_REQ_KEY_RANGE2(0x21, req->firstKeyAct, req->nKeyActs, req,
(*nActsRtrn),
+ 0);
+ for (nActs = i = 0; i < req->nKeyActs; i++) {
++ /* Check we received enough data to read the next byte on the wire */
++ if (!_XkbCheckRequestBounds(client, req, wire, wire + 1)) {
++ *nActsRtrn = _XkbErrCode3(0x24, i + req->firstKeyAct, i);
++ return 0;
++ }
+ if (wire[0] != 0) {
+ if (wire[0] == symsPerKey[i + req->firstKeyAct])
+ nActs += wire[0];
+@@ -1850,7 +1867,8 @@ CheckKeyActions(XkbDescPtr xkb,
+ }
+
+ static int
+-CheckKeyBehaviors(XkbDescPtr xkb,
++CheckKeyBehaviors(ClientPtr client,
++ XkbDescPtr xkb,
+ xkbSetMapReq * req,
+ xkbBehaviorWireDesc ** wireRtrn, int *errorRtrn)
+ {
+@@ -1876,6 +1894,11 @@ CheckKeyBehaviors(XkbDescPtr xkb,
+ }
+
+ for (i = 0; i < req->totalKeyBehaviors; i++, wire++) {
++ /* Check we received enough data to read the next behavior */
++ if (!_XkbCheckRequestBounds(client, req, wire, wire + 1)) {
++ *errorRtrn = _XkbErrCode3(0x36, first, i);
++ return 0;
++ }
+ if ((wire->key < first) || (wire->key > last)) {
+ *errorRtrn = _XkbErrCode4(0x33, first, last, wire->key);
+ return 0;
+@@ -1901,7 +1924,8 @@ CheckKeyBehaviors(XkbDescPtr xkb,
+ }
+
+ static int
+-CheckVirtualMods(XkbDescRec * xkb,
++CheckVirtualMods(ClientPtr client,
++ XkbDescRec * xkb,
+ xkbSetMapReq * req, CARD8 **wireRtrn, int *errorRtrn)
+ {
+ register CARD8 *wire = *wireRtrn;
+@@ -1913,12 +1937,18 @@ CheckVirtualMods(XkbDescRec * xkb,
+ if (req->virtualMods & bit)
+ nMods++;
+ }
++ /* Check we received enough data for the number of virtual mods expected
*/
++ if (!_XkbCheckRequestBounds(client, req, wire, wire +
XkbPaddedSize(nMods))) {
++ *errorRtrn = _XkbErrCode3(0x37, nMods, i);
++ return 0;
++ }
+ *wireRtrn = (wire + XkbPaddedSize(nMods));
+ return 1;
+ }
+
+ static int
+-CheckKeyExplicit(XkbDescPtr xkb,
++CheckKeyExplicit(ClientPtr client,
++ XkbDescPtr xkb,
+ xkbSetMapReq * req, CARD8 **wireRtrn, int *errorRtrn)
+ {
+ register CARD8 *wire = *wireRtrn;
+@@ -1944,6 +1974,11 @@ CheckKeyExplicit(XkbDescPtr xkb,
+ }
+ start = wire;
+ for (i = 0; i < req->totalKeyExplicit; i++, wire += 2) {
++ /* Check we received enough data to read the next two bytes */
++ if (!_XkbCheckRequestBounds(client, req, wire, wire + 2)) {
++ *errorRtrn = _XkbErrCode4(0x54, first, last, i);
++ return 0;
++ }
+ if ((wire[0] < first) || (wire[0] > last)) {
+ *errorRtrn = _XkbErrCode4(0x53, first, last, wire[0]);
+ return 0;
+@@ -1999,7 +2034,8 @@ CheckModifierMap(ClientPtr client, XkbDescPtr xkb,
xkbSetMapReq * req,
+ }
+
+ static int
+-CheckVirtualModMap(XkbDescPtr xkb,
++CheckVirtualModMap(ClientPtr client,
++ XkbDescPtr xkb,
+ xkbSetMapReq * req,
+ xkbVModMapWireDesc ** wireRtrn, int *errRtrn)
+ {
+@@ -2023,6 +2059,11 @@ CheckVirtualModMap(XkbDescPtr xkb,
+ return 0;
+ }
+ for (i = 0; i < req->totalVModMapKeys; i++, wire++) {
++ /* Check we received enough data to read the next virtual mod map key
*/
++ if (!_XkbCheckRequestBounds(client, req, wire, wire + 1)) {
++ *errRtrn = _XkbErrCode3(0x74, first, i);
++ return 0;
++ }
+ if ((wire->key < first) || (wire->key > last)) {
+ *errRtrn = _XkbErrCode4(0x73, first, last, wire->key);
+ return 0;
+@@ -2566,7 +2607,7 @@ _XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev,
xkbSetMapReq * req,
+ }
+
+ if ((req->present & XkbKeyActionsMask) &&
+- (!CheckKeyActions(xkb, req, nTypes, mapWidths, symsPerKey,
++ (!CheckKeyActions(client, xkb, req, nTypes, mapWidths, symsPerKey,
+ (CARD8 **) &values, &nActions))) {
+ client->errorValue = nActions;
+ return BadValue;
+@@ -2574,18 +2615,18 @@ _XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev,
xkbSetMapReq * req,
+
+ if ((req->present & XkbKeyBehaviorsMask) &&
+ (!CheckKeyBehaviors
+- (xkb, req, (xkbBehaviorWireDesc **) &values, &error))) {
++ (client, xkb, req, (xkbBehaviorWireDesc **) &values, &error))) {
+ client->errorValue = error;
+ return BadValue;
+ }
+
+ if ((req->present & XkbVirtualModsMask) &&
+- (!CheckVirtualMods(xkb, req, (CARD8 **) &values, &error))) {
++ (!CheckVirtualMods(client, xkb, req, (CARD8 **) &values, &error))) {
+ client->errorValue = error;
+ return BadValue;
+ }
+ if ((req->present & XkbExplicitComponentsMask) &&
+- (!CheckKeyExplicit(xkb, req, (CARD8 **) &values, &error))) {
++ (!CheckKeyExplicit(client, xkb, req, (CARD8 **) &values, &error))) {
+ client->errorValue = error;
+ return BadValue;
+ }
+@@ -2596,7 +2637,7 @@ _XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev,
xkbSetMapReq * req,
+ }
+ if ((req->present & XkbVirtualModMapMask) &&
+ (!CheckVirtualModMap
+- (xkb, req, (xkbVModMapWireDesc **) &values, &error))) {
++ (client, xkb, req, (xkbVModMapWireDesc **) &values, &error))) {
+ client->errorValue = error;
+ return BadValue;
+ }
+--
+2.53.0
+
--- End Message ---