From 8f5e95beac2d05fa09f2887b448ae5af2f7e1104 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Mon, 2 Mar 2026 14:09:57 +0100 Subject: [PATCH] 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 Acked-by: Peter Hutterer (cherry picked from commit d38c563fab5c4a554e0939da39e4d1dadef7cbae) Part-of: --- xkb/xkb.c | 69 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/xkb/xkb.c b/xkb/xkb.c index e90a5d7ba..0493210e8 100644 --- a/xkb/xkb.c +++ b/xkb/xkb.c @@ -1751,6 +1751,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); } @@ -1789,6 +1794,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]; } @@ -1812,11 +1823,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; @@ -1827,6 +1839,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]; @@ -1845,7 +1862,8 @@ CheckKeyActions(XkbDescPtr xkb, } static int -CheckKeyBehaviors(XkbDescPtr xkb, +CheckKeyBehaviors(ClientPtr client, + XkbDescPtr xkb, xkbSetMapReq * req, xkbBehaviorWireDesc ** wireRtrn, int *errorRtrn) { @@ -1871,6 +1889,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; @@ -1896,7 +1919,8 @@ CheckKeyBehaviors(XkbDescPtr xkb, } static int -CheckVirtualMods(XkbDescRec * xkb, +CheckVirtualMods(ClientPtr client, + XkbDescRec * xkb, xkbSetMapReq * req, CARD8 **wireRtrn, int *errorRtrn) { register CARD8 *wire = *wireRtrn; @@ -1908,12 +1932,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; @@ -1939,6 +1969,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; @@ -1994,7 +2029,8 @@ CheckModifierMap(ClientPtr client, XkbDescPtr xkb, xkbSetMapReq * req, } static int -CheckVirtualModMap(XkbDescPtr xkb, +CheckVirtualModMap(ClientPtr client, + XkbDescPtr xkb, xkbSetMapReq * req, xkbVModMapWireDesc ** wireRtrn, int *errRtrn) { @@ -2018,6 +2054,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; @@ -2561,7 +2602,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; @@ -2569,18 +2610,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; } @@ -2591,7 +2632,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; }