Bug 2545860 (CVE-2026-93518)
| Summary: | CVE-2026-93518 xorg-x11-server: xorg-x11-server: arbitrary code execution via integer truncation during keyboard mapping resize | ||
|---|---|---|---|
| Product: | [Other] Security Response | Reporter: | OSIDB Bzimport <bzimport> |
| Component: | vulnerability | Assignee: | Product Security <prodsec-ir-bot> |
| Status: | NEW --- | QA Contact: | |
| Severity: | medium | Docs Contact: | |
| Priority: | medium | ||
| Version: | unspecified | CC: | rhel-process-autobot, security-response-team, watson-tool-maintainers |
| Target Milestone: | --- | Keywords: | Security |
| Target Release: | --- | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Fixed In Version: | Doc Type: | --- | |
| Doc Text: |
A flaw was found in xorg-x11-server. Due to an integer truncation issue during memory allocation calculations within the X Keyboard Extension (XKB), the server allocates an undersized buffer when resizing key types. An authenticated local client can exploit this vulnerability by sending specially crafted XKB requests, causing a heap-based buffer overflow. This can result in arbitrary code execution or a denial of service (DoS).
|
Story Points: | --- |
| Clone Of: | Environment: | ||
| Last Closed: | Type: | --- | |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
| Deadline: | 2026-10-07 | ||
In XkbResizeKeyType(), the size_syms variable is declared as unsigned short. The expression (nTotal * 15) / 10 can exceed 65535 for large nTotal values, and the result is truncated when assigned to the unsigned short variable. This causes an undersized allocation, and subsequent writes overflow the heap buffer. An authenticated X client can trigger this by sending XKB requests that cause a key type resize with a sufficiently large nTotal value. The heap buffer overflow resulting from the truncated allocation can lead to arbitrary code execution or denial of service. Fixed in: xorg-server-21.1.25 and xwayland-24.1.14 Fields in XkbClientMapRec and XkbServerMapRec that denote size/num and are unsigned short can result in truncations. For example when XkbResizeKeyType() computes the new size_syms value as (nTotal * 15) / 10, the result may be implicitly truncated to 16 bits on assignment. This causes an undersized calloc allocation, and the subsequent copy loop writes based on the actual (untruncated) key count, resulting in a heap buffer overflow. A similar truncation may happen in XkbResizeKeySyms() and XkbResizeKeyActions(). Widen the fields from unsigned short to unsigned int. These are internal server structures, not wire protocol types. --- include/xkbstr.h | 8 ++++---- xkb/XKBMAlloc.c | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/xkbstr.h b/include/xkbstr.h index 749f1f26e500..45a15f37632a 100644 --- a/include/xkbstr.h +++ b/include/xkbstr.h @@ -307,18 +307,18 @@ typedef struct _XkbControls { } XkbControlsRec, *XkbControlsPtr; #define XkbAX_AnyFeedback(c) ((c)->enabled_ctrls&XkbAccessXFeedbackMask) #define XkbAX_NeedOption(c,w) ((c)->ax_options&(w)) #define XkbAX_NeedFeedback(c, w) (XkbAX_AnyFeedback((c)) && \ XkbAX_NeedOption((c), (w))) typedef struct _XkbServerMapRec { - unsigned short num_acts; - unsigned short size_acts; + unsigned int num_acts; + unsigned int size_acts; XkbAction *acts; XkbBehavior *behaviors; unsigned short *key_acts; #if defined(__cplusplus) || defined(c_plusplus) /* explicit is a C++ reserved word */ unsigned char *c_explicit; #else @@ -341,18 +341,18 @@ typedef struct _XkbSymMapRec { unsigned short offset; } XkbSymMapRec, *XkbSymMapPtr; typedef struct _XkbClientMapRec { unsigned char size_types; unsigned char num_types; XkbKeyTypePtr types; - unsigned short size_syms; - unsigned short num_syms; + unsigned int size_syms; + unsigned int num_syms; KeySym *syms; XkbSymMapPtr key_sym_map; unsigned char *modmap; } XkbClientMapRec, *XkbClientMapPtr; #define XkbCMKeyGroupInfo(m, k) ((m)->key_sym_map[(k)].group_info) #define XkbCMKeyNumGroups(m, k) (XkbNumGroups((m)->key_sym_map[(k)].group_info)) diff --git a/xkb/XKBMAlloc.c b/xkb/XKBMAlloc.c index 78e597f3d93e..8f8ac28fadb9 100644 --- a/xkb/XKBMAlloc.c +++ b/xkb/XKBMAlloc.c @@ -380,17 +380,18 @@ XkbResizeKeyType(XkbDescPtr xkb, nTotal += XkbKeyNumSyms(xkb, i); else { nTotal += XkbKeyNumGroups(xkb, i) * new_num_lvls; nResize++; } } if (nResize > 0) { int nextMatch; - + if (nTotal > INT_MAX / 15) + return BadAlloc; xkb->map->size_syms = (nTotal * 15) / 10; newSyms = calloc(xkb->map->size_syms, sizeof(KeySym)); if (newSyms == NULL) return BadAlloc; nextMatch = 0; nSyms = 1; for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) { if (matchingKeys[nextMatch] == i) { -- 2.55.0