diff options
author | José Expósito <jexposit@redhat.com> | 2023-12-22 18:28:31 +0100 |
---|---|---|
committer | José Expósito <jose.exposito89@gmail.com> | 2024-01-16 09:58:02 +0100 |
commit | 7b5694368b3f3b039fb523e66b816c1323f3cc39 (patch) | |
tree | 384364c2f0e071c30561af4ed1eb35c1a1a351d2 | |
parent | 6236342157b9ddc9a4ebb3438e469a8cb37eaecb (diff) |
Xi: do not keep linked list pointer during recursion
The `DisableDevice()` function is called whenever an enabled device
is disabled and it moves the device from the `inputInfo.devices` linked
list to the `inputInfo.off_devices` linked list.
However, its link/unlink operation has an issue during the recursive
call to `DisableDevice()` due to the `prev` pointer pointing to a
removed device.
This issue leads to a length mismatch between the total number of
devices and the number of device in the list, leading to a heap
overflow and, possibly, to local privilege escalation.
Simplify the code that checked whether the device passed to
`DisableDevice()` was in `inputInfo.devices` or not and find the
previous device after the recursion.
CVE-2024-21886, ZDI-CAN-22840
This vulnerability was discovered by:
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
(cherry picked from commit bc1fdbe46559dd947674375946bbef54dd0ce36b)
-rw-r--r-- | dix/devices.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/dix/devices.c b/dix/devices.c index 15e46a9a5..c3f30e6ee 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -447,14 +447,20 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) { DeviceIntPtr *prev, other; BOOL enabled; + BOOL dev_in_devices_list = FALSE; int flags[MAXDEVICES] = { 0 }; if (!dev->enabled) return TRUE; - for (prev = &inputInfo.devices; - *prev && (*prev != dev); prev = &(*prev)->next); - if (*prev != dev) + for (other = inputInfo.devices; other; other = other->next) { + if (other == dev) { + dev_in_devices_list = TRUE; + break; + } + } + + if (!dev_in_devices_list) return FALSE; TouchEndPhysicallyActiveTouches(dev); @@ -505,6 +511,9 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) LeaveWindow(dev); SetFocusOut(dev); + for (prev = &inputInfo.devices; + *prev && (*prev != dev); prev = &(*prev)->next); + *prev = dev->next; dev->next = inputInfo.off_devices; inputInfo.off_devices = dev; |