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

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