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