|
|
4bbf3f |
From 06d1a032ee491547f7037c3ff042065dc2aeaa99 Mon Sep 17 00:00:00 2001
|
|
|
4bbf3f |
From: Matthieu Herrb <matthieu@herrb.eu>
|
|
|
4bbf3f |
Date: Thu, 12 Nov 2020 19:15:07 +0100
|
|
|
4bbf3f |
Subject: [PATCH xserver 2/2] Check SetMap request length carefully.
|
|
|
4bbf3f |
|
|
|
4bbf3f |
Avoid out of bounds memory accesses on too short request.
|
|
|
4bbf3f |
|
|
|
4bbf3f |
ZDI-CAN 11572 / CVE-2020-14360
|
|
|
4bbf3f |
|
|
|
4bbf3f |
This vulnerability was discovered by:
|
|
|
4bbf3f |
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
|
|
|
4bbf3f |
|
|
|
4bbf3f |
Signed-off-by: Matthieu Herrb <matthieu@herrb.eu>
|
|
|
4bbf3f |
(cherry picked from commit 446ff2d3177087b8173fa779fa5b77a2a128988b)
|
|
|
4bbf3f |
---
|
|
|
4bbf3f |
xkb/xkb.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
4bbf3f |
1 file changed, 92 insertions(+)
|
|
|
4bbf3f |
|
|
|
4bbf3f |
diff --git a/xkb/xkb.c b/xkb/xkb.c
|
|
|
4bbf3f |
index f162e8d83..68c59df02 100644
|
|
|
4bbf3f |
--- a/xkb/xkb.c
|
|
|
4bbf3f |
+++ b/xkb/xkb.c
|
|
|
4bbf3f |
@@ -2382,6 +2382,93 @@ SetVirtualModMap(XkbSrvInfoPtr xkbi,
|
|
|
4bbf3f |
return (char *) wire;
|
|
|
4bbf3f |
}
|
|
|
4bbf3f |
|
|
|
4bbf3f |
+#define _add_check_len(new) \
|
|
|
4bbf3f |
+ if (len > UINT32_MAX - (new) || len > req_len - (new)) goto bad; \
|
|
|
4bbf3f |
+ else len += new
|
|
|
4bbf3f |
+
|
|
|
4bbf3f |
+/**
|
|
|
4bbf3f |
+ * Check the length of the SetMap request
|
|
|
4bbf3f |
+ */
|
|
|
4bbf3f |
+static int
|
|
|
4bbf3f |
+_XkbSetMapCheckLength(xkbSetMapReq *req)
|
|
|
4bbf3f |
+{
|
|
|
4bbf3f |
+ size_t len = sz_xkbSetMapReq, req_len = req->length << 2;
|
|
|
4bbf3f |
+ xkbKeyTypeWireDesc *keytype;
|
|
|
4bbf3f |
+ xkbSymMapWireDesc *symmap;
|
|
|
4bbf3f |
+ BOOL preserve;
|
|
|
4bbf3f |
+ int i, map_count, nSyms;
|
|
|
4bbf3f |
+
|
|
|
4bbf3f |
+ if (req_len < len)
|
|
|
4bbf3f |
+ goto bad;
|
|
|
4bbf3f |
+ /* types */
|
|
|
4bbf3f |
+ if (req->present & XkbKeyTypesMask) {
|
|
|
4bbf3f |
+ keytype = (xkbKeyTypeWireDesc *)(req + 1);
|
|
|
4bbf3f |
+ for (i = 0; i < req->nTypes; i++) {
|
|
|
4bbf3f |
+ _add_check_len(XkbPaddedSize(sz_xkbKeyTypeWireDesc));
|
|
|
4bbf3f |
+ if (req->flags & XkbSetMapResizeTypes) {
|
|
|
4bbf3f |
+ _add_check_len(keytype->nMapEntries
|
|
|
4bbf3f |
+ * sz_xkbKTSetMapEntryWireDesc);
|
|
|
4bbf3f |
+ preserve = keytype->preserve;
|
|
|
4bbf3f |
+ map_count = keytype->nMapEntries;
|
|
|
4bbf3f |
+ if (preserve) {
|
|
|
4bbf3f |
+ _add_check_len(map_count * sz_xkbModsWireDesc);
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ keytype += 1;
|
|
|
4bbf3f |
+ keytype = (xkbKeyTypeWireDesc *)
|
|
|
4bbf3f |
+ ((xkbKTSetMapEntryWireDesc *)keytype + map_count);
|
|
|
4bbf3f |
+ if (preserve)
|
|
|
4bbf3f |
+ keytype = (xkbKeyTypeWireDesc *)
|
|
|
4bbf3f |
+ ((xkbModsWireDesc *)keytype + map_count);
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ /* syms */
|
|
|
4bbf3f |
+ if (req->present & XkbKeySymsMask) {
|
|
|
4bbf3f |
+ symmap = (xkbSymMapWireDesc *)((char *)req + len);
|
|
|
4bbf3f |
+ for (i = 0; i < req->nKeySyms; i++) {
|
|
|
4bbf3f |
+ _add_check_len(sz_xkbSymMapWireDesc);
|
|
|
4bbf3f |
+ nSyms = symmap->nSyms;
|
|
|
4bbf3f |
+ _add_check_len(nSyms*sizeof(CARD32));
|
|
|
4bbf3f |
+ symmap += 1;
|
|
|
4bbf3f |
+ symmap = (xkbSymMapWireDesc *)((CARD32 *)symmap + nSyms);
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ /* actions */
|
|
|
4bbf3f |
+ if (req->present & XkbKeyActionsMask) {
|
|
|
4bbf3f |
+ _add_check_len(req->totalActs * sz_xkbActionWireDesc
|
|
|
4bbf3f |
+ + XkbPaddedSize(req->nKeyActs));
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ /* behaviours */
|
|
|
4bbf3f |
+ if (req->present & XkbKeyBehaviorsMask) {
|
|
|
4bbf3f |
+ _add_check_len(req->totalKeyBehaviors * sz_xkbBehaviorWireDesc);
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ /* vmods */
|
|
|
4bbf3f |
+ if (req->present & XkbVirtualModsMask) {
|
|
|
4bbf3f |
+ _add_check_len(XkbPaddedSize(Ones(req->virtualMods)));
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ /* explicit */
|
|
|
4bbf3f |
+ if (req->present & XkbExplicitComponentsMask) {
|
|
|
4bbf3f |
+ /* two bytes per non-zero explicit componen */
|
|
|
4bbf3f |
+ _add_check_len(XkbPaddedSize(req->totalKeyExplicit * sizeof(CARD16)));
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ /* modmap */
|
|
|
4bbf3f |
+ if (req->present & XkbModifierMapMask) {
|
|
|
4bbf3f |
+ /* two bytes per non-zero modmap component */
|
|
|
4bbf3f |
+ _add_check_len(XkbPaddedSize(req->totalModMapKeys * sizeof(CARD16)));
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ /* vmodmap */
|
|
|
4bbf3f |
+ if (req->present & XkbVirtualModMapMask) {
|
|
|
4bbf3f |
+ _add_check_len(req->totalVModMapKeys * sz_xkbVModMapWireDesc);
|
|
|
4bbf3f |
+ }
|
|
|
4bbf3f |
+ if (len == req_len)
|
|
|
4bbf3f |
+ return Success;
|
|
|
4bbf3f |
+bad:
|
|
|
4bbf3f |
+ ErrorF("[xkb] BOGUS LENGTH in SetMap: expected %ld got %ld\n",
|
|
|
4bbf3f |
+ len, req_len);
|
|
|
4bbf3f |
+ return BadLength;
|
|
|
4bbf3f |
+}
|
|
|
4bbf3f |
+
|
|
|
4bbf3f |
+
|
|
|
4bbf3f |
/**
|
|
|
4bbf3f |
* Check if the given request can be applied to the given device but don't
|
|
|
4bbf3f |
* actually do anything..
|
|
|
4bbf3f |
@@ -2639,6 +2726,11 @@ ProcXkbSetMap(ClientPtr client)
|
|
|
4bbf3f |
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
|
|
|
4bbf3f |
CHK_MASK_LEGAL(0x01, stuff->present, XkbAllMapComponentsMask);
|
|
|
4bbf3f |
|
|
|
4bbf3f |
+ /* first verify the request length carefully */
|
|
|
4bbf3f |
+ rc = _XkbSetMapCheckLength(stuff);
|
|
|
4bbf3f |
+ if (rc != Success)
|
|
|
4bbf3f |
+ return rc;
|
|
|
4bbf3f |
+
|
|
|
4bbf3f |
tmp = (char *) &stuff[1];
|
|
|
4bbf3f |
|
|
|
4bbf3f |
/* Check if we can to the SetMap on the requested device. If this
|
|
|
4bbf3f |
--
|
|
|
4bbf3f |
2.28.0
|
|
|
4bbf3f |
|