98518b3
From dd8caf39e9e15d8f302e54045dd08d8ebf1025dc Mon Sep 17 00:00:00 2001
98518b3
From: Peter Hutterer <peter.hutterer@who-t.net>
98518b3
Date: Tue, 5 Jul 2022 09:50:41 +1000
98518b3
Subject: [PATCH xserver 2/3] xkb: swap XkbSetDeviceInfo and
98518b3
 XkbSetDeviceInfoCheck
98518b3
98518b3
XKB often uses a FooCheck and Foo function pair, the former is supposed
98518b3
to check all values in the request and error out on BadLength,
98518b3
BadValue, etc. The latter is then called once we're confident the values
98518b3
are good (they may still fail on an individual device, but that's a
98518b3
different topic).
98518b3
98518b3
In the case of XkbSetDeviceInfo, those functions were incorrectly
98518b3
named, with XkbSetDeviceInfo ending up as the checker function and
98518b3
XkbSetDeviceInfoCheck as the setter function. As a result, the setter
98518b3
function was called before the checker function, accessing request
98518b3
data and modifying device state before we ensured that the data is
98518b3
valid.
98518b3
98518b3
In particular, the setter function relied on values being already
98518b3
byte-swapped. This in turn could lead to potential OOB memory access.
98518b3
98518b3
Fix this by correctly naming the functions and moving the length checks
98518b3
over to the checker function. These were added in 87c64fc5b0 to the
98518b3
wrong function, probably due to the incorrect naming.
98518b3
98518b3
Fixes ZDI-CAN 16070, CVE-2022-2320.
98518b3
98518b3
This vulnerability was discovered by:
98518b3
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
98518b3
98518b3
Introduced in c06e27b2f6fd9f7b9f827623a48876a225264132
98518b3
98518b3
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
98518b3
---
98518b3
 xkb/xkb.c | 46 +++++++++++++++++++++++++---------------------
98518b3
 1 file changed, 25 insertions(+), 21 deletions(-)
98518b3
98518b3
diff --git a/xkb/xkb.c b/xkb/xkb.c
98518b3
index 64e52611e..34b2c290b 100644
98518b3
--- a/xkb/xkb.c
98518b3
+++ b/xkb/xkb.c
98518b3
@@ -6550,7 +6550,8 @@ ProcXkbGetDeviceInfo(ClientPtr client)
98518b3
 static char *
98518b3
 CheckSetDeviceIndicators(char *wire,
98518b3
                          DeviceIntPtr dev,
98518b3
-                         int num, int *status_rtrn, ClientPtr client)
98518b3
+                         int num, int *status_rtrn, ClientPtr client,
98518b3
+                         xkbSetDeviceInfoReq * stuff)
98518b3
 {
98518b3
     xkbDeviceLedsWireDesc *ledWire;
98518b3
     int i;
98518b3
@@ -6558,6 +6559,11 @@ CheckSetDeviceIndicators(char *wire,
98518b3
 
98518b3
     ledWire = (xkbDeviceLedsWireDesc *) wire;
98518b3
     for (i = 0; i < num; i++) {
98518b3
+        if (!_XkbCheckRequestBounds(client, stuff, ledWire, ledWire + 1)) {
98518b3
+            *status_rtrn = BadLength;
98518b3
+            return (char *) ledWire;
98518b3
+        }
98518b3
+
98518b3
         if (client->swapped) {
98518b3
             swaps(&ledWire->ledClass);
98518b3
             swaps(&ledWire->ledID);
98518b3
@@ -6585,6 +6591,11 @@ CheckSetDeviceIndicators(char *wire,
98518b3
             atomWire = (CARD32 *) &ledWire[1];
98518b3
             if (nNames > 0) {
98518b3
                 for (n = 0; n < nNames; n++) {
98518b3
+                    if (!_XkbCheckRequestBounds(client, stuff, atomWire, atomWire + 1)) {
98518b3
+                        *status_rtrn = BadLength;
98518b3
+                        return (char *) atomWire;
98518b3
+                    }
98518b3
+
98518b3
                     if (client->swapped) {
98518b3
                         swapl(atomWire);
98518b3
                     }
98518b3
@@ -6596,6 +6607,10 @@ CheckSetDeviceIndicators(char *wire,
98518b3
             mapWire = (xkbIndicatorMapWireDesc *) atomWire;
98518b3
             if (nMaps > 0) {
98518b3
                 for (n = 0; n < nMaps; n++) {
98518b3
+                    if (!_XkbCheckRequestBounds(client, stuff, mapWire, mapWire + 1)) {
98518b3
+                        *status_rtrn = BadLength;
98518b3
+                        return (char *) mapWire;
98518b3
+                    }
98518b3
                     if (client->swapped) {
98518b3
                         swaps(&mapWire->virtualMods);
98518b3
                         swapl(&mapWire->ctrls);
98518b3
@@ -6647,11 +6662,6 @@ SetDeviceIndicators(char *wire,
98518b3
         xkbIndicatorMapWireDesc *mapWire;
98518b3
         XkbSrvLedInfoPtr sli;
98518b3
 
98518b3
-        if (!_XkbCheckRequestBounds(client, stuff, ledWire, ledWire + 1)) {
98518b3
-            *status_rtrn = BadLength;
98518b3
-            return (char *) ledWire;
98518b3
-        }
98518b3
-
98518b3
         namec = mapc = statec = 0;
98518b3
         sli = XkbFindSrvLedInfo(dev, ledWire->ledClass, ledWire->ledID,
98518b3
                                 XkbXI_IndicatorMapsMask);
98518b3
@@ -6670,10 +6680,6 @@ SetDeviceIndicators(char *wire,
98518b3
             memset((char *) sli->names, 0, XkbNumIndicators * sizeof(Atom));
98518b3
             for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
98518b3
                 if (ledWire->namesPresent & bit) {
98518b3
-                    if (!_XkbCheckRequestBounds(client, stuff, atomWire, atomWire + 1)) {
98518b3
-                        *status_rtrn = BadLength;
98518b3
-                        return (char *) atomWire;
98518b3
-                    }
98518b3
                     sli->names[n] = (Atom) *atomWire;
98518b3
                     if (sli->names[n] == None)
98518b3
                         ledWire->namesPresent &= ~bit;
98518b3
@@ -6691,10 +6697,6 @@ SetDeviceIndicators(char *wire,
98518b3
         if (ledWire->mapsPresent) {
98518b3
             for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
98518b3
                 if (ledWire->mapsPresent & bit) {
98518b3
-                    if (!_XkbCheckRequestBounds(client, stuff, mapWire, mapWire + 1)) {
98518b3
-                        *status_rtrn = BadLength;
98518b3
-                        return (char *) mapWire;
98518b3
-                    }
98518b3
                     sli->maps[n].flags = mapWire->flags;
98518b3
                     sli->maps[n].which_groups = mapWire->whichGroups;
98518b3
                     sli->maps[n].groups = mapWire->groups;
98518b3
@@ -6730,13 +6732,17 @@ SetDeviceIndicators(char *wire,
98518b3
 }
98518b3
 
98518b3
 static int
98518b3
-_XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev,
98518b3
+_XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev,
98518b3
                   xkbSetDeviceInfoReq * stuff)
98518b3
 {
98518b3
     char *wire;
98518b3
 
98518b3
     wire = (char *) &stuff[1];
98518b3
     if (stuff->change & XkbXI_ButtonActionsMask) {
98518b3
+        int sz = stuff->nBtns * SIZEOF(xkbActionWireDesc);
98518b3
+        if (!_XkbCheckRequestBounds(client, stuff, wire, (char *) wire + sz))
98518b3
+            return BadLength;
98518b3
+
98518b3
         if (!dev->button) {
98518b3
             client->errorValue = _XkbErrCode2(XkbErr_BadClass, ButtonClass);
98518b3
             return XkbKeyboardErrorCode;
98518b3
@@ -6747,13 +6753,13 @@ _XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev,
98518b3
                              dev->button->numButtons);
98518b3
             return BadMatch;
98518b3
         }
98518b3
-        wire += (stuff->nBtns * SIZEOF(xkbActionWireDesc));
98518b3
+        wire += sz;
98518b3
     }
98518b3
     if (stuff->change & XkbXI_IndicatorsMask) {
98518b3
         int status = Success;
98518b3
 
98518b3
         wire = CheckSetDeviceIndicators(wire, dev, stuff->nDeviceLedFBs,
98518b3
-                                        &status, client);
98518b3
+                                        &status, client, stuff);
98518b3
         if (status != Success)
98518b3
             return status;
98518b3
     }
98518b3
@@ -6764,8 +6770,8 @@ _XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev,
98518b3
 }
98518b3
 
98518b3
 static int
98518b3
-_XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev,
98518b3
-                       xkbSetDeviceInfoReq * stuff)
98518b3
+_XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev,
98518b3
+                  xkbSetDeviceInfoReq * stuff)
98518b3
 {
98518b3
     char *wire;
98518b3
     xkbExtensionDeviceNotify ed;
98518b3
@@ -6789,8 +6795,6 @@ _XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev,
98518b3
         if (stuff->firstBtn + stuff->nBtns > nBtns)
98518b3
             return BadValue;
98518b3
         sz = stuff->nBtns * SIZEOF(xkbActionWireDesc);
98518b3
-        if (!_XkbCheckRequestBounds(client, stuff, wire, (char *) wire + sz))
98518b3
-            return BadLength;
98518b3
         memcpy((char *) &acts[stuff->firstBtn], (char *) wire, sz);
98518b3
         wire += sz;
98518b3
         ed.reason |= XkbXI_ButtonActionsMask;
98518b3
-- 
98518b3
2.36.1
98518b3