Blame SOURCES/0002-xkb-swap-XkbSetDeviceInfo-and-XkbSetDeviceInfoCheck.patch

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