Cursor: Refuse to free the root cursor

If a cursor reference count drops to 0, the cursor is freed.

The root cursor however is referenced with a specific global variable,
and when the root cursor is freed, the global variable may still point
to freed memory.

Make sure to prevent the rootCursor from being explicitly freed by a
client.

CVE-2025-26594, ZDI-CAN-25544

This vulnerability was discovered by:
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative

v2: Explicitly forbid XFreeCursor() on the root cursor (Peter Hutterer
<peter.hutterer@who-t.net>)
v3: Return BadCursor instead of BadValue (Michel Dänzer
<michel@daenzer.net>)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1828>
This commit is contained in:
Olivier Fourdan 2024-11-27 11:27:05 +01:00
parent 530e80375e
commit 01642f263f

View File

@ -3123,6 +3123,10 @@ ProcFreeCursor(ClientPtr client)
rc = dixLookupResourceByType((void **) &pCursor, stuff->id, X11_RESTYPE_CURSOR, rc = dixLookupResourceByType((void **) &pCursor, stuff->id, X11_RESTYPE_CURSOR,
client, DixDestroyAccess); client, DixDestroyAccess);
if (rc == Success) { if (rc == Success) {
if (pCursor == rootCursor) {
client->errorValue = stuff->id;
return BadCursor;
}
FreeResource(stuff->id, X11_RESTYPE_NONE); FreeResource(stuff->id, X11_RESTYPE_NONE);
return Success; return Success;
} }