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

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