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
+

Reply via email to