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

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