summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Expósito <jexposit@redhat.com>2023-12-22 18:28:31 +0100
committerJosé Expósito <jose.exposito89@gmail.com>2024-01-16 09:58:02 +0100
commit7b5694368b3f3b039fb523e66b816c1323f3cc39 (patch)
tree384364c2f0e071c30561af4ed1eb35c1a1a351d2
parent6236342157b9ddc9a4ebb3438e469a8cb37eaecb (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.c15
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;