Commit graph xserver/Xext
Author SHA1 Message Date
Peter Hutterer
a8192aa709 Xi: add bounds check for barrier events in input_constrain_cursor
input_constrain_cursor() writes barrier hit and leave events into the
InputEventList buffer without checking how many slots remain.
The buffer is allocated by the DDX at GetMaximumEventsNum() (100) entries
and may contain one raw event already. A client can create more than 100
pointer barriers, pre-arm them as released via XIBarrierReleasePointer,
and then trigger a single pointer motion that crosses all barriers
simultaneously. The leave event loop iterates every hit barrier and
writes one event per barrier, overflowing the 100-slot buffer.

In an ideal world we'd change the InternalEvent* pointer to a struct
that contains allocated size, number of events and the pointer itself
but we're crossing public APIs here and that requires an ABI bump.

So we make do with cutting off the number of barrier events at 64 which
should be low enough to not trigger the issue. However, for the 100+
barrier case this means we only send BarierHit events, not BarrierRelease.
Potentially leaving a client stuck.

We mitigate that problem by simply refusing to create more than 32
barriers per screen (which on its own would also fix the issue, but hey,
'doppelt gemoppelt' as they say).

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

ZDI-CAN-31938

CVE-2026-93519

Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
(cherry picked from commit 1f42cc1f00)
2026-10-20 21:11:11 +02:00
Peter Hutterer
cede1a7f95 Xi: validate modifier values in ProcXIPassiveUngrabDevice
ProcXIPassiveUngrabDevice() passes client-supplied modifier values
directly to DeletePassiveGrabFromList() without validating them.

DeletePassiveGrabFromList() may reach DeleteDetailFromMask() which uses
BITCLEAR(mask, modifier). The mask is allocated as 8 Mask words (256
bits). A modifier value > 255 causes BITCLEAR to index mask[modifier>>5]
past the allocation, resulting in a controlled single-bit-clear at an
attacker-chosen heap offset.

Add the same modifier validation that CheckGrabValues() uses: reject
modifiers that are not XIAnyModifier and have bits set outside
AllModifiersMask.

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

ZDI-CAN-32366

CVE-2026-93523

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
(cherry picked from commit 37a1847a60)
2026-10-20 21:11:11 +02:00
Peter Hutterer
bae088ccbd xkb: fix CheckKeySyms overwriting request-range symsPerKey entries
CheckKeySyms() has two loops: the first processes keys in the SetMap
request range, the second fills in any missing keys from the existing
map.

The indexing between the two was inconsistent: the first loop
uses a zero-based index + req->firstKeySym, the second loop used it just
as zero-based index.

Example:
   req->firstKeySym = 50
   req->nKeySyms = 10

  i goes from 0 to 10,
  loop 1 checks [50, 60), changes the width but finishes with i at 10.
  loop 2 then runs over [10, 255(, copying the old keymap width

The second loop overwrites the new widths with the width of the
existing keymap. The subsequent SetKeySyms worked on the new width
and may write fewer actions than the map width.

A subsequent XkbGetMap request would then read XkbKeyNumActions()
entries (derived from the new wider key_sym_map.width) from the shorter
action allocation, causing an out-of-bounds heap read. The overread
bytes would be copied into the GetMap reply and sent back to the client,
producing a bounded heap information disclosure.

This vulnerability was discovered by:
  WONJOON HWANG (@joon1337) working with TrendAI Zero Day Initiative

ZDI-CAN-32408

CVE-2026-93524

Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
(cherry picked from commit cea71d0273)

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2026-10-20 19:54:36 +02:00
Peter Hutterer
c5247a4185 xkb: widen size_syms, num_syms, size_acts, num_acts to unsigned int
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.

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

ZDI-CAN-31834

CVE-2026-93518

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
(cherry picked from commit 89101a6c66)
2026-10-20 19:54:36 +02:00
Peter Hutterer
2822958bbf 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: a3171732da ("xkb: Always use MAP_LENGTH keymap size")

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
(cherry picked from commit b941a473e0)
2026-10-20 19:54:36 +02:00
Peter Hutterer
a0f5e66caa xkb: NULL text pointer after free in _CheckSetDoodad error path
_CheckSetDoodad() allocates doodad->text.text via _GetCountedString()
and then attempts to allocate doodad->text.font. If the font string
allocation fails (e.g. because the font string length extends past
the request boundary), the error handler frees doodad->text.text but
does not NULL the pointer. The doodad was already added to the geometry
by XkbAddGeomDoodad() before the string allocations, so when
XkbFreeGeometry() runs cleanup, _XkbClearDoodad() frees the same
dangling pointer again, resulting in a double-free.

NULL the pointer after freeing it to prevent the double-free.

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

ZDI-CAN-31221

CVE-2026-88812

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
(cherry picked from commit 0d1b1b0bad)
2026-10-20 19:54:36 +02:00
Mikhail Dmitrichenko
37f43dc86a xkb: reject incomplete keymaps in GetKbdByName
XkmReadFile() allocates an XkbDesc before it reads the individual XKM
sections, so a section read failure leaves a non-NULL but only partially
initialized description behind.

ReadXkmKeyTypes() does not report such a failure at all. When
XkbAllocClientMap() fails it returns the number of bytes read so far,
which is positive, so XkmReadFile() takes the section for successfully
read and clears it from the mask of sections it reports as missing.

ProcXkbGetKbdByName() in turn only checks that the description it got
back is non-NULL before setting rep.loaded. It can therefore install a
description that has neither a client map nor controls, and
XkbCopyControls() then dereferences those and crashes the server.

Return -1 from ReadXkmKeyTypes() when the client map cannot be
allocated, and only report a keymap as loaded once rep.found covers
every component in fneed. Decide whether to update the actions from
rep.loaded rather than from the requested load flag, so that an
incomplete description is not handled as a successfully loaded map.

The keymap the device already had stays active when the compiled XKM
cannot be read completely.

Signed-off-by: Mikhail Dmitrichenko <m.dmitrichenko222@gmail.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2304>
(cherry picked from commit 6a4fb12019)
2026-10-20 19:51:15 +02:00
Mikhail Dmitrichenko
3bb0f25410 xkb: use ssize_t for XKM byte counts
The ReadXkm* section readers return the number of bytes they consumed,
or -1 when they give up. That contract was spelled as int, while the
counters accumulating their results were a mix of int and unsigned, and
XkmGetCARD8/16/32() took the counter by reference as an int *.

XkmReadFile() also returns an unsigned, but that value is a bitmask of
the sections it could not read, not a byte count. Keeping byte counts in
unsigned variables right next to it makes the two easy to confuse, and
the confusion has a concrete cost: XkmReadFile() kept the readers'
results in an unsigned tmp, so the -1 that every one of the seven
readers it dispatches to can return became UINT_MAX. That passed the
tmp > 0 test below, and the section which had just failed to read was
marked as defined and cleared from the mask of sections reported as
missing.

Use ssize_t, the usual type for "a number of bytes, or -1 on failure",
for every byte count in this file: the section readers' return type, the
local counters, the counter XkmGetCARD8/16/32() take by reference, and
the return values of XkmSkipPadding() and XkmGetCountedString(). An
unsigned in this file now only ever denotes a bitmask, and a failing
section reader is no longer taken for a successful one.

ReadXkmKeyTypes() used a single tmp both for byte counts and as the
in/out element count handed to XkmInsureTypedSize(), which needs an
int *. That second use gets its own variable.

Signed-off-by: Mikhail Dmitrichenko <m.dmitrichenko222@gmail.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2304>
(cherry picked from commit bad7edcab0)
2026-10-20 19:51:15 +02:00
Peter Hutterer
5d3b8520ec present: unlink notifies from window list in present_clear_window_notifies
When a window is destroyed, present_clear_window_notifies()
does not remove the notify list node from the window. The notify
may then be freed as part of the window_priv, leaving dangling
pointers in place.

When the vblank owning the notify is later torn down,
present_free_window_notify() calls xorg_list_del() which
writes through these dangling pointers (use-after-free write).

This happens when Present cross-window notifies are used: a
PresentPixmap on window A can reference window B as a notify target.
An untriggered wait_fence keeps the vblank alive so that B can be
destroyed first, creating the dangling-pointer window.

Fix this by calling the free function we have (and moving the window
reset into that function too). present_clear_window_notifies is only
called from one place anyway.

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

ZDI-CAN-31830

CVE-2026-93515

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
(cherry picked from commit 1b6955c310)
2026-10-20 19:49:20 +02:00
Peter Hutterer
02359bf013 glx: validate dataBytes against cmdlen in RenderLarge first request
__glXDisp_RenderLarge() allocates the large command buffer based on
cmdlen (from hdr->length, the total command size embedded in the
payload), but copies dataBytes (from req->dataBytes, the payload size
of the current sub-request) into it. The existing length check only
validates that the X11 request length is consistent with dataBytes,
not that dataBytes fits within the cmdlen-sized buffer.

A malicious client can set hdr->length to a small value (e.g. 12 bytes)
while sending a large dataBytes (up to ~256KB or more with
BIG-REQUESTS), causing the memcpy to overflow the cmdlen-sized buffer.

Add a check that dataBytes <= cmdlen before the buffer allocation and
copy on the first request.

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

ZDI-CAN-31833

CVE-2026-93517

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2341>
(cherry picked from commit 2abe4632d7)
2026-10-20 19:49:20 +02:00
Kiyoshi Spreclerg
3a7005b67c composite: fix inverted cw->damaged in compReportDamage()
Also use `false` instead of `FALSE` in compWindowUpdate() for the bool field.

Fixes: 4a30260387 ("composite: use 'bool' instead of 'Bool' in CompClientWindowRec")
Signed-off-by: Kiyoshi Spreclerg <kiyoshi_pip@protonmail.com>
2026-10-19 13:10:03 +02:00
Enrico Weigelt, metux IT consult
d13cf6f431 Xext: xv: fix mismatching event swap prototypes
Instead of hard typecasts on event proc assignment, better accept the
expected parameter types and do the typecast inside the functions.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-17 19:45:49 +02:00
Enrico Weigelt, metux IT consult
c255120ee8 Xext: saver: fix mismatching event swap prototypes
Instead of hard typecasts on event proc assignment, better accept the
expected parameter types and do the typecast inside the functions.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-17 19:37:55 +02:00
Enrico Weigelt, metux IT consult
f9a4cc731a Xext: shm: fix mismatching event swap prototypes
Instead of hard typecasts on event proc assignment, better accept the
expected parameter types and do the typecast inside the functions.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-16 11:59:20 +02:00
Enrico Weigelt, metux IT consult
66505eecd5 Xext: sync: fix mismatching event swap prototypes
Instead of hard typecasts on event proc assignment, better accept the
expected parameter types and do the typecast inside the functions.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-15 19:08:16 +02:00
Enrico Weigelt, metux IT consult
4fb08174d7 Xext: shape: fix mismatching event swap prototypes
Instead of hard typecasts on event proc assignment, better accept the
expected parameter types and do the typecast inside the functions.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-15 17:57:49 +02:00
Enrico Weigelt, metux IT consult
e1aa7c5fd5 Xext: randr: fix mismatching event swap prototypes
Instead of hard typecasts on event proc assignment, better accept the
expected parameter types and do the typecast inside the functions.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-15 17:30:45 +02:00
Enrico Weigelt, metux IT consult
e0c0a20dee Xext: damage: fix mismatching event swap prototypes
Instead of hard typecasts on event proc assignment, better accept the
expected parameter types and do the typecast inside the functions.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-15 17:30:26 +02:00
Enrico Weigelt, metux IT consult
06775174d1 Xext: xfixes: fix mismatching event swap prototypes
Instead of hard typecasts on event proc assignment, better accept the
expected parameter types and do the typecast inside the functions.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-15 17:28:32 +02:00
Herman Semenoff
01ac17b4c7 dix, Xi: remove spurious dereference when checking function pointers
Check CursorConfinedTo and CursorWarpedTo function pointers directly without
dereferencing them in 'if' conditions in events and xiwarppointer

Signed-off-by: Herman Semenoff <GermanAizek@yandex.ru>
2026-10-15 16:47:45 +02:00
Enrico Weigelt, metux IT consult
45c12c9e80 composite: fix prototype of compRedirectWindow()
It's returning int, not bool.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-14 12:22:58 +02:00
Mason Green
1090a8b19b Xext: security: fix double free when AddResource() fails
When AddResource() cannot allocate its record, it calls the resource
type's delete function before returning FALSE. For an authorization that
is SecurityDeleteAuthorization(), which removes the authorization,
releases its event clients and frees pAuth.

ProcSecurityGenerateAuthorization() then went to bailout, which removed
the authorization a second time and freed pAuth again. Return BadAlloc
directly instead.

Signed-off-by: Mason Green <mason@greenm01.net>
2026-10-14 11:59:30 +02:00
Enrico Weigelt, metux IT consult
4a30260387 composite: use 'bool' instead of 'Bool' in CompClientWindowRec
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-14 11:59:07 +02:00
Enrico Weigelt, metux IT consult
33b61f9f87 composite: turn pendingScreenUpdate field into 'bool'
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-14 11:00:25 +02:00
Enrico Weigelt, metux IT consult
5fa3fe82e3 pseudoramiX: use X_REQUEST_*()/X_REPLY_*() macros in request handlers
Convert the PseudoramiX (XQuartz) request handlers to the
X_REQUEST_HEAD_STRUCT()/X_REQUEST_FIELD_*()/X_REPLY_FIELD_*() macros
from dix/request_priv.h, mirroring the PanoramiX/RRXinerama handlers.
Behaviour-preserving: same size check and conditional byte-swaps.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-13 14:45:14 +02:00
Enrico Weigelt, metux IT consult
c421afd219 randr: use X_REQUEST_*()/X_REPLY_*() macros in RRXinerama request handlers
Convert the RandR-Xinerama request handlers in rrxinerama.c to the
X_REQUEST_HEAD_STRUCT()/X_REQUEST_FIELD_*()/X_REPLY_FIELD_*() macros
from dix/request_priv.h, mirroring the already-converted PanoramiX
handlers in Xext/panoramiX/panoramiX.c. Behaviour-preserving: the
macros expand to the same size check and conditional byte-swaps.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-13 14:45:14 +02:00
Enrico Weigelt, metux IT consult
9f913a3156 meson_options: disable XvMC build by default
XvMC is only helpful for old MPEG2 decoding (and here only some specific
part, the motion compensation). It's only supported by few cards, and needs
special client-side drivers, which need to have direct and pretty low-level
(non-DRI) GPU access (usually involving root access).

Since it's local-only anyways, modern clients can use generic GPU shaders
for various video formats (via standard DRI/mesa) and send whole frames.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-13 14:16:38 +02:00
itz-me-zappex
5f6b5e0138 present: Get rid of blank "present_execute()" declaration.
Signed-off-by: itz-me-zappex <85901674+itz-me-zappex@users.noreply.github.com>
2026-10-13 14:16:11 +02:00
David
baaa397af9 render: free animated cursor timers on destruction
AnimCursorCreate allocates an OsTimer even if the cursor is never
displayed. AnimCurUnrealizeCursor releases the retained frame cursors
but does not release that timer, leaking 40 bytes per animated cursor
on the tested x86_64 build.

Free the timer with the frame references on screen zero, and clear the
pointer. This cleanup runs when the final cursor reference is released.

The leak was reproduced with LeakSanitizer on an XLibre 25.1.9-based
test server. With the fix, all 90 focused native ASan/UBSan checks
pass with leak detection enabled and GLX disabled, including unused
animated cursors and repeated displayed cursor replacement.

Signed-off-by: David <david@code.contractors>
2026-10-13 13:58:33 +02:00
Mason Green
73cd133bbb Xext: composite: take the pixmap reference before AddResource() on Xinerama
When AddResource() fails it calls the type's delete function, which for
pixmaps is dixDestroyPixmap() and drops one reference.

SingleCompositeNameWindowPixmap() increments pPixmap->refcnt before
AddResource(), so a failure only drops that extra reference. The Xinerama
path in ProcCompositeNameWindowPixmap() incremented it afterwards, so a
failure dropped the window's own reference to its backing pixmap and
could free it while still in use. Take the reference first, as the
single-screen path does.

Signed-off-by: Mason Green <mason@greenm01.net>
2026-10-13 13:06:14 +02:00
Octavia Togami
bb59d6895f Fix use-after-free caused by duplicate glyphs in one glyphset
We make two glyphsets, GS1 and GS2, both with the same format depth.
GS1 contains any glyph different from the others, let's call it U
(unique). GS2 contains two glyphs with the same content, or at least
sha1 hash. Let's call them A and B.

We first register GS1 and GS2. GS1 has no problems, but before the
fix, registering GS2 breaks accounting in `globalGlyphs`. Since there
is no check for duplicate glyphs within a single set, we make two
`GlyphNew` entries for A and B. Now in the loop at the end, we go over
each entry and call `AddGlyph` and `FreeGlyph`:
1. AddGlyph(GS2, A, idA) inserts A into `globalGlyphs`
2. FreeGlyph(A) drops A's refcnt by one, but as it's being held in
   `globalGlyphs` it's kept alive.
3. AddGlyph(GS2, B, idB) finds A in `globalGlyphs` and reuses it
   instead of inserting B
4. FreeGlyph(B) drops B's refcnt by one (to zero), and B is freed.
   Before the fix, the lookup in `globalGlyphs` finds A's entry, and
   since it isn't a DeletedGlyph, it erroneously removes the
   `gr->glyph` pointing to `A` and decrements `tableEntries`. This
   results in `tableEntries` being off-by-one as `A` is still alive.

Now, we free the glyphsets in a particular order. Freeing GS1 results
in calling FreeGlyph(U), which will decrement U's refcnt to zero, and
free U. This clears out the entry in `globalGlyphs` for U and
decrements `tableEntries`, which due to the earlier error is now zero.
When `FreeGlyphSet` sees this, it clears the `globalGlyphs` for that
format depth. Now freeing A or GS2 (which transitively frees A) will
try to check the `globalGlyphs` at that format depth, but because it
was cleared out this crashes.

The fix here is to change FreeGlyph to only free a glyph from
`globalGlyphs` that is exactly the glyph being freed, so that
FreeGlyph(B) doesn't touch `globalGlyphs` at all. This keeps a proper
count in `tableEntries` and prevents `globalGlyphs[fdepth]` from being
freed before A is freed.

Closes: #1881
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2264>
(cherry picked from commit 81edc9caf557f7a44c5b308742814457de0eb6c0)
(cherry picked from commit 716d876142280cd66bdcf000f81428dadd5d3937)
Signed-off-by: Octavia Togami <octy@octyl.net>
2026-10-12 15:37:47 +02:00
Mason Green
999015f6cd Xext/namespace: fix memory leak during namespace destruction
When a transient namespace is deleted, XnsDestroyNamespace() frees the
namespace struct, its name, and its authentication tokens. However, it
leaves the virtual root window active in the server's resource database.

Because the virtual root window is never freed, the server leaks a Window
structure, window attributes, and properties every time a temporary
namespace is destroyed.

Fix this leak by calling FreeResource() on the virtual root window
before destroying the namespace.

Also update the formal TLA+ model in doc/Xnamespace.tla to track
resource cleanup and verify the fix.

Signed-off-by: Mason Green <mason@greenm01.net>
2026-10-07 16:01:44 +02:00
Mason Green
e0160fdb7d Xext/namespace: fix potential NULL-pointer dereference in select_ns()
When the configuration file is parsed at server startup, select_ns()
dynamically allocates namespace structures. However, it does not check
whether calloc() or strdup() successfully allocate memory.

If calloc() fails, the server dereferences a NULL pointer and crashes
instantly.

If strdup() fails, the namespace is added to the global list with a
NULL name. When the server later searches for a namespace, it calls
strlen() on the NULL name. This causes a delayed crash of the server
at runtime.

Fix this by adding standard FatalError() checks to handle allocation
failures safely during startup.

Also include a formal TLA+ verification model of the Xnamespace
security isolation extension in doc/Xnamespace.tla.

Signed-off-by: Mason Green <mason@greenm01.net>
2026-10-07 16:01:44 +02:00
Enrico Weigelt, metux IT consult
8b865dbb56 xinput: make barrier event emission NULL-safe in input_constrain_cursor()
input_constrain_cursor() writes pointer-barrier hit/leave events into the
caller-supplied events buffer and bumps *nevents. It dereferenced both
unconditionally (barrier_events->barrier_event = ev; *nevents += 1), so
calling it with a NULL events/nevents pair crashed on the first barrier.

Callers do not pass NULL today (the only NULL call, GetTouchEvents ->
positionSprite(), is hardcoded to Absolute mode where this function's
barrier paths are skipped), but the function is a straightforward
NULL-safety hazard. Guard event emission on a can_emit flag derived from
both pointers, while still performing the barrier clamping so cursor
coordinates are constrained correctly even when no events can be emitted.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-07 15:56:14 +02:00
Jeremy Huddleston Sequoia
d8cee7e08b xkb: Guard XkbAdjustGroup() against a keymap with no groups
When every key in a keymap has zero groups, ctrls->num_groups is 0 and each out-of-range action here misbehaves.
XkbWrapIntoRange divides by zero, which is the reported crash.  XkbClampIntoRange is worse: it computes -1,
returns it through this function's unsigned type, and the callers truncate it into XkbStateRec's unsigned char
group fields as 255, after which XkbComputeCompatState() reads map->groups[255] out of a four element array and
reports what it finds to clients in the compat state of every core event.  The negative-group case adds zero
forever, wedging the server thread, in one path while it holds input_lock.  XkbComputeDerivedState() treats group
0 as out of range once num_groups is 0, so all of this is reachable from an ordinary key event.

XQuartz gets there because it asks for model "empty", whose keycodes file declares no key names, so a keymap
compiled at a client's request has no key definitions at all.

Guard the arithmetic itself and not just the places that compute num_groups: groups_wrap selects between these
actions and is client settable, and this is exported for DDXes that supply their own controls.

Fixes: https://github.com/XQuartz/XQuartz/issues/422
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2278>
(cherry picked from commit bdb14dce4b)
(cherry picked from commit b5ea5591d1f514d0eb0cc5f58052a24fd1b06b9e)
(cherry picked from commit eb420bff03b4ae05d00821482c9fcfaf32a2922d)
2026-10-01 19:01:38 +02:00
Lukáš Lipinský
cafe531326 Xi: byte-swap DeviceChanged valuator and scroll data
SDeviceChangedEvent left ValuatorClass.value and every ScrollClass-specific multi-byte field in server byte order. Swapped clients therefore received corrupt current values and scroll metadata.

Swap those fields and extend the protocol event conversion coverage to nonzero relative valuator values and both scroll directions and flags.

Signed-off-by: Lukáš Lipinský <18076-Mr-Tao@users.noreply.gitlab.freedesktop.org>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2291>
(cherry picked from commit cf91b97d6c)
(cherry picked from commit 7a7e9c66b17cd0d64d31fa19244f3e4eb162fed7)
(cherry picked from commit f9e486ad1d398fb8dcf48f88cd8923decd291c7c)
2026-10-01 19:00:26 +02:00
Lukáš Lipinský
9f1a06d0b5 Xi: byte-swap XIQueryDevice ScrollClass flags
SwapScrollInfo converted the other multi-byte ScrollClass fields but left flags in server byte order. Swap it as well and decode the field in the swapped-client protocol test so nonzero flags exercise the wire representation.

Signed-off-by: Lukáš Lipinský <18076-Mr-Tao@users.noreply.gitlab.freedesktop.org>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2291>
(cherry picked from commit 8033c4d93e)
(cherry picked from commit 2d1d0b67dc2119507f52e3dae96827b8946d0eca)
(cherry picked from commit db6f28acaa7c7d2a049a92396e1bc35b6f759d8a)
2026-10-01 18:55:18 +02:00
Jeremy Huddleston Sequoia
d7e1c7e5c9 xkb: Keep the group counts of a loaded keymap in range
Clamp the count once per key and use it everywhere the key or the keymap is indexed with it, while still reading
every symbol the file claimed so that the stream stays in step and the symbol array is not left short.

At the other end, a symbols section in which no key defines any group leaves the count at the zero it was
allocated with.  This is how XQuartz's keyboard is initialized: model "empty" supplies a symbols section that
defines no keys, and a section that defines nothing is still a section, so XkbInitControls() sees XkmSymbolsMask
and skips its own single-group default.  The device only survives because DarwinKeyboardReloadHandler()
immediately pushes a core keymap that raises the count again.

Fixes: https://github.com/XQuartz/XQuartz/issues/422
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2278>
(cherry picked from commit 0c764d98ee)
(cherry picked from commit 173fe333e4c4cec65bf61427827e2f44262c29af)
(cherry picked from commit ea50d2225fb90686987bc45449a3b93decf0054c)
2026-10-01 18:19:22 +02:00
Jeremy Huddleston Sequoia
ba20d93aea xkb: Never recompute a keymap's group count down to zero
Both places that derive ctrls->num_groups from the widest key in the map can arrive at zero.  But a keymap in
which no key defines any symbols is legal, so ensure we declare at least one group.

Fixes: https://github.com/XQuartz/XQuartz/issues/422
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2278>
(cherry picked from commit aa0bc93d27)
(cherry picked from commit a3f4359f33e65d16037d010a875ef93ed8cc6dee)
(cherry picked from commit 8bb68f76e1940dea50e6c4182b45e8ee528cbe62)
2026-10-01 18:18:40 +02:00
Jeremy Huddleston Sequoia
88043a1944 xkb: Default to one group whenever a keymap reports none
XkbInitControls() had a fallback to ensure keymaps that defined no symbols at all still resulted in one group.
Extend this to cover the case where a keymap reports symbols but no groups.

Fixes: https://github.com/XQuartz/XQuartz/issues/422
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2278>
(cherry picked from commit 8e11715024)
(cherry picked from commit c9dd5aa9e505d65036c351c78cd74c5a6fc53535)
(cherry picked from commit 712c3e7497c90a0d9ad6f863abdd2e330623887d)
2026-10-01 17:36:35 +02:00
Enrico Weigelt, metux IT consult
42d18f08ab Xext: panoramiX: declare where needed in PanoramiXCreateConnectionBlock()
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-10-01 11:26:55 +02:00
Alan Coopersmith
2bbea240f3 Handle -Wimplicit-fallthrough warnings from gcc 16.1
Gets rid of 36 -Wimplicit-fallthrough warnings

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2272>
2026-09-30 21:03:21 +02:00
Alan Coopersmith
a60048ef94 xkb: Fix -Wcalloc-transposed-args warning in _XkbCopyGeom()
Reported by gcc 16.1:
xkb/xkbUtils.c:1440:39: warning: ‘calloc’ sizes specified with ‘sizeof’ in
the earlier argument and not in the later argument [-Wcalloc-transposed-args]
 1440 |             dst->geom = calloc(sizeof(XkbGeometryRec), 1);
      |                                       ^~~~~~~~~~~~~~

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2272>
2026-09-30 20:53:12 +02:00
Enrico Weigelt, metux IT consult
21f82727a4 Xext: panoramiX: let PanoramiXCreateConnectionBlock() return rpcbuf
Let PanoramiXCreateConnectionBlock() only return x_rpcbuf_t, not touching
global structures anymore - it's caller will that now.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-09-29 16:11:03 +02:00
Enrico Weigelt, metux IT consult
0003a7180c xfixes: implement 6.1: forced server shutdown on client disconnect
XFixes 6.1 adds a new feature where individual client can demand immediate
server shutdown when it disconnects: the client can set a special flag via
X_XFixesGetClientDisconnectMode request - when it's set and that client
terminates, the server stops event delivery and shuts down immediately.

It's is mainly a security feature for screen lockers: without it, crashing
screen locker leading to the whole session becoming unlocked. This is now
prevented by immediately killing the xserver, so no unauthorized access
to the session is possible anymore.

Another practical use case is when some critical applications must be present
(eg. in certain control centers), and a crash of those should trigger to
immediate fault state or session restart.

For now, the feature can only be enabled explicitly in the xfree86 DDX,
via the AllowForceTerminate boolean config file option. Not enabled at all
on other DDX'es yet.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-09-29 12:23:40 +02:00
Enrico Weigelt, metux IT consult
1792233bd8 xext: panoramix: simplify PanoramiXConsolidate() calls
1. move the panoramix enabled check into PanoramiXConsolidate()
2. declare a static inline dummy if XINERAMA is not defined,
   so callers don't need extra ifdefs anymore.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-09-28 19:50:33 +02:00
Enrico Weigelt, metux IT consult
6dc28b50aa xext: panoramix: directly use PanoramiXPixWidth / PanoramiXPixHeight
Instead of extracting them the connection info block, use the original
values (those are written into the connection block at consolidation)

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-09-28 19:44:54 +02:00
Enrico Weigelt, metux IT consult
4c37cf1437 dix: connsetup: remove screenDataOffset param
now that we have dixConnBlockScreenStart(), we don't need the
reference parameter of dixConnBlockScreenStart() anymore.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-09-28 19:19:32 +02:00
Enrico Weigelt, metux IT consult
ab7b2b44f3 dix: connsetup: add helper dixConnBlockScreenStart()
adding a helper for calculating the offset of the first xWindowRoot
structure within the connection info block. this way getting rid
of the global connBlockScreenStart field.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-09-28 16:13:08 +02:00
Enrico Weigelt, metux IT consult
322305bfe6 Xext: panoramix: inline CreateConnectionBlock()
inline CreateConnectionBlock() into PanoramiXCreateConnectionBlock(),
in order to make future refactoring a bit easier. Further steps will
refactor the function to just return the buffer instead of setting
global variables.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2026-09-25 22:42:03 +02:00