Fix crash when calling XListInputDevices on devices without classes

This commit is contained in:
Peter Hutterer 2016-10-13 14:09:31 +10:00
parent 4c3a6bbf3c
commit 0d388fb26a
3 changed files with 239 additions and 1 deletions

View File

@ -0,0 +1,98 @@
From 5010fe92202e98f3117be319aae268c5ab82c8ef Mon Sep 17 00:00:00 2001
From: Niels Ole Salscheider <niels_ole@salscheider-online.de>
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 <niels_ole@salscheider-online.de>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
---
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

View File

@ -0,0 +1,132 @@
From e821996b443e926a2cbab0eae38b33bad73e6060 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <peter.hutterer@who-t.net>
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 <peter.hutterer@who-t.net>
CC: Niels Ole Salscheider <niels_ole@salscheider-online.de>
---
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

View File

@ -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 <peter.hutterer@redhat.com> 1.7.7-2
- Fix crash when calling XListInputDevices on devices without classes
* Wed Oct 05 2016 Benjamin Tissoires <benjamin.tissoires@redhat.com> 1.7.7-1
- libXi 1.7.7
- fixes CVE-2016-7945, CVE-2016-7946