Package: release.debian.org Severity: normal Tags: jessie User: release.debian....@packages.debian.org Usertags: pu
I think this is the last one for this round. It's also the one I'm least confident about. But it's been in sid and wheezy-lts for a while, and a couple of issues have already been found and fixed, so maybe it's ok. Cheers, Julien diff -u libxi-1.7.4/debian/changelog libxi-1.7.4/debian/changelog --- libxi-1.7.4/debian/changelog +++ libxi-1.7.4/debian/changelog @@ -1,3 +1,11 @@ +libxi (2:1.7.4-1+deb8u1) jessie; urgency=medium + + * Insufficient validation of data from the X server can cause out of + boundary memory access or endless loops. Addresses CVE-2016-7945 and + CVE-2016-7946. + + -- Julien Cristau <jcris...@debian.org> Sat, 28 Jan 2017 16:17:42 +0100 + libxi (2:1.7.4-1) unstable; urgency=low * New upstream release. only in patch2: unchanged: --- libxi-1.7.4.orig/man/XListInputDevices.txt +++ libxi-1.7.4/man/XListInputDevices.txt @@ -220,5 +220,13 @@ Floating. If the device is a master device, attached specifies the device ID of the master device this device is paired with. - To free the XDeviceInfo array created by XListInputDevices, use - XFreeDeviceList. +RETURN VALUE +------------ + + XListInputDevices returns a pointer to an array of XDeviceInfo + structs and sets ndevices_return to the number of elements in + that array. To free the XDeviceInfo array created by + XListInputDevices, use XFreeDeviceList. + + On error, XListInputDevices returns NULL and ndevices_return is + left unmodified. only in patch2: unchanged: --- libxi-1.7.4.orig/src/XGMotion.c +++ libxi-1.7.4/src/XGMotion.c @@ -114,7 +114,8 @@ } /* 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); only in patch2: unchanged: --- libxi-1.7.4.orig/src/XGetBMap.c +++ libxi-1.7.4/src/XGetBMap.c @@ -92,7 +92,8 @@ 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); only in patch2: unchanged: --- libxi-1.7.4.orig/src/XGetDCtl.c +++ libxi-1.7.4/src/XGetDCtl.c @@ -93,7 +93,8 @@ 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 @@ 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) only in patch2: unchanged: --- libxi-1.7.4.orig/src/XGetFCtl.c +++ libxi-1.7.4/src/XGetFCtl.c @@ -73,6 +73,7 @@ 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 @@ 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 @@ case StringFeedbackClass: { xStringFeedbackState *strf = (xStringFeedbackState *) f; + if ((char *)f + sizeof(*strf) > end) + goto out; size += sizeof(XStringFeedbackState) + (strf->num_syms_supported * sizeof(KeySym)); } only in patch2: unchanged: --- libxi-1.7.4.orig/src/XGetKMap.c +++ libxi-1.7.4/src/XGetKMap.c @@ -54,6 +54,7 @@ #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 @@ 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 only in patch2: unchanged: --- libxi-1.7.4.orig/src/XGetMMap.c +++ libxi-1.7.4/src/XGetMMap.c @@ -53,6 +53,7 @@ #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 @@ 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) only in patch2: unchanged: --- libxi-1.7.4.orig/src/XIQueryDevice.c +++ libxi-1.7.4/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,8 +44,9 @@ xXIQueryDeviceReq *req; xXIQueryDeviceReply reply; char *ptr; + char *end; int i; - char *buf; + char *buf = NULL; XExtDisplayInfo *extinfo = XInput_find_display(dpy); @@ -60,14 +62,25 @@ if (!_XReply(dpy, (xReply*) &reply, 0, xFalse)) goto error; - *ndevices_return = reply.num_devices; - info = Xmalloc((reply.num_devices + 1) * sizeof(XIDeviceInfo)); - if (!info) + if (reply.length < INT_MAX / 4) + { + *ndevices_return = reply.num_devices; + info = Xmalloc((reply.num_devices + 1) * sizeof(XIDeviceInfo)); + buf = Xmalloc(reply.length * 4); + } + else + { + *ndevices_return = 0; + info = NULL; + buf = NULL; + } + + if (!info || !buf) 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 +92,9 @@ 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 +103,23 @@ 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,7 +130,15 @@ SyncHandle(); return info; +error_loop: + while (--i >= 0) + { + Xfree(info[i].name); + Xfree(info[i].classes); + } error: + Xfree(info); + Xfree(buf); UnlockDisplay(dpy); SyncHandle(); *ndevices_return = -1; only in patch2: unchanged: --- libxi-1.7.4.orig/src/XListDev.c +++ libxi-1.7.4/src/XListDev.c @@ -73,35 +73,42 @@ return ((base_size + padsize - 1)/padsize) * padsize; } -static size_t -SizeClassInfo(xAnyClassPtr *any, int num_classes) +static int +SizeClassInfo(xAnyClassPtr *any, size_t len, int num_classes, size_t *size) { - int size = 0; int j; + size_t sz = 0; + for (j = 0; j < num_classes; j++) { switch ((*any)->class) { case KeyClass: - size += pad_to_xid(sizeof(XKeyInfo)); + sz += pad_to_xid(sizeof(XKeyInfo)); break; case ButtonClass: - size += pad_to_xid(sizeof(XButtonInfo)); + sz += pad_to_xid(sizeof(XButtonInfo)); break; case ValuatorClass: { xValuatorInfoPtr v; + if (len < sizeof(v)) + return 1; v = (xValuatorInfoPtr) *any; - size += pad_to_xid(sizeof(XValuatorInfo) + + sz += pad_to_xid(sizeof(XValuatorInfo) + (v->num_axes * sizeof(XAxisInfo))); break; } default: break; } + if ((*any)->length > len) + return 1; *any = (xAnyClassPtr) ((char *)(*any) + (*any)->length); } - return size; + *size = sz; + + return 0; } static void @@ -168,9 +175,9 @@ XDeviceInfo * XListInputDevices( register Display *dpy, - int *ndevices) + int *ndevices_return) { - size_t size; + size_t s, size; xListInputDevicesReq *req; xListInputDevicesReply rep; xDeviceInfo *list, *slist = NULL; @@ -178,10 +185,12 @@ XDeviceInfo *clist = NULL; xAnyClassPtr any, sav_any; XAnyClassPtr Any; + char *end = NULL; unsigned char *nptr, *Nptr; int i; unsigned long rlen; XExtDisplayInfo *info = XInput_find_display(dpy); + int ndevices; LockDisplay(dpy); if (_XiCheckExtInit(dpy, XInput_Initial_Release, info) == -1) @@ -197,8 +206,8 @@ return (XDeviceInfo *) NULL; } - if ((*ndevices = rep.ndevices)) { /* at least 1 input device */ - size = *ndevices * sizeof(XDeviceInfo); + if ((ndevices = rep.ndevices)) { /* at least 1 input device */ + size = ndevices * sizeof(XDeviceInfo); if (rep.length < (INT_MAX >> 2)) { rlen = rep.length << 2; /* multiply length by 4 */ slist = list = Xmalloc(rlen); @@ -211,18 +220,21 @@ } _XRead(dpy, (char *)list, rlen); - any = (xAnyClassPtr) ((char *)list + (*ndevices * sizeof(xDeviceInfo))); + any = (xAnyClassPtr) ((char *)list + (ndevices * sizeof(xDeviceInfo))); sav_any = any; - for (i = 0; i < *ndevices; i++, list++) { - size += SizeClassInfo(&any, (int)list->num_classes); + end = (char *)list + rlen; + for (i = 0; i < ndevices; i++, list++) { + if(SizeClassInfo(&any, end - (char *)any, (int)list->num_classes, &s)) + goto out; + size += s; } - Nptr = ((unsigned char *)list) + rlen + 1; - for (i = 0, nptr = (unsigned char *)any; i < *ndevices; i++) { + 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); @@ -234,10 +246,10 @@ } sclist = clist; Any = (XAnyClassPtr) ((char *)clist + - (*ndevices * sizeof(XDeviceInfo))); + (ndevices * sizeof(XDeviceInfo))); list = slist; any = sav_any; - for (i = 0; i < *ndevices; i++, list++, clist++) { + for (i = 0; i < ndevices; i++, list++, clist++) { clist->type = list->type; clist->id = list->id; clist->use = list->use; @@ -250,7 +262,7 @@ clist = sclist; nptr = (unsigned char *)any; Nptr = (unsigned char *)Any; - for (i = 0; i < *ndevices; i++, clist++) { + for (i = 0; i < ndevices; i++, clist++) { clist->name = (char *)Nptr; memcpy(Nptr, nptr + 1, *nptr); Nptr += (*nptr); @@ -259,6 +271,8 @@ } } + *ndevices_return = ndevices; + out: XFree((char *)slist); UnlockDisplay(dpy); only in patch2: unchanged: --- libxi-1.7.4.orig/src/XOpenDev.c +++ libxi-1.7.4/src/XOpenDev.c @@ -53,6 +53,7 @@ #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 @@ 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 */ only in patch2: unchanged: --- libxi-1.7.4.orig/src/XQueryDv.c +++ libxi-1.7.4/src/XQueryDv.c @@ -73,7 +73,7 @@ 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 @@ 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 @@ _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 @@ case ValuatorClass: { xValuatorState *v = (xValuatorState *) any; + if ((char *)any + sizeof(xValuatorState) > end) + goto out; size += (sizeof(XValuatorState) + (v->num_valuators * sizeof(int))); }
signature.asc
Description: PGP signature