57dbbbe
From 4a5e9b1895627d40d26045bd0b7ef3dce503cbd1 Mon Sep 17 00:00:00 2001
57dbbbe
From: Peter Hutterer <peter.hutterer@who-t.net>
57dbbbe
Date: Thu, 4 Jan 2024 10:01:24 +1000
57dbbbe
Subject: [PATCH 5/9] Xi: flush hierarchy events after adding/removing master
57dbbbe
 devices
57dbbbe
57dbbbe
The `XISendDeviceHierarchyEvent()` function allocates space to store up
57dbbbe
to `MAXDEVICES` (256) `xXIHierarchyInfo` structures in `info`.
57dbbbe
57dbbbe
If a device with a given ID was removed and a new device with the same
57dbbbe
ID added both in the same operation, the single device ID will lead to
57dbbbe
two info structures being written to `info`.
57dbbbe
57dbbbe
Since this case can occur for every device ID at once, a total of two
57dbbbe
times `MAXDEVICES` info structures might be written to the allocation.
57dbbbe
57dbbbe
To avoid it, once one add/remove master is processed, send out the
57dbbbe
device hierarchy event for the current state and continue. That event
57dbbbe
thus only ever has exactly one of either added/removed in it (and
57dbbbe
optionally slave attached/detached).
57dbbbe
57dbbbe
CVE-2024-21885, ZDI-CAN-22744
57dbbbe
57dbbbe
This vulnerability was discovered by:
57dbbbe
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
57dbbbe
---
57dbbbe
 Xi/xichangehierarchy.c | 27 ++++++++++++++++++++++-----
57dbbbe
 1 file changed, 22 insertions(+), 5 deletions(-)
57dbbbe
57dbbbe
diff --git a/Xi/xichangehierarchy.c b/Xi/xichangehierarchy.c
57dbbbe
index d2d985848..72d00451e 100644
57dbbbe
--- a/Xi/xichangehierarchy.c
57dbbbe
+++ b/Xi/xichangehierarchy.c
57dbbbe
@@ -416,6 +416,11 @@ ProcXIChangeHierarchy(ClientPtr client)
57dbbbe
     size_t len;			/* length of data remaining in request */
57dbbbe
     int rc = Success;
57dbbbe
     int flags[MAXDEVICES] = { 0 };
57dbbbe
+    enum {
57dbbbe
+        NO_CHANGE,
57dbbbe
+        FLUSH,
57dbbbe
+        CHANGED,
57dbbbe
+    } changes = NO_CHANGE;
57dbbbe
 
57dbbbe
     REQUEST(xXIChangeHierarchyReq);
57dbbbe
     REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
57dbbbe
@@ -465,8 +470,9 @@ ProcXIChangeHierarchy(ClientPtr client)
57dbbbe
             rc = add_master(client, c, flags);
57dbbbe
             if (rc != Success)
57dbbbe
                 goto unwind;
57dbbbe
-        }
57dbbbe
+            changes = FLUSH;
57dbbbe
             break;
57dbbbe
+        }
57dbbbe
         case XIRemoveMaster:
57dbbbe
         {
57dbbbe
             xXIRemoveMasterInfo *r = (xXIRemoveMasterInfo *) any;
57dbbbe
@@ -475,8 +481,9 @@ ProcXIChangeHierarchy(ClientPtr client)
57dbbbe
             rc = remove_master(client, r, flags);
57dbbbe
             if (rc != Success)
57dbbbe
                 goto unwind;
57dbbbe
-        }
57dbbbe
+            changes = FLUSH;
57dbbbe
             break;
57dbbbe
+        }
57dbbbe
         case XIDetachSlave:
57dbbbe
         {
57dbbbe
             xXIDetachSlaveInfo *c = (xXIDetachSlaveInfo *) any;
57dbbbe
@@ -485,8 +492,9 @@ ProcXIChangeHierarchy(ClientPtr client)
57dbbbe
             rc = detach_slave(client, c, flags);
57dbbbe
             if (rc != Success)
57dbbbe
                 goto unwind;
57dbbbe
-        }
57dbbbe
+            changes = CHANGED;
57dbbbe
             break;
57dbbbe
+        }
57dbbbe
         case XIAttachSlave:
57dbbbe
         {
57dbbbe
             xXIAttachSlaveInfo *c = (xXIAttachSlaveInfo *) any;
57dbbbe
@@ -495,16 +503,25 @@ ProcXIChangeHierarchy(ClientPtr client)
57dbbbe
             rc = attach_slave(client, c, flags);
57dbbbe
             if (rc != Success)
57dbbbe
                 goto unwind;
57dbbbe
+            changes = CHANGED;
57dbbbe
+            break;
57dbbbe
         }
57dbbbe
+        default:
57dbbbe
             break;
57dbbbe
         }
57dbbbe
 
57dbbbe
+        if (changes == FLUSH) {
57dbbbe
+            XISendDeviceHierarchyEvent(flags);
57dbbbe
+            memset(flags, 0, sizeof(flags));
57dbbbe
+            changes = NO_CHANGE;
57dbbbe
+        }
57dbbbe
+
57dbbbe
         len -= any->length * 4;
57dbbbe
         any = (xXIAnyHierarchyChangeInfo *) ((char *) any + any->length * 4);
57dbbbe
     }
57dbbbe
 
57dbbbe
  unwind:
57dbbbe
-
57dbbbe
-    XISendDeviceHierarchyEvent(flags);
57dbbbe
+    if (changes != NO_CHANGE)
57dbbbe
+        XISendDeviceHierarchyEvent(flags);
57dbbbe
     return rc;
57dbbbe
 }
57dbbbe
-- 
57dbbbe
2.43.0
57dbbbe