Fedora Account System
Red Hat Associate
Red Hat Customer
This is caused by an incomplete fix regression from commit a3171732d. XkbAllocNames() still uses max_key_code+1 for the names->keys allocation size, while memset in the ChangeKeycodeRange path uses MAP_LENGTH which can be larger. This causes a heap out-of-bounds write when the keycode range is changed to a value where MAP_LENGTH exceeds max_key_code+1. An authenticated X client can trigger this by sending XKB requests that change the keycode range. The heap out-of-bounds write can lead to arbitrary code execution or denial of service. Fixed in: xorg-server-21.1.25 and xwayland-24.1.14 Fix: https://gitlab.freedesktop.org/xorg/xserver/-/commit/TBD Found by: Anonymous working with TrendAI Zero Day Initiative. (ZDI-CAN-31941) * Patch From 58e2874f69ef83323cdd18a4004535e06a8947bb Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer> Date: Wed, 26 Aug 2026 17:04:03 +1000 Subject: [PATCH xserver] 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") Assisted-by: Claude:claude-opus-4-6 #+begin_src diff --- xkb/XKBAlloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xkb/XKBAlloc.c b/xkb/XKBAlloc.c index dced42eebd2c..314a858ddb09 100644 --- a/xkb/XKBAlloc.c +++ b/xkb/XKBAlloc.c @@ -143,17 +143,17 @@ XkbAllocNames(XkbDescPtr xkb, unsigned which, int nTotalRG, int nTotalAliases) } } } if ((which & XkbKeyNamesMask) && (names->keys == NULL)) { if ((!XkbIsLegalKeycode(xkb->min_key_code)) || (!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; } if ((which & XkbKeyAliasesMask) && (nTotalAliases > 0)) { if (names->key_aliases == NULL) { names->key_aliases = calloc(nTotalAliases, sizeof(XkbKeyAliasRec)); } else if (nTotalAliases > names->num_key_aliases) { -- 2.55.0 #+end_src