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

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