diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2024-01-30 11:11:54 +1000 |
---|---|---|
committer | Marge Bot <emma+marge@anholt.net> | 2024-09-01 23:12:28 +0000 |
commit | e7c876ab0b0daa546a23d4ef82537fdf8fd88e04 (patch) | |
tree | 3ddf8559dad353ba00ec776a5781282621d33585 /Xi | |
parent | 9b983fecf999b9f50946973f2379a5ce00491cad (diff) |
Xi: when removing a master search for a disabled paired device
If either the master pointer or keyboard was disabled, the respective
GetMaster() call returns NULL, causing a segfault later accessing the
deviceid.
Fix this by looking in the off_devices list for any master
device of the type we're looking for. Master devices lose the pairing
when disabled (on enabling a keyboard we simply pair with the first
available unpaired pointer).
And for readability, split the device we get from the protocol request
into a new "dev" variable instead of re-using ptr.
Fixes #1611
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1256>
Diffstat (limited to 'Xi')
-rw-r--r-- | Xi/xichangehierarchy.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/Xi/xichangehierarchy.c b/Xi/xichangehierarchy.c index 99cc25045..8e7a0dcae 100644 --- a/Xi/xichangehierarchy.c +++ b/Xi/xichangehierarchy.c @@ -50,6 +50,7 @@ #include "extnsionst.h" #include "exglobals.h" #include "geext.h" +#include "misc.h" #include "xace.h" #include "xiquerydevice.h" /* for GetDeviceUse */ #include "xkbsrv.h" @@ -217,36 +218,56 @@ disable_clientpointer(DeviceIntPtr dev) } } +static DeviceIntPtr +find_disabled_master(int type) +{ + DeviceIntPtr dev; + + /* Once a master device is disabled it loses the pairing, so returning the first + * match is good enough */ + for (dev = inputInfo.off_devices; dev; dev = dev->next) { + if (dev->type == type) + return dev; + } + + return NULL; +} + static int remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES]) { - DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd; + DeviceIntPtr dev, ptr, keybd, XTestptr, XTestkeybd; int rc = Success; if (r->return_mode != XIAttachToMaster && r->return_mode != XIFloating) return BadValue; - rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess); + rc = dixLookupDevice(&dev, r->deviceid, client, DixDestroyAccess); if (rc != Success) goto unwind; - if (!IsMaster(ptr)) { + if (!IsMaster(dev)) { client->errorValue = r->deviceid; rc = BadDevice; goto unwind; } /* XXX: For now, don't allow removal of VCP, VCK */ - if (ptr == inputInfo.pointer ||ptr == inputInfo.keyboard) { + if (dev == inputInfo.pointer || dev == inputInfo.keyboard) { rc = BadDevice; goto unwind; } - ptr = GetMaster(ptr, MASTER_POINTER); + if ((ptr = GetMaster(dev, MASTER_POINTER)) == NULL) + ptr = find_disabled_master(MASTER_POINTER); + BUG_RETURN_VAL(ptr == NULL, BadDevice); rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess); if (rc != Success) goto unwind; - keybd = GetMaster(ptr, MASTER_KEYBOARD); + + if ((keybd = GetMaster(dev, MASTER_KEYBOARD)) == NULL) + keybd = find_disabled_master(MASTER_KEYBOARD); + BUG_RETURN_VAL(keybd == NULL, BadDevice); rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess); if (rc != Success) goto unwind; |