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

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