From d5a3b440130257e08f7e507eae711885b4f4db50 Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Thu, 10 Dec 2020 10:24:29 +0100 Subject: CVE-2020-14360: Check SetMap request length carefully. Backported from X.org: From 446ff2d3177087b8173fa779fa5b77a2a128988b Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Thu, 12 Nov 2020 19:15:07 +0100 Subject: [PATCH] Check SetMap request length carefully. Avoid out of bounds memory accesses on too short request. ZDI-CAN 11572 / CVE-2020-14360 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative Fixes ArcticaProject/nx-libs#972. --- nx-X11/programs/Xserver/xkb/xkb.c | 91 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'nx-X11/programs/Xserver/xkb') diff --git a/nx-X11/programs/Xserver/xkb/xkb.c b/nx-X11/programs/Xserver/xkb/xkb.c index 7b392fa09..654b33fe7 100644 --- a/nx-X11/programs/Xserver/xkb/xkb.c +++ b/nx-X11/programs/Xserver/xkb/xkb.c @@ -2202,6 +2202,92 @@ XkbServerMapPtr srv = xkbi->desc->server; 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; +} + int ProcXkbSetMap(ClientPtr client) { @@ -2225,6 +2311,11 @@ ProcXkbSetMap(ClientPtr client) CHK_KBD_DEVICE(dev,stuff->deviceSpec); CHK_MASK_LEGAL(0x01,stuff->present,XkbAllMapComponentsMask); + /* first verify the request length carefully */ + rc = _XkbSetMapCheckLength(stuff); + if (rc != Success) + return rc; + XkbSetCauseXkbReq(&cause,X_kbSetMap,client); xkbi= dev->key->xkbInfo; xkb = xkbi->desc; -- cgit v1.2.3