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

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