Passive grabs (GrabRec) store raw DeviceIntPtr values for both the
grabbed device and the modifier device without any lifetime management.
When a device is removed via XIRemoveMaster, CloseDevice() frees the
device struct, but leaves dangling pointers in grab->modifierDevice
for any grab that used this device.
Subsequent pointer events trigger CheckPassiveGrab() which dereferences
the dangling modifierDevice pointer for XI grabs (the CORE and XI2 paths
reassign it, but the XI path does not).
This vulnerability was discovered by:
Anonymous working with TrendAI Zero Day Initiative
ZDI-CAN-31832
CVE-2026-93516
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 be57263415)
The global static swapEvent/swapEventLen buffer in WriteEventsToClient()
was a persistent allocation that grew on demand. Replace with a
per-call calloc/free to avoid holding memory indefinitely and to
eliminate a static state that is not thread-safe.
The previous logic grew the buffer via realloc() and kept it for the
life of the process. The new logic allocates exactly eventlength bytes
for each swapped WriteEventsToClient() call, uses it for all events
in that call, and frees it before returning.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
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>
The X11 protocol requires each window to be destroyed in turn.
Previously, DestroySubwindows unmapped all child windows first.
This sent all UnmapNotify events before any DestroyNotify events.
Removing the UnmapSubwindows call lets each child window be unmapped
and destroyed individually. This restores correct event ordering.
Each child now runs its own ValidateTree pass instead of sharing one.
This diverges from xorg/main, which still carries the UnmapSubwindows
shortcut and its XXX comment.
Signed-off-by: Mason Green <mason@greenm01.net>
ProcDestroySubwindows() ignored the result of DestroySubwindows() and
always replied Success. When an XACE hook denies destroying a child,
DestroySubwindows() stops there and returns the error, but the client
was told the request succeeded while some children were left in place.
Return the result instead. This also lets PanoramiXDestroySubwindows()
stop at the first failing screen, which it already checks for.
Signed-off-by: Mason Green <mason@greenm01.net>
NextAvailableClient() stores the new client in clients[i] before
InitClientResources() and InsertFakeRequest(). If either fails, the
client is freed but clients[i] still points at it.
When i is a free slot below currentMaxClients, the next incoming
connection reaches EstablishNewConnections(), which walks
clients[1..currentMaxClients) and dereferences the freed client.
Clear clients[i] on both failure paths before freeing.
Signed-off-by: Mason Green <mason@greenm01.net>
This was accidentially exported. No external driver ever had a chance
to use it yet, so unexport it now.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
With commit b778d62b9b these are also used by
the modesetting driver, which failed due them not being _X_EXPORT'ed.
But since they're so small, it's easier to just make them inline, instead
of making extra _X_EXPORT's just for this particular case.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
RegionValidate() copies *badreg into ri[0].reg, so ri[0].reg.data aliases badreg->data. A later
RECTALLOC_BAIL() can realloc() that block and move it, updating ri[0].reg.data but not badreg->data. On
the bail path, freeing ri[0].reg.data and then calling RegionBreak(badreg) frees badreg->data a second
time, which by then is a stale pointer into memory already freed or reallocated to something else.
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2281>
(cherry picked from commit 4ef1b4cd26)
(cherry picked from commit bb02769445b1a516f33b4855977cc227f0542cb7)
(cherry picked from commit bc0760d9514fe5f2d9e4f5287ab0318d45c32736)
At this point, allowing X Font Server connections just introduces us to
possible security issues since the code effectively trusts any font
server and few checks are in place.
Since font servers also haven't been used for ages, let's disable
them by default. Use-cases that require them will have to pass
+fontserverconnections on the commandline and/or set the corresponding
ServerFlags option.
The tests are a bit hacky: Debian builds libXfont2 with --disable-fc so
we need to cater for the case where the X server enables fontserver support
but libXfont then blocks it and we still need to treat this as success.
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2263>
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
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>
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>
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>
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>
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>
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>
When Xinerama is enabled, the number of user-visible roots (screens)
isn't equal to number of actual server screens anymore. Instead of
having #ifdef's in several places, let the connection block renderer
record the number of roots actually processed.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
We have to patch up the connection info block with per-client specific
data. Instead of patching up a global buffer, do this in a safe copy.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Factor out the actual rendering to a separate function, which now just
returns x_rpcbuf_t, not directly updating global ConnectionInfo field
(that's left to the caller).
In later iterations, we then could easily generate a new connection info
block per client, eg. masking the available screens based on separate
policies (NEXUS screen remapping, Xnamespace permissions, etc).
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Simplify the code by using x_rpcbuf_t, so we don't need prio block size
calculation and care for allocation / reallocation. rpcbuf is don't it
all for us and giving us the final block size.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Drop the global connSetupPrefix variable and instead create that
tiny struct on the fly (we need to copy it for byteswapping anyways)
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Store it it's own variable as authorative source, so we don't
need to keep it in connSetupPrefix anymore - and get rid of that
in future steps.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Make the code path a bit cleaner and tightly more efficient
(by doing the byteswap directly)
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Remove dependency on MIN() from os/mathx_priv.h by replacing the MIN()
call with an explicit bounds check using ternary-style logic.
Changes:
- Change walkStop from int to unsigned (consistency with walkScreenIdx)
- Replace MIN(start + num, screenInfo.numScreens) with explicit check
- Update doc comment to accurately describe 'start + num limited by
screenInfo.numScreens' semantics instead of 'all screens'
- Fix typo 'poiner' -> 'pointer' in doc comment
This keeps the macro signature and behavior unchanged (#3725 uses it),
while making it self-contained without requiring os/mathx_priv.h.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Panoramix needs a special handling so that we're only sending one
screen (and numRoots becomes = 1). Instead of tweaking global
variables back and forth, just pass in the desired value.
When 0 is passed, using screenInfo.numScreens instead.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Special form of DIX_FOR_EACH_SCREEN() which is starting at some
given offset and walking only given number from here.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Usually, we would use screenInfo.numScreens, but Xinerama has a special
handling that's taking the number from the already compiled ConnectionInfo's
numRoots field.
Actually, we don't need any special handling here, just take the numroots
field, because in non-xinerama case, it's equal to screenInfo.numScreens.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
When inlined, we were doing calls like:
`strncat(buf, str, sizeof(buf))`, which can overflow the buffer.
When building with asan it lead to pages of this:
```
In function '__accbit',
inlined from '__accbit' at ../xlibre-server-9999/dix/registry.c:269:20,
inlined from 'LookupDixAccessName' at ../xlibre-server-9999/dix/registry.c:308:5,
inlined from 'hookResourceAccess' at ../xlibre-server-9999/Xext/namespace/hook-resource.c:134:5:
../xlibre-server-9999/dix/registry.c:272:13: warning: 'strncat' specified bound 128 equals destination size [-Wstringop-overflow=]
272 | strncat(buf, ",", sz);
| ^
../xlibre-server-9999/dix/registry.c:273:9: warning: 'strncat' specified bound 128 equals destination size [-Wstringop-overflow=]
273 | strncat(buf, name, sz);
|
```
Signed-off-by: stefan11111 <stefan11111github@gmail.com>
AddScreen() allocates a new ScreenRec structure, adds it to the global screen
list and then calls the passed ScreenInitProcPtr function for the DDX init.
Right now, this machinery has no way for passing DDX private data into DDX
init, so all DDX'es have to do ugly tricks (eg. using the latest screen number
and global) to access it's private data. That tends to imply various assumptions,
eg. DDX knowing exactly which screen numbers going to be allocated for the yet
to be created screens. It's managable as long as screens are static and DDX is
the only one reserving screen slots, but totally falling once screens get added
or removed at runtime or something something like NEXUS comes around, creating
virtual before the DDX screens.
Therefore, allow DDX passing private data to it's own init functions through
the AddScreen machinery. Upcoming steps will updating the individual DDX'es
to actually use that data, instead of going through global arrays, and also
assigning devPrivate's to their screens, so global table looksups via screen
aren't necessary at all anymore.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
This PR re-adds support for DPI Auto-Detection which was available in X.Org till 21.1, but was removed. This reverts commit 35af1299 and allows to get Auto DPI Detection back only when specified by user as:
$ X -dpi auto
double_size() assigned realloc()'s result directly into *ptr. On
failure this (a) overwrote the only pointer to the still-valid old
buffer with NULL, leaking it and leaving the caller's size counter
(nmajor/nevent/nerror) out of sync with the now-NULL data pointer, and
(b) called dixResetRegistry() -> dixFreeRegistry(), whose free loops
walk requests[]/events[]/errors[] up to that stale nonzero counter --
dereferencing the just-NULLed array before ever reaching a free().
Trigger: RegisterRequestName() (building the request/extension
registry from protocol.txt at server startup) hits OOM on a growth
call after the tables have already grown past the first size class
(nmajor > 0) -- gated on X_REGISTRY_REQUEST (SELinux/XSecurity/dtrace/
namespace-enabled builds), on the normal startup path there.
Use a temporary for realloc()'s result and only commit it to *ptr on
success, so a failed growth leaves the existing buffer and count
untouched and simply aborts that one registration (matching how
RegisterRequestName/RegisterEventName/RegisterErrorName already just
return on a double_size() failure) instead of nuking and potentially
crashing on the whole registry.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
InitTrackers() freed the old tracker buffer and then unconditionally
overwrote vel->tracker with calloc()'s result and vel->num_tracker
with the new count, even on allocation failure. Every tracker access
(FeedTrackers(), QueryTrackers(), the TRACKER()/TRACKER_INDEX() macros)
divides by num_tracker with no zero-guard anywhere in this subsystem,
so a failed alloc left a device either dereferencing a NULL tracker
buffer or dividing by zero on num_tracker on the very next motion
event.
Reachable two ways: the first-ever call from InitVelocityData() (fixed
ntracker=16, calloc-fed vel with no prior buffer), and a later resize
via the "VelocityTrackerCount" driver option
(hw/xfree86/common/xf86Xinput.c).
Fix InitTrackers() to only replace the old buffer/count together on
success, keeping the previous valid state on failure (matches the
resize case; harmless no-op distance from the initial NULL/0 state on
the first-call case). For the first-call case specifically, propagate
the failure out of InitPredictableAccelerationScheme() -- which already
models "return FALSE, free vel/schemeData" for its other two allocation
failures -- instead of letting the device go live with num_tracker == 0.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Update SPDX-License-Identifier from MIT OR X11 (or MIT OR X11 OR AGPLv3+ variants)
to the canonical X11 OR MIT OR AGPL-3.0-or-later on 95 existing source files.
Add the triple-license header to 33 newly-identified files authored by Enrico
Weigelt that were missing SPDX headers entirely.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
XF86-BigFont lets local clients share font-metrics arrays via SysV
shared memory (and compresses them for remote clients) -- a local-only
optimization dating back to ancient XFree86. It hasn't been built by
default for really long time.
Enabling it in our CI immediately exposed that the code has bit-rotted
on 7 non-Linux CI lanes (macOS/BSD: including a nonexistent Linux-only
header; Solaris: an ARRAY_SIZE redefinition pulled in via its system
headers; mingw32: implicit geteuid()/getegid() plus an unused variable).
Concrete evidence that this extension currently has no real users
exercising it, since none of that breakage was ever noticed.
Therefore no practical need for carrying it around any longer.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
These helpers are always defined, even when compiling w/o PanoramiX
at all (symbol XINERAMA not defined), so we need fewer ifdef's.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
A window can have more than one __GLXdrawable registered under its X id.
On teardown DrawableGone() freed the partner with FreeResourceByType(),
which matches only id+type and so frees an arbitrary one, leaving the
survivor dangling -> later use-after-free (issue #1491).
Add FreeResourceByTypeValue() (internal, dix/resource_priv.h) that also
matches the value, and use it in DrawableGone() to free the entry for
this exact drawable. Fixes the UAF while keeping duplicate glXCreateWindow
working, unlike the previous fix that rejected it and broke clients.
Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Kiyoshi Spreclerg <kiyoshi_pip@protonmail.com>
x_rpcbuf_write_counted_string_pad() wrote nothing at all when str was NULL.
But a counted string is a fixed wire element - a 16-bit length, the bytes,
then padding to a 4-byte unit. The matching reader (XKB's _GetCountedString)
unconditionally consumes that 16-bit length (an empty string is length 0 +
pad = 4 bytes), and XkbSizeCountedString() budgets 4 bytes for NULL too.
Omitting the field for NULL therefore produced a short, malformed
XkbGetGeometry reply whenever a geometry string field was NULL (label_font,
a doodad text/font/logo_name, a colour spec, or a property name/value),
desyncing every following field for the reading client.
Write an empty counted string (length 0 + padding) for NULL instead, so the
writer matches the reader and the size accounting.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
sizes can't have negative numbers, so use the size_t here.
Also having to fix up lots of callers.
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>