Blame SOURCES/0003-dix-fix-DeviceStateNotify-event-calculation.patch

f4a46c
From 219c54b8a3337456ce5270ded6a67bcde53553d5 Mon Sep 17 00:00:00 2001
f4a46c
From: Peter Hutterer <peter.hutterer@who-t.net>
f4a46c
Date: Mon, 18 Dec 2023 12:26:20 +1000
f4a46c
Subject: [PATCH 3/9] dix: fix DeviceStateNotify event calculation
f4a46c
f4a46c
The previous code only made sense if one considers buttons and keys to
f4a46c
be mutually exclusive on a device. That is not necessarily true, causing
f4a46c
a number of issues.
f4a46c
f4a46c
This function allocates and fills in the number of xEvents we need to
f4a46c
send the device state down the wire.  This is split across multiple
f4a46c
32-byte devices including one deviceStateNotify event and optional
f4a46c
deviceKeyStateNotify, deviceButtonStateNotify and (possibly multiple)
f4a46c
deviceValuator events.
f4a46c
f4a46c
The previous behavior would instead compose a sequence
f4a46c
of [state, buttonstate, state, keystate, valuator...]. This is not
f4a46c
protocol correct, and on top of that made the code extremely convoluted.
f4a46c
f4a46c
Fix this by streamlining: add both button and key into the deviceStateNotify
f4a46c
and then append the key state and button state, followed by the
f4a46c
valuators. Finally, the deviceValuator events contain up to 6 valuators
f4a46c
per event but we only ever sent through 3 at a time. Let's double that
f4a46c
troughput.
f4a46c
f4a46c
CVE-2024-0229, ZDI-CAN-22678
f4a46c
f4a46c
This vulnerability was discovered by:
f4a46c
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
f4a46c
---
f4a46c
 dix/enterleave.c | 121 ++++++++++++++++++++---------------------------
f4a46c
 1 file changed, 52 insertions(+), 69 deletions(-)
f4a46c
f4a46c
diff --git a/dix/enterleave.c b/dix/enterleave.c
f4a46c
index 17964b00a..7b7ba1098 100644
f4a46c
--- a/dix/enterleave.c
f4a46c
+++ b/dix/enterleave.c
f4a46c
@@ -615,9 +615,15 @@ FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v,
f4a46c
 
f4a46c
     ev->type = DeviceValuator;
f4a46c
     ev->deviceid = dev->id;
f4a46c
-    ev->num_valuators = nval < 3 ? nval : 3;
f4a46c
+    ev->num_valuators = nval < 6 ? nval : 6;
f4a46c
     ev->first_valuator = first;
f4a46c
     switch (ev->num_valuators) {
f4a46c
+    case 6:
f4a46c
+        ev->valuator2 = v->axisVal[first + 5];
f4a46c
+    case 5:
f4a46c
+        ev->valuator2 = v->axisVal[first + 4];
f4a46c
+    case 4:
f4a46c
+        ev->valuator2 = v->axisVal[first + 3];
f4a46c
     case 3:
f4a46c
         ev->valuator2 = v->axisVal[first + 2];
f4a46c
     case 2:
f4a46c
@@ -626,7 +632,6 @@ FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v,
f4a46c
         ev->valuator0 = v->axisVal[first];
f4a46c
         break;
f4a46c
     }
f4a46c
-    first += ev->num_valuators;
f4a46c
 }
f4a46c
 
f4a46c
 static void
f4a46c
@@ -646,7 +651,7 @@ FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k,
f4a46c
         ev->num_buttons = b->numButtons;
f4a46c
         memcpy((char *) ev->buttons, (char *) b->down, 4);
f4a46c
     }
f4a46c
-    else if (k) {
f4a46c
+    if (k) {
f4a46c
         ev->classes_reported |= (1 << KeyClass);
f4a46c
         ev->num_keys = k->xkbInfo->desc->max_key_code -
f4a46c
             k->xkbInfo->desc->min_key_code;
f4a46c
@@ -670,15 +675,26 @@ FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k,
f4a46c
     }
f4a46c
 }
f4a46c
 
f4a46c
-
f4a46c
+/**
f4a46c
+ * The device state notify event is split across multiple 32-byte events.
f4a46c
+ * The first one contains the first 32 button state bits, the first 32
f4a46c
+ * key state bits, and the first 3 valuator values.
f4a46c
+ *
f4a46c
+ * If a device has more than that, the server sends out:
f4a46c
+ * - one deviceButtonStateNotify for buttons 32 and above
f4a46c
+ * - one deviceKeyStateNotify for keys 32 and above
f4a46c
+ * - one deviceValuator event per 6 valuators above valuator 4
f4a46c
+ *
f4a46c
+ * All events but the last one have the deviceid binary ORed with MORE_EVENTS,
f4a46c
+ */
f4a46c
 static void
f4a46c
 DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win)
f4a46c
 {
f4a46c
+    /* deviceStateNotify, deviceKeyStateNotify, deviceButtonStateNotify
f4a46c
+     * and one deviceValuator for each 6 valuators */
f4a46c
+    deviceStateNotify sev[3 + (MAX_VALUATORS + 6)/6];
f4a46c
     int evcount = 1;
f4a46c
-    deviceStateNotify sev[6 + (MAX_VALUATORS + 2)/3];
f4a46c
-    deviceStateNotify *ev;
f4a46c
-    deviceKeyStateNotify *kev;
f4a46c
-    deviceButtonStateNotify *bev;
f4a46c
+    deviceStateNotify *ev = sev;
f4a46c
 
f4a46c
     KeyClassPtr k;
f4a46c
     ButtonClassPtr b;
f4a46c
@@ -691,82 +707,49 @@ DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win)
f4a46c
 
f4a46c
     if ((b = dev->button) != NULL) {
f4a46c
         nbuttons = b->numButtons;
f4a46c
-        if (nbuttons > 32)
f4a46c
+        if (nbuttons > 32) /* first 32 are encoded in deviceStateNotify */
f4a46c
             evcount++;
f4a46c
     }
f4a46c
     if ((k = dev->key) != NULL) {
f4a46c
         nkeys = k->xkbInfo->desc->max_key_code - k->xkbInfo->desc->min_key_code;
f4a46c
-        if (nkeys > 32)
f4a46c
+        if (nkeys > 32) /* first 32 are encoded in deviceStateNotify */
f4a46c
             evcount++;
f4a46c
-        if (nbuttons > 0) {
f4a46c
-            evcount++;
f4a46c
-        }
f4a46c
     }
f4a46c
     if ((v = dev->valuator) != NULL) {
f4a46c
         nval = v->numAxes;
f4a46c
-
f4a46c
-        if (nval > 3)
f4a46c
-            evcount++;
f4a46c
-        if (nval > 6) {
f4a46c
-            if (!(k && b))
f4a46c
-                evcount++;
f4a46c
-            if (nval > 9)
f4a46c
-                evcount += ((nval - 7) / 3);
f4a46c
-        }
f4a46c
+        /* first three are encoded in deviceStateNotify, then
f4a46c
+         * it's 6 per deviceValuator event */
f4a46c
+        evcount += ((nval - 3) + 6)/6;
f4a46c
     }
f4a46c
 
f4a46c
-    ev = sev;
f4a46c
-    FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first);
f4a46c
-
f4a46c
-    if (b != NULL) {
f4a46c
-        FixDeviceStateNotify(dev, ev++, NULL, b, v, first);
f4a46c
-        first += 3;
f4a46c
-        nval -= 3;
f4a46c
-        if (nbuttons > 32) {
f4a46c
-            (ev - 1)->deviceid |= MORE_EVENTS;
f4a46c
-            bev = (deviceButtonStateNotify *) ev++;
f4a46c
-            bev->type = DeviceButtonStateNotify;
f4a46c
-            bev->deviceid = dev->id;
f4a46c
-            memcpy((char *) &bev->buttons[4], (char *) &b->down[4],
f4a46c
-                   DOWN_LENGTH - 4);
f4a46c
-        }
f4a46c
-        if (nval > 0) {
f4a46c
-            (ev - 1)->deviceid |= MORE_EVENTS;
f4a46c
-            FixDeviceValuator(dev, (deviceValuator *) ev++, v, first);
f4a46c
-            first += 3;
f4a46c
-            nval -= 3;
f4a46c
-        }
f4a46c
+    BUG_RETURN(evcount <= ARRAY_SIZE(sev));
f4a46c
+
f4a46c
+    FixDeviceStateNotify(dev, ev, k, b, v, first);
f4a46c
+
f4a46c
+    if (b != NULL && nbuttons > 32) {
f4a46c
+        deviceButtonStateNotify *bev = (deviceButtonStateNotify *) ++ev;
f4a46c
+        (ev - 1)->deviceid |= MORE_EVENTS;
f4a46c
+        bev->type = DeviceButtonStateNotify;
f4a46c
+        bev->deviceid = dev->id;
f4a46c
+        memcpy((char *) &bev->buttons[4], (char *) &b->down[4],
f4a46c
+               DOWN_LENGTH - 4);
f4a46c
     }
f4a46c
 
f4a46c
-    if (k != NULL) {
f4a46c
-        FixDeviceStateNotify(dev, ev++, k, NULL, v, first);
f4a46c
-        first += 3;
f4a46c
-        nval -= 3;
f4a46c
-        if (nkeys > 32) {
f4a46c
-            (ev - 1)->deviceid |= MORE_EVENTS;
f4a46c
-            kev = (deviceKeyStateNotify *) ev++;
f4a46c
-            kev->type = DeviceKeyStateNotify;
f4a46c
-            kev->deviceid = dev->id;
f4a46c
-            memmove((char *) &kev->keys[0], (char *) &k->down[4], 28);
f4a46c
-        }
f4a46c
-        if (nval > 0) {
f4a46c
-            (ev - 1)->deviceid |= MORE_EVENTS;
f4a46c
-            FixDeviceValuator(dev, (deviceValuator *) ev++, v, first);
f4a46c
-            first += 3;
f4a46c
-            nval -= 3;
f4a46c
-        }
f4a46c
+    if (k != NULL && nkeys > 32) {
f4a46c
+        deviceKeyStateNotify *kev = (deviceKeyStateNotify *) ++ev;
f4a46c
+        (ev - 1)->deviceid |= MORE_EVENTS;
f4a46c
+        kev->type = DeviceKeyStateNotify;
f4a46c
+        kev->deviceid = dev->id;
f4a46c
+        memmove((char *) &kev->keys[0], (char *) &k->down[4], 28);
f4a46c
     }
f4a46c
 
f4a46c
+    first = 3;
f4a46c
+    nval -= 3;
f4a46c
     while (nval > 0) {
f4a46c
-        FixDeviceStateNotify(dev, ev++, NULL, NULL, v, first);
f4a46c
-        first += 3;
f4a46c
-        nval -= 3;
f4a46c
-        if (nval > 0) {
f4a46c
-            (ev - 1)->deviceid |= MORE_EVENTS;
f4a46c
-            FixDeviceValuator(dev, (deviceValuator *) ev++, v, first);
f4a46c
-            first += 3;
f4a46c
-            nval -= 3;
f4a46c
-        }
f4a46c
+        ev->deviceid |= MORE_EVENTS;
f4a46c
+        FixDeviceValuator(dev, (deviceValuator *) ++ev, v, first);
f4a46c
+        first += 6;
f4a46c
+        nval -= 6;
f4a46c
     }
f4a46c
 
f4a46c
     DeliverEventsToWindow(dev, win, (xEvent *) sev, evcount,
f4a46c
-- 
f4a46c
2.43.0
f4a46c