From b9c08b30ea54b8bc1c5142304a6eb0ea1bc33a97 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <peter.hutterer@who-t.net>
Date: Mon, 20 Apr 2026 11:18:13 +1000
Subject: [PATCH xserver 4/9] xkb: clamp nMaps to mapWidths buffer size in
 CheckKeyTypes

CheckKeyTypes computes nMaps = firstType + nTypes from client-controlled
request fields when XkbSetMapResizeTypes is set. This value is used to
index mapWidths[], a stack-allocated CARD8 array of XkbMaxLegalKeyCode + 1
(256) elements. No upper bound is enforced on nMaps.

An attacker can first send SetMap(firstType=0, nTypes=255, ResizeTypes) to
set the server's num_types to 255, then send SetMap(firstType=255,
nTypes=10, ResizeTypes). The firstType > num_types check passes because
255 > 255 is false (the check uses > rather than >=). nMaps is then
computed as 265, and the loop writes mapWidths[255..264], overflowing 9
bytes past the stack buffer into adjacent stack variables (symsPerKey[]).

Fix by rejecting requests where firstType + nTypes would exceed the
mapWidths buffer size (XkbMaxLegalKeyCode + 1).

This vulnerability was discovered by:
Anonymous working with TrendAI Zero Day Initiative

ZDI-CAN-30161

Assisted-by: Claude:claude-opus-4-6
---
 xkb/xkb.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git ./xkb/xkb.c ../xkb/xkb.c
index 49c69a933761..7ee11bcd8b33 100644
--- ./xkb/xkb.c
+++ ../xkb/xkb.c
@@ -1616,16 +1616,21 @@ CheckKeyTypes(ClientPtr client,
         return 0;
     }
     if (req->flags & XkbSetMapResizeTypes) {
         nMaps = req->firstType + req->nTypes;
         if (nMaps < XkbNumRequiredTypes) {      /* canonical types must be there */
             *nMapsRtrn = _XkbErrCode4(0x02, req->firstType, req->nTypes, 4);
             return 0;
         }
+        if (nMaps > XkbMaxLegalKeyCode + 1) {
+            *nMapsRtrn = _XkbErrCode4(0x02, req->firstType, req->nTypes,
+                                      XkbMaxLegalKeyCode + 1);
+            return 0;
+        }
     }
     else if (req->present & XkbKeyTypesMask) {
         nMaps = xkb->map->num_types;
         if ((req->firstType + req->nTypes) > nMaps) {
             *nMapsRtrn = req->firstType + req->nTypes;
             return 0;
         }
     }
-- 
2.53.0

