Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[xsrc/netbsd-9]: xsrc/external/mit/xorg-server/dist/xkb Apply patch, requeste...



details:   https://anonhg.NetBSD.org/xsrc/rev/1ffd7744fa06
branches:  netbsd-9
changeset: 10636:1ffd7744fa06
user:      martin <martin%NetBSD.org@localhost>
date:      Sun Dec 06 10:18:02 2020 +0000

description:
Apply patch, requested by mrg in ticket #1141:

        external/mit/xorg-server/dist/xkb/xkb.c         apply patch

Apply upstream patches for:
 * CVE-2020-14360 / ZDI CAN 11572 XkbSetMap Out-Of-Bounds Access
 * CVE-2020-25712 / ZDI-CAN-11839 XkbSetDeviceInfo Heap-based Buffer Overflow

diffstat:

 external/mit/xorg-server/dist/xkb/xkb.c |  197 +++++++++++++++++++++++++++++--
 1 files changed, 180 insertions(+), 17 deletions(-)

diffs (truncated from 462 to 300 lines):

diff -r ef50ddea7cbb -r 1ffd7744fa06 external/mit/xorg-server/dist/xkb/xkb.c
--- a/external/mit/xorg-server/dist/xkb/xkb.c   Thu Oct 22 11:25:22 2020 +0000
+++ b/external/mit/xorg-server/dist/xkb/xkb.c   Sun Dec 06 10:18:02 2020 +0000
@@ -152,6 +152,19 @@
 #define        CHK_REQ_KEY_RANGE(err,first,num,r)  \
        CHK_REQ_KEY_RANGE2(err,first,num,r,client->errorValue,BadValue)
 
+static Bool
+_XkbCheckRequestBounds(ClientPtr client, void *stuff, void *from, void *to) {
+    char *cstuff = (char *)stuff;
+    char *cfrom = (char *)from;
+    char *cto = (char *)to;
+
+    return cfrom < cto &&
+           cfrom >= cstuff &&
+           cfrom < cstuff + ((size_t)client->req_len << 2) &&
+           cto >= cstuff &&
+           cto <= cstuff + ((size_t)client->req_len << 2);
+}
+
 /***====================================================================***/
 
 int
@@ -1587,7 +1600,7 @@
               XkbDescPtr xkb,
               xkbSetMapReq * req,
               xkbKeyTypeWireDesc ** wireRtrn,
-              int *nMapsRtrn, CARD8 *mapWidthRtrn)
+              int *nMapsRtrn, CARD8 *mapWidthRtrn, Bool doswap)
 {
     unsigned nMaps;
     register unsigned i, n;
@@ -1626,7 +1639,7 @@
     for (i = 0; i < req->nTypes; i++) {
         unsigned width;
 
-        if (client->swapped) {
+        if (client->swapped && doswap) {
             swaps(&wire->virtualMods);
         }
         n = i + req->firstType;
@@ -1653,7 +1666,7 @@
             mapWire = (xkbKTSetMapEntryWireDesc *) &wire[1];
             preWire = (xkbModsWireDesc *) &mapWire[wire->nMapEntries];
             for (n = 0; n < wire->nMapEntries; n++) {
-                if (client->swapped) {
+                if (client->swapped && doswap) {
                     swaps(&mapWire[n].virtualMods);
                 }
                 if (mapWire[n].realMods & (~wire->realMods)) {
@@ -1671,7 +1684,7 @@
                     return 0;
                 }
                 if (wire->preserve) {
-                    if (client->swapped) {
+                    if (client->swapped && doswap) {
                         swaps(&preWire[n].virtualMods);
                     }
                     if (preWire[n].realMods & (~mapWire[n].realMods)) {
@@ -1710,7 +1723,7 @@
              xkbSetMapReq * req,
              int nTypes,
              CARD8 *mapWidths,
-             CARD16 *symsPerKey, xkbSymMapWireDesc ** wireRtrn, int *errorRtrn)
+             CARD16 *symsPerKey, xkbSymMapWireDesc ** wireRtrn, int *errorRtrn, Bool doswap)
 {
     register unsigned i;
     XkbSymMapPtr map;
@@ -1724,7 +1737,7 @@
         KeySym *pSyms;
         register unsigned nG;
 
-        if (client->swapped) {
+        if (client->swapped && doswap) {
             swaps(&wire->nSyms);
         }
         nG = XkbNumGroups(wire->groupInfo);
@@ -2366,13 +2379,100 @@
     return (char *) wire;
 }
 
+#define _add_check_len(new) \
+    if (len > UINT32_MAX - (new) || len > req_len - (new)) goto bad; \
+    else len += new
+
+/**
+ * Check the length of the SetMap request
+ */
+static int
+_XkbSetMapCheckLength(xkbSetMapReq *req)
+{
+    size_t len = sz_xkbSetMapReq, req_len = req->length << 2;
+    xkbKeyTypeWireDesc *keytype;
+    xkbSymMapWireDesc *symmap;
+    BOOL preserve;
+    int i, map_count, nSyms;
+
+    if (req_len < len)
+        goto bad;
+    /* types */
+    if (req->present & XkbKeyTypesMask) {
+        keytype = (xkbKeyTypeWireDesc *)(req + 1);
+        for (i = 0; i < req->nTypes; i++) {
+            _add_check_len(XkbPaddedSize(sz_xkbKeyTypeWireDesc));
+            if (req->flags & XkbSetMapResizeTypes) {
+                _add_check_len(keytype->nMapEntries
+                               * sz_xkbKTSetMapEntryWireDesc);
+                preserve = keytype->preserve;
+                map_count = keytype->nMapEntries;
+                if (preserve) {
+                    _add_check_len(map_count * sz_xkbModsWireDesc);
+                }
+                keytype += 1;
+                keytype = (xkbKeyTypeWireDesc *)
+                          ((xkbKTSetMapEntryWireDesc *)keytype + map_count);
+                if (preserve)
+                    keytype = (xkbKeyTypeWireDesc *)
+                              ((xkbModsWireDesc *)keytype + map_count);
+            }
+        }
+    }
+    /* syms */
+    if (req->present & XkbKeySymsMask) {
+        symmap = (xkbSymMapWireDesc *)((char *)req + len);
+        for (i = 0; i < req->nKeySyms; i++) {
+            _add_check_len(sz_xkbSymMapWireDesc);
+            nSyms = symmap->nSyms;
+            _add_check_len(nSyms*sizeof(CARD32));
+            symmap += 1;
+            symmap = (xkbSymMapWireDesc *)((CARD32 *)symmap + nSyms);
+        }
+    }
+    /* actions */
+    if (req->present & XkbKeyActionsMask) {
+        _add_check_len(req->totalActs * sz_xkbActionWireDesc 
+                       + XkbPaddedSize(req->nKeyActs));
+    }
+    /* behaviours */
+    if (req->present & XkbKeyBehaviorsMask) {
+        _add_check_len(req->totalKeyBehaviors * sz_xkbBehaviorWireDesc);
+    }
+    /* vmods */
+    if (req->present & XkbVirtualModsMask) {
+        _add_check_len(XkbPaddedSize(Ones(req->virtualMods)));
+    }
+    /* explicit */
+    if (req->present & XkbExplicitComponentsMask) {
+        /* two bytes per non-zero explicit componen */
+        _add_check_len(XkbPaddedSize(req->totalKeyExplicit * sizeof(CARD16)));
+    }
+    /* modmap */
+    if (req->present & XkbModifierMapMask) {
+         /* two bytes per non-zero modmap component */
+        _add_check_len(XkbPaddedSize(req->totalModMapKeys * sizeof(CARD16)));
+    }
+    /* vmodmap */
+    if (req->present & XkbVirtualModMapMask) {
+        _add_check_len(req->totalVModMapKeys * sz_xkbVModMapWireDesc);
+    }
+    if (len == req_len)
+        return Success;
+bad:
+    ErrorF("[xkb] BOGUS LENGTH in SetMap: expected %ld got %ld\n",
+           len, req_len);
+    return BadLength;
+}
+
+
 /**
  * Check if the given request can be applied to the given device but don't
- * actually do anything..
+ * actually do anything, except swap values when client->swapped and doswap are both true.
  */
 static int
 _XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq * req,
-                 char *values)
+                 char *values, Bool doswap)
 {
     XkbSrvInfoPtr xkbi;
     XkbDescPtr xkb;
@@ -2409,10 +2509,13 @@
 
     if ((req->present & XkbKeyTypesMask) &&
         (!CheckKeyTypes(client, xkb, req, (xkbKeyTypeWireDesc **) &values,
-                        &nTypes, mapWidths))) {
+                        &nTypes, mapWidths, doswap))) {
         client->errorValue = nTypes;
         return BadValue;
     }
+    else {
+        nTypes = xkb->map->num_types;
+    }
 
     /* symsPerKey/mapWidths must be filled regardless of client-side flags */
     map = &xkb->map->key_sym_map[xkb->min_key_code];
@@ -2423,7 +2526,7 @@
         for (w = g = 0; g < ng; g++) {
             if (map->kt_index[g] >= (unsigned) nTypes) {
                 client->errorValue = _XkbErrCode4(0x13, i, g, map->kt_index[g]);
-                return 0;
+                return BadValue;
             }
             if (mapWidths[map->kt_index[g]] > w)
                 w = mapWidths[map->kt_index[g]];
@@ -2433,7 +2536,7 @@
 
     if ((req->present & XkbKeySymsMask) &&
         (!CheckKeySyms(client, xkb, req, nTypes, mapWidths, symsPerKey,
-                       (xkbSymMapWireDesc **) &values, &error))) {
+                       (xkbSymMapWireDesc **) &values, &error, doswap))) {
         client->errorValue = error;
         return BadValue;
     }
@@ -2617,12 +2720,17 @@
     CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
     CHK_MASK_LEGAL(0x01, stuff->present, XkbAllMapComponentsMask);
 
+    /* first verify the request length carefully */
+    rc = _XkbSetMapCheckLength(stuff);
+    if (rc != Success)
+        return rc;
+
     tmp = (char *) &stuff[1];
 
     /* Check if we can to the SetMap on the requested device. If this
        succeeds, do the same thing for all extension devices (if needed).
        If any of them fails, fail.  */
-    rc = _XkbSetMapChecks(client, dev, stuff, tmp);
+    rc = _XkbSetMapChecks(client, dev, stuff, tmp, TRUE);
 
     if (rc != Success)
         return rc;
@@ -2638,7 +2746,7 @@
                 rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
                               DixManageAccess);
                 if (rc == Success) {
-                    rc = _XkbSetMapChecks(client, other, stuff, tmp);
+                    rc = _XkbSetMapChecks(client, other, stuff, tmp, FALSE);
                     if (rc != Success)
                         return rc;
                 }
@@ -2652,7 +2760,7 @@
                 (other != master || dev != master->lastSlave))
                 continue;
 
-            rc = _XkbSetMapChecks(client, other, stuff, tmp);
+            rc = _XkbSetMapChecks(client, other, stuff, tmp, FALSE);
             if (rc != Success)
                 return rc;
         }
@@ -4036,6 +4144,8 @@
             client->errorValue = _XkbErrCode2(0x04, stuff->firstType);
             return BadAccess;
         }
+        if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + stuff->nTypes))
+            return BadLength;
         old = tmp;
         tmp = _XkbCheckAtoms(tmp, stuff->nTypes, client->swapped, &bad);
         if (!tmp) {
@@ -4065,6 +4175,8 @@
         }
         width = (CARD8 *) tmp;
         tmp = (CARD32 *) (((char *) tmp) + XkbPaddedSize(stuff->nKTLevels));
+        if (!_XkbCheckRequestBounds(client, stuff, width, tmp))
+            return BadLength;
         type = &xkb->map->types[stuff->firstKTLevel];
         for (i = 0; i < stuff->nKTLevels; i++, type++) {
             if (width[i] == 0)
@@ -4074,6 +4186,8 @@
                                                   type->num_levels, width[i]);
                 return BadMatch;
             }
+            if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + width[i]))
+                return BadLength;
             tmp = _XkbCheckAtoms(tmp, width[i], client->swapped, &bad);
             if (!tmp) {
                 client->errorValue = bad;
@@ -4086,6 +4200,9 @@
             client->errorValue = 0x08;
             return BadMatch;
         }
+        if (!_XkbCheckRequestBounds(client, stuff, tmp,
+                                    tmp + Ones(stuff->indicators)))
+            return BadLength;
         tmp = _XkbCheckMaskedAtoms(tmp, XkbNumIndicators, stuff->indicators,
                                    client->swapped, &bad);
         if (!tmp) {
@@ -4098,6 +4215,9 @@
             client->errorValue = 0x09;
             return BadMatch;
         }
+        if (!_XkbCheckRequestBounds(client, stuff, tmp,
+                                    tmp + Ones(stuff->virtualMods)))
+            return BadLength;
         tmp = _XkbCheckMaskedAtoms(tmp, XkbNumVirtualMods,
                                    (CARD32) stuff->virtualMods,
                                    client->swapped, &bad);
@@ -4111,6 +4231,9 @@
             client->errorValue = 0x0a;
             return BadMatch;



Home | Main Index | Thread Index | Old Index