diff mbox

[3/8] gnu: libxi: Fix CVE-2016-{7945,7946}.

Message ID 44b2405c697c7961d3184bfa66d9b7324d1bcb36.1475690088.git.leo@famulari.name
State New
Headers show

Commit Message

Leo Famulari Oct. 5, 2016, 5:55 p.m. UTC
* gnu/packages/patches/libxi-CVE-2016-7945-CVE-2016-7946.patch: New file.
* gnu/local.mk (dist_patch_DATA): Add it.
* gnu/packages/xorg.scm (libxi)[replacement]: New field.
(libxi/fixed): New variable.
---
 gnu/local.mk                                       |   1 +
 .../libxi-CVE-2016-7945-CVE-2016-7946.patch        | 420 +++++++++++++++++++++
 gnu/packages/xorg.scm                              |   8 +
 3 files changed, 429 insertions(+)
 create mode 100644 gnu/packages/patches/libxi-CVE-2016-7945-CVE-2016-7946.patch
diff mbox

Patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 9e875de..e092c84 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -672,6 +672,7 @@  dist_patch_DATA =						\
   %D%/packages/patches/libx11-CVE-2016-7942.patch		\
   %D%/packages/patches/libx11-CVE-2016-7943.patch		\
   %D%/packages/patches/libxfixes-CVE-2016-7944.patch		\
+  %D%/packages/patches/libxi-CVE-2016-7945-CVE-2016-7946.patch	\
   %D%/packages/patches/libxslt-generated-ids.patch		\
   %D%/packages/patches/lirc-localstatedir.patch			\
   %D%/packages/patches/llvm-for-extempore.patch			\
diff --git a/gnu/packages/patches/libxi-CVE-2016-7945-CVE-2016-7946.patch b/gnu/packages/patches/libxi-CVE-2016-7945-CVE-2016-7946.patch
new file mode 100644
index 0000000..ca899e3
--- /dev/null
+++ b/gnu/packages/patches/libxi-CVE-2016-7945-CVE-2016-7946.patch
@@ -0,0 +1,420 @@ 
+Fix CVE-2016-7945:
+
+https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-7945
+
+Patch copied from upstream source repository:
+
+https://cgit.freedesktop.org/xorg/lib/libXi/commit/?id=19a9cd607de73947fcfb104682f203ffe4e1f4e5
+
+From 19a9cd607de73947fcfb104682f203ffe4e1f4e5 Mon Sep 17 00:00:00 2001
+From: Tobias Stoeckmann <tobias@stoeckmann.org>
+Date: Sun, 25 Sep 2016 22:31:34 +0200
+Subject: [PATCH] Properly validate server responses.
+
+By validating length fields from server responses, out of boundary
+accesses and endless loops can be mitigated.
+
+Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
+Reviewed-by: Matthieu Herrb <matthieu@herrb.eu>
+---
+ src/XGMotion.c      |  3 ++-
+ src/XGetBMap.c      |  3 ++-
+ src/XGetDCtl.c      |  6 ++++--
+ src/XGetFCtl.c      |  7 ++++++-
+ src/XGetKMap.c      | 14 +++++++++++---
+ src/XGetMMap.c      | 11 +++++++++--
+ src/XIQueryDevice.c | 36 ++++++++++++++++++++++++++++++++++--
+ src/XListDev.c      | 21 +++++++++++++++------
+ src/XOpenDev.c      | 13 ++++++++++---
+ src/XQueryDv.c      |  8 ++++++--
+ 10 files changed, 99 insertions(+), 23 deletions(-)
+
+diff --git a/src/XGMotion.c b/src/XGMotion.c
+index 7785843..9433e29 100644
+--- a/src/XGMotion.c
++++ b/src/XGMotion.c
+@@ -114,7 +114,8 @@ XGetDeviceMotionEvents(
+     }
+     /* rep.axes is a CARD8, so assume max number of axes for bounds check */
+     if (rep.nEvents <
+-	(INT_MAX / (sizeof(XDeviceTimeCoord) + (UCHAR_MAX * sizeof(int))))) {
++	(INT_MAX / (sizeof(XDeviceTimeCoord) + (UCHAR_MAX * sizeof(int)))) &&
++	rep.nEvents * (rep.axes + 1) <= rep.length) {
+ 	size_t bsize = rep.nEvents *
+ 	    (sizeof(XDeviceTimeCoord) + (rep.axes * sizeof(int)));
+ 	bufp = Xmalloc(bsize);
+diff --git a/src/XGetBMap.c b/src/XGetBMap.c
+index 002daba..13bb8c6 100644
+--- a/src/XGetBMap.c
++++ b/src/XGetBMap.c
+@@ -92,7 +92,8 @@ XGetDeviceButtonMapping(
+ 
+     status = _XReply(dpy, (xReply *) & rep, 0, xFalse);
+     if (status == 1) {
+-	if (rep.length <= (sizeof(mapping) >> 2)) {
++	if (rep.length <= (sizeof(mapping) >> 2) &&
++	    rep.nElts <= (rep.length << 2)) {
+ 	    unsigned long nbytes = rep.length << 2;
+ 	    _XRead(dpy, (char *)mapping, nbytes);
+ 
+diff --git a/src/XGetDCtl.c b/src/XGetDCtl.c
+index c5d3b53..7f6b396 100644
+--- a/src/XGetDCtl.c
++++ b/src/XGetDCtl.c
+@@ -93,7 +93,8 @@ XGetDeviceControl(
+     if (rep.length > 0) {
+ 	unsigned long nbytes;
+ 	size_t size = 0;
+-	if (rep.length < (INT_MAX >> 2)) {
++	if (rep.length < (INT_MAX >> 2) &&
++	    (rep.length << 2) >= sizeof(xDeviceState)) {
+ 	    nbytes = (unsigned long) rep.length << 2;
+ 	    d = Xmalloc(nbytes);
+ 	}
+@@ -117,7 +118,8 @@ XGetDeviceControl(
+ 	    size_t val_size;
+ 
+ 	    r = (xDeviceResolutionState *) d;
+-	    if (r->num_valuators >= (INT_MAX / (3 * sizeof(int))))
++	    if (sizeof(xDeviceResolutionState) > nbytes ||
++		r->num_valuators >= (INT_MAX / (3 * sizeof(int))))
+ 		goto out;
+ 	    val_size = 3 * sizeof(int) * r->num_valuators;
+ 	    if ((sizeof(xDeviceResolutionState) + val_size) > nbytes)
+diff --git a/src/XGetFCtl.c b/src/XGetFCtl.c
+index 7fd6d0e..82dcc64 100644
+--- a/src/XGetFCtl.c
++++ b/src/XGetFCtl.c
+@@ -73,6 +73,7 @@ XGetFeedbackControl(
+     XFeedbackState *Sav = NULL;
+     xFeedbackState *f = NULL;
+     xFeedbackState *sav = NULL;
++    char *end = NULL;
+     xGetFeedbackControlReq *req;
+     xGetFeedbackControlReply rep;
+     XExtDisplayInfo *info = XInput_find_display(dpy);
+@@ -105,10 +106,12 @@ XGetFeedbackControl(
+ 	    goto out;
+ 	}
+ 	sav = f;
++	end = (char *)f + nbytes;
+ 	_XRead(dpy, (char *)f, nbytes);
+ 
+ 	for (i = 0; i < *num_feedbacks; i++) {
+-	    if (f->length > nbytes)
++	    if ((char *)f + sizeof(*f) > end ||
++	        f->length == 0 || f->length > nbytes)
+ 		goto out;
+ 	    nbytes -= f->length;
+ 
+@@ -125,6 +128,8 @@ XGetFeedbackControl(
+ 	    case StringFeedbackClass:
+ 	    {
+ 		xStringFeedbackState *strf = (xStringFeedbackState *) f;
++		if ((char *)f + sizeof(*strf) > end)
++		    goto out;
+ 		size += sizeof(XStringFeedbackState) +
+ 		    (strf->num_syms_supported * sizeof(KeySym));
+ 	    }
+diff --git a/src/XGetKMap.c b/src/XGetKMap.c
+index 0540ce4..008a72b 100644
+--- a/src/XGetKMap.c
++++ b/src/XGetKMap.c
+@@ -54,6 +54,7 @@ SOFTWARE.
+ #include <config.h>
+ #endif
+ 
++#include <limits.h>
+ #include <X11/extensions/XI.h>
+ #include <X11/extensions/XIproto.h>
+ #include <X11/Xlibint.h>
+@@ -93,9 +94,16 @@ XGetDeviceKeyMapping(register Display * dpy, XDevice * dev,
+ 	return (KeySym *) NULL;
+     }
+     if (rep.length > 0) {
+-	*syms_per_code = rep.keySymsPerKeyCode;
+-	nbytes = (long)rep.length << 2;
+-	mapping = (KeySym *) Xmalloc((unsigned)nbytes);
++	if (rep.length < INT_MAX >> 2 &&
++	    rep.length == rep.keySymsPerKeyCode * keycount) {
++	    *syms_per_code = rep.keySymsPerKeyCode;
++	    nbytes = (long)rep.length << 2;
++	    mapping = (KeySym *) Xmalloc((unsigned)nbytes);
++	} else {
++	    *syms_per_code = 0;
++	    nbytes = 0;
++	    mapping = NULL;
++	}
+ 	if (mapping)
+ 	    _XRead(dpy, (char *)mapping, nbytes);
+ 	else
+diff --git a/src/XGetMMap.c b/src/XGetMMap.c
+index 246698c..33c114f 100644
+--- a/src/XGetMMap.c
++++ b/src/XGetMMap.c
+@@ -53,6 +53,7 @@ SOFTWARE.
+ #include <config.h>
+ #endif
+ 
++#include <limits.h>
+ #include <X11/extensions/XI.h>
+ #include <X11/extensions/XIproto.h>
+ #include <X11/Xlibint.h>
+@@ -85,8 +86,14 @@ XGetDeviceModifierMapping(
+ 	SyncHandle();
+ 	return (XModifierKeymap *) NULL;
+     }
+-    nbytes = (unsigned long)rep.length << 2;
+-    res = (XModifierKeymap *) Xmalloc(sizeof(XModifierKeymap));
++    if (rep.length < (INT_MAX >> 2) &&
++	rep.numKeyPerModifier == rep.length >> 1) {
++	nbytes = (unsigned long)rep.length << 2;
++	res = (XModifierKeymap *) Xmalloc(sizeof(XModifierKeymap));
++    } else {
++	nbytes = 0;
++	res = NULL;
++    }
+     if (res) {
+ 	res->modifiermap = (KeyCode *) Xmalloc(nbytes);
+ 	if (res->modifiermap)
+diff --git a/src/XIQueryDevice.c b/src/XIQueryDevice.c
+index fb8504f..a457cd6 100644
+--- a/src/XIQueryDevice.c
++++ b/src/XIQueryDevice.c
+@@ -26,6 +26,7 @@
+ #include <config.h>
+ #endif
+ 
++#include <limits.h>
+ #include <stdint.h>
+ #include <X11/Xlibint.h>
+ #include <X11/extensions/XI2proto.h>
+@@ -43,6 +44,7 @@ XIQueryDevice(Display *dpy, int deviceid, int *ndevices_return)
+     xXIQueryDeviceReq   *req;
+     xXIQueryDeviceReply reply;
+     char                *ptr;
++    char                *end;
+     int                 i;
+     char                *buf;
+ 
+@@ -60,14 +62,24 @@ XIQueryDevice(Display *dpy, int deviceid, int *ndevices_return)
+     if (!_XReply(dpy, (xReply*) &reply, 0, xFalse))
+         goto error;
+ 
+-    *ndevices_return = reply.num_devices;
+-    info = Xmalloc((reply.num_devices + 1) * sizeof(XIDeviceInfo));
++    if (reply.length < INT_MAX / 4)
++    {
++	*ndevices_return = reply.num_devices;
++	info = Xmalloc((reply.num_devices + 1) * sizeof(XIDeviceInfo));
++    }
++    else
++    {
++	*ndevices_return = 0;
++	info = NULL;
++    }
++
+     if (!info)
+         goto error;
+ 
+     buf = Xmalloc(reply.length * 4);
+     _XRead(dpy, buf, reply.length * 4);
+     ptr = buf;
++    end = buf + reply.length * 4;
+ 
+     /* info is a null-terminated array */
+     info[reply.num_devices].name = NULL;
+@@ -79,6 +91,9 @@ XIQueryDevice(Display *dpy, int deviceid, int *ndevices_return)
+         XIDeviceInfo    *lib = &info[i];
+         xXIDeviceInfo   *wire = (xXIDeviceInfo*)ptr;
+ 
++        if (ptr + sizeof(xXIDeviceInfo) > end)
++            goto error_loop;
++
+         lib->deviceid    = wire->deviceid;
+         lib->use         = wire->use;
+         lib->attachment  = wire->attachment;
+@@ -87,12 +102,23 @@ XIQueryDevice(Display *dpy, int deviceid, int *ndevices_return)
+ 
+         ptr += sizeof(xXIDeviceInfo);
+ 
++        if (ptr + wire->name_len > end)
++            goto error_loop;
++
+         lib->name = Xcalloc(wire->name_len + 1, 1);
++        if (lib->name == NULL)
++            goto error_loop;
+         strncpy(lib->name, ptr, wire->name_len);
++        lib->name[wire->name_len] = '\0';
+         ptr += ((wire->name_len + 3)/4) * 4;
+ 
+         sz = size_classes((xXIAnyInfo*)ptr, nclasses);
+         lib->classes = Xmalloc(sz);
++        if (lib->classes == NULL)
++        {
++            Xfree(lib->name);
++            goto error_loop;
++        }
+         ptr += copy_classes(lib, (xXIAnyInfo*)ptr, &nclasses);
+         /* We skip over unused classes */
+         lib->num_classes = nclasses;
+@@ -103,6 +129,12 @@ XIQueryDevice(Display *dpy, int deviceid, int *ndevices_return)
+     SyncHandle();
+     return info;
+ 
++error_loop:
++    while (--i >= 0)
++    {
++        Xfree(info[i].name);
++        Xfree(info[i].classes);
++    }
+ error:
+     UnlockDisplay(dpy);
+ error_unlocked:
+diff --git a/src/XListDev.c b/src/XListDev.c
+index b85ff3c..f850cd0 100644
+--- a/src/XListDev.c
++++ b/src/XListDev.c
+@@ -74,7 +74,7 @@ static int pad_to_xid(int base_size)
+ }
+ 
+ static size_t
+-SizeClassInfo(xAnyClassPtr *any, int num_classes)
++SizeClassInfo(xAnyClassPtr *any, size_t len, int num_classes)
+ {
+     int size = 0;
+     int j;
+@@ -90,6 +90,8 @@ SizeClassInfo(xAnyClassPtr *any, int num_classes)
+                 {
+                     xValuatorInfoPtr v;
+ 
++                    if (len < sizeof(v))
++                        return 0;
+                     v = (xValuatorInfoPtr) *any;
+                     size += pad_to_xid(sizeof(XValuatorInfo) +
+                         (v->num_axes * sizeof(XAxisInfo)));
+@@ -98,6 +100,8 @@ SizeClassInfo(xAnyClassPtr *any, int num_classes)
+             default:
+                 break;
+         }
++        if ((*any)->length > len)
++            return 0;
+         *any = (xAnyClassPtr) ((char *)(*any) + (*any)->length);
+     }
+ 
+@@ -170,7 +174,7 @@ XListInputDevices(
+     register Display	*dpy,
+     int			*ndevices)
+ {
+-    size_t size;
++    size_t s, size;
+     xListInputDevicesReq *req;
+     xListInputDevicesReply rep;
+     xDeviceInfo *list, *slist = NULL;
+@@ -178,6 +182,7 @@ XListInputDevices(
+     XDeviceInfo *clist = NULL;
+     xAnyClassPtr any, sav_any;
+     XAnyClassPtr Any;
++    char *end = NULL;
+     unsigned char *nptr, *Nptr;
+     int i;
+     unsigned long rlen;
+@@ -213,16 +218,20 @@ XListInputDevices(
+ 
+ 	any = (xAnyClassPtr) ((char *)list + (*ndevices * sizeof(xDeviceInfo)));
+ 	sav_any = any;
++	end = (char *)list + rlen;
+ 	for (i = 0; i < *ndevices; i++, list++) {
+-            size += SizeClassInfo(&any, (int)list->num_classes);
++            s = SizeClassInfo(&any, end - (char *)any, (int)list->num_classes);
++            if (!s)
++                goto out;
++            size += s;
+ 	}
+ 
+-	Nptr = ((unsigned char *)list) + rlen + 1;
++	Nptr = ((unsigned char *)list) + rlen;
+ 	for (i = 0, nptr = (unsigned char *)any; i < *ndevices; i++) {
++	    if (nptr >= Nptr)
++		goto out;
+ 	    size += *nptr + 1;
+ 	    nptr += (*nptr + 1);
+-	    if (nptr > Nptr)
+-		goto out;
+ 	}
+ 
+ 	clist = (XDeviceInfoPtr) Xmalloc(size);
+diff --git a/src/XOpenDev.c b/src/XOpenDev.c
+index 029dec2..4b3c460 100644
+--- a/src/XOpenDev.c
++++ b/src/XOpenDev.c
+@@ -53,6 +53,7 @@ SOFTWARE.
+ #include <config.h>
+ #endif
+ 
++#include <limits.h>
+ #include <X11/extensions/XI.h>
+ #include <X11/extensions/XIproto.h>
+ #include <X11/Xlibint.h>
+@@ -86,9 +87,15 @@ XOpenDevice(
+ 	return (XDevice *) NULL;
+     }
+ 
+-    rlen = rep.length << 2;
+-    dev = (XDevice *) Xmalloc(sizeof(XDevice) + rep.num_classes *
+-			      sizeof(XInputClassInfo));
++    if (rep.length < INT_MAX >> 2 &&
++	(rep.length << 2) >= rep.num_classes * sizeof(xInputClassInfo)) {
++	rlen = rep.length << 2;
++	dev = (XDevice *) Xmalloc(sizeof(XDevice) + rep.num_classes *
++				  sizeof(XInputClassInfo));
++    } else {
++	rlen = 0;
++	dev = NULL;
++    }
+     if (dev) {
+ 	int dlen;	/* data length */
+ 
+diff --git a/src/XQueryDv.c b/src/XQueryDv.c
+index de1c0e5..7ee2272 100644
+--- a/src/XQueryDv.c
++++ b/src/XQueryDv.c
+@@ -73,7 +73,7 @@ XQueryDeviceState(
+     xQueryDeviceStateReply rep;
+     XDeviceState *state = NULL;
+     XInputClass *any, *Any;
+-    char *data = NULL;
++    char *data = NULL, *end = NULL;
+     XExtDisplayInfo *info = XInput_find_display(dpy);
+ 
+     LockDisplay(dpy);
+@@ -92,6 +92,7 @@ XQueryDeviceState(
+ 	if (rep.length < (INT_MAX >> 2)) {
+ 	    rlen = (unsigned long) rep.length << 2;
+ 	    data = Xmalloc(rlen);
++	    end = data + rlen;
+ 	}
+ 	if (!data) {
+ 	    _XEatDataWords(dpy, rep.length);
+@@ -100,7 +101,8 @@ XQueryDeviceState(
+ 	_XRead(dpy, data, rlen);
+ 
+ 	for (i = 0, any = (XInputClass *) data; i < (int)rep.num_classes; i++) {
+-	    if (any->length > rlen)
++	    if ((char *)any + sizeof(XInputClass) > end ||
++		any->length == 0 || any->length > rlen)
+ 		goto out;
+ 	    rlen -= any->length;
+ 
+@@ -114,6 +116,8 @@ XQueryDeviceState(
+ 	    case ValuatorClass:
+ 	    {
+ 		xValuatorState *v = (xValuatorState *) any;
++		if ((char *)any + sizeof(xValuatorState) > end)
++		    goto out;
+ 		size += (sizeof(XValuatorState) +
+ 			 (v->num_valuators * sizeof(int)));
+ 	    }
+-- 
+2.10.1
+
diff --git a/gnu/packages/xorg.scm b/gnu/packages/xorg.scm
index 5bd3aee..ce0c4f9 100644
--- a/gnu/packages/xorg.scm
+++ b/gnu/packages/xorg.scm
@@ -4896,6 +4896,7 @@  new API's in libXft, or the legacy API's in libX11.")
 (define-public libxi
   (package
     (name "libxi")
+    (replacement libxi/fixed)
     (version "1.7.6")
     (source
       (origin
@@ -4922,6 +4923,13 @@  new API's in libXft, or the legacy API's in libX11.")
     (description "Library for the XInput Extension to the X11 protocol.")
     (license license:x11)))
 
+(define libxi/fixed
+  (package
+    (inherit libxi)
+    (source (origin
+              (inherit (package-source libxi))
+              (patches (search-patches
+                         "libxi-CVE-2016-7945-CVE-2016-7946.patch"))))))
 
 (define-public libxrandr
   (package