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

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