From 0d388fb26ad5eb414906e98f3c2399c4b591f41c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 13 Oct 2016 14:09:31 +1000 Subject: [PATCH] Fix crash when calling XListInputDevices on devices without classes --- ...o-can-return-0-even-without-an-error.patch | 98 +++++++++++++ ...s-don-t-touch-ndevices-in-case-of-er.patch | 132 ++++++++++++++++++ libXi.spec | 10 +- 3 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 0001-SizeClassInfo-can-return-0-even-without-an-error.patch create mode 100644 0002-XListInputDevices-don-t-touch-ndevices-in-case-of-er.patch diff --git a/0001-SizeClassInfo-can-return-0-even-without-an-error.patch b/0001-SizeClassInfo-can-return-0-even-without-an-error.patch new file mode 100644 index 0000000..b1dc325 --- /dev/null +++ b/0001-SizeClassInfo-can-return-0-even-without-an-error.patch @@ -0,0 +1,98 @@ +From 5010fe92202e98f3117be319aae268c5ab82c8ef Mon Sep 17 00:00:00 2001 +From: Niels Ole Salscheider +Date: Fri, 7 Oct 2016 21:46:44 +0200 +Subject: [PATCH v2 libXi 1/2] SizeClassInfo can return 0 even without an error + +Catch the error case separately. Commit 19a9cd607d added length checking to +SizeClassInfo but re-used the return value of 0 for an error. A device without +classes (as is initialized by xf86-input-libinput for tablets) can +legitimately return 0 and erroneously triggers an error. +Fix this by using a separate value for the error. + +Reproducible by calling XListInputDevices() with a tablet attached. + +This fixes a regression introduced in commit 19a9cd607d. + +Signed-off-by: Niels Ole Salscheider +Signed-off-by: Peter Hutterer +--- +Changes to v1: +- don't touch *size until we're sure. +- expand commit message + +Niels: +I left you as author and your signed-off-by since it's essentially your +patch with a minor change. + + src/XListDev.c | 24 +++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +diff --git a/src/XListDev.c b/src/XListDev.c +index f850cd0..e4bd3d5 100644 +--- a/src/XListDev.c ++++ b/src/XListDev.c +@@ -73,27 +73,28 @@ static int pad_to_xid(int base_size) + return ((base_size + padsize - 1)/padsize) * padsize; + } + +-static size_t +-SizeClassInfo(xAnyClassPtr *any, size_t len, 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 0; ++ return 1; + v = (xValuatorInfoPtr) *any; +- size += pad_to_xid(sizeof(XValuatorInfo) + ++ sz += pad_to_xid(sizeof(XValuatorInfo) + + (v->num_axes * sizeof(XAxisInfo))); + break; + } +@@ -101,11 +102,13 @@ SizeClassInfo(xAnyClassPtr *any, size_t len, int num_classes) + break; + } + if ((*any)->length > len) +- return 0; ++ return 1; + *any = (xAnyClassPtr) ((char *)(*any) + (*any)->length); + } + +- return size; ++ *size = sz; ++ ++ return 0; + } + + static void +@@ -220,8 +223,7 @@ XListInputDevices( + sav_any = any; + end = (char *)list + rlen; + for (i = 0; i < *ndevices; i++, list++) { +- s = SizeClassInfo(&any, end - (char *)any, (int)list->num_classes); +- if (!s) ++ if(SizeClassInfo(&any, end - (char *)any, (int)list->num_classes, &s)) + goto out; + size += s; + } +-- +2.7.4 + diff --git a/0002-XListInputDevices-don-t-touch-ndevices-in-case-of-er.patch b/0002-XListInputDevices-don-t-touch-ndevices-in-case-of-er.patch new file mode 100644 index 0000000..9b92cc4 --- /dev/null +++ b/0002-XListInputDevices-don-t-touch-ndevices-in-case-of-er.patch @@ -0,0 +1,132 @@ +From e821996b443e926a2cbab0eae38b33bad73e6060 Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Thu, 13 Oct 2016 13:33:11 +1000 +Subject: [PATCH v2 libXi 2/2] XListInputDevices: don't touch ndevices in case of + error + +We used to always set *ndevices to the number of devices returned by the +server. This magically worked because we pretty much never returned an error +except on faulty server or library implementations. With 19a9cd60 we now have +more chances of getting an error, so the polite thing is to just leave *ndevices +alone when we error out. + +Document it as such in the man page, just in case someone accidentally reads +it. + +Signed-off-by: Peter Hutterer +CC: Niels Ole Salscheider +--- +Changes to v1: +- Niels' first patch set ndevices to 0, this one leaves it untouched + + man/XListInputDevices.txt | 12 ++++++++++-- + src/XListDev.c | 21 ++++++++++++--------- + 2 files changed, 22 insertions(+), 11 deletions(-) + +diff --git a/man/XListInputDevices.txt b/man/XListInputDevices.txt +index 276660d..450f377 100644 +--- a/man/XListInputDevices.txt ++++ b/man/XListInputDevices.txt +@@ -220,5 +220,13 @@ DESCRIPTION + 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. +diff --git a/src/XListDev.c b/src/XListDev.c +index e4bd3d5..dda6011 100644 +--- a/src/XListDev.c ++++ b/src/XListDev.c +@@ -175,7 +175,7 @@ ParseClassInfo(xAnyClassPtr *any, XAnyClassPtr *Any, int num_classes) + XDeviceInfo * + XListInputDevices( + register Display *dpy, +- int *ndevices) ++ int *ndevices_return) + { + size_t s, size; + xListInputDevicesReq *req; +@@ -190,6 +190,7 @@ XListInputDevices( + int i; + unsigned long rlen; + XExtDisplayInfo *info = XInput_find_display(dpy); ++ int ndevices; + + LockDisplay(dpy); + if (_XiCheckExtInit(dpy, XInput_Initial_Release, info) == -1) +@@ -205,8 +206,8 @@ XListInputDevices( + 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); +@@ -219,17 +220,17 @@ XListInputDevices( + } + _XRead(dpy, (char *)list, rlen); + +- any = (xAnyClassPtr) ((char *)list + (*ndevices * sizeof(xDeviceInfo))); ++ any = (xAnyClassPtr) ((char *)list + (ndevices * sizeof(xDeviceInfo))); + sav_any = any; + end = (char *)list + rlen; +- for (i = 0; i < *ndevices; i++, list++) { ++ 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; +- for (i = 0, nptr = (unsigned char *)any; i < *ndevices; i++) { ++ for (i = 0, nptr = (unsigned char *)any; i < ndevices; i++) { + if (nptr >= Nptr) + goto out; + size += *nptr + 1; +@@ -245,10 +246,10 @@ XListInputDevices( + } + 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; +@@ -261,7 +262,7 @@ XListInputDevices( + 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); +@@ -270,6 +271,8 @@ XListInputDevices( + } + } + ++ *ndevices_return = ndevices; ++ + out: + XFree((char *)slist); + UnlockDisplay(dpy); +-- +2.7.4 + diff --git a/libXi.spec b/libXi.spec index 49d25c8..397195a 100644 --- a/libXi.spec +++ b/libXi.spec @@ -5,7 +5,7 @@ Summary: X.Org X11 libXi runtime library Name: libXi Version: 1.7.7 -Release: 1%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} +Release: 2%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} License: MIT Group: System Environment/Libraries URL: http://www.x.org @@ -17,6 +17,9 @@ Source1: make-git-snapshot.sh Source0: ftp://ftp.x.org/pub/individual/lib/%{name}-%{version}.tar.bz2 %endif +Patch01: 0001-SizeClassInfo-can-return-0-even-without-an-error.patch +Patch02: 0002-XListInputDevices-don-t-touch-ndevices-in-case-of-er.patch + BuildRequires: autoconf automake libtool BuildRequires: xorg-x11-util-macros BuildRequires: xorg-x11-proto-devel @@ -43,6 +46,8 @@ X.Org X11 libXi development package %prep %setup -q -n %{tarball}-%{?gitdate:%{gitdate}}%{!?gitdate:%{version}} +%patch01 -p1 +%patch02 -p1 %build autoreconf -v --install || exit 1 @@ -78,6 +83,9 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man3/*.3* %changelog +* Thu Oct 13 2016 Peter Hutterer 1.7.7-2 +- Fix crash when calling XListInputDevices on devices without classes + * Wed Oct 05 2016 Benjamin Tissoires 1.7.7-1 - libXi 1.7.7 - fixes CVE-2016-7945, CVE-2016-7946