diff options
author | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2020-12-10 10:24:29 +0100 |
---|---|---|
committer | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2021-01-15 16:38:11 +0100 |
commit | 4eba4f53ad8c62c27c12835e58184d66121ff636 (patch) | |
tree | c1a6376444443773b4b0673cbaa5d2ca9ad383e6 /nx-X11 | |
parent | 89b37de7c923337cc403480e6db44000bdd0674a (diff) | |
download | nx-libs-4eba4f53ad8c62c27c12835e58184d66121ff636.tar.gz nx-libs-4eba4f53ad8c62c27c12835e58184d66121ff636.tar.bz2 nx-libs-4eba4f53ad8c62c27c12835e58184d66121ff636.zip |
CVE-2020-14360: Check SetMap request length carefully.
Backported from X.org:
From 446ff2d3177087b8173fa779fa5b77a2a128988b Mon Sep 17 00:00:00 2001
From: Matthieu Herrb <matthieu@herrb.eu>
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.
Diffstat (limited to 'nx-X11')
-rw-r--r-- | nx-X11/programs/Xserver/xkb/xkb.c | 91 |
1 files changed, 91 insertions, 0 deletions
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; |