summaryrefslogtreecommitdiff
path: root/src/XIQueryDevice.c
diff options
context:
space:
mode:
authorTobias Stoeckmann <tobias@stoeckmann.org>2016-09-25 22:31:34 +0200
committerMatthieu Herrb <matthieu@herrb.eu>2016-09-25 22:31:34 +0200
commit19a9cd607de73947fcfb104682f203ffe4e1f4e5 (patch)
tree5fbb89ac3f543a3b25d9eb9e85def0e19b174e9e /src/XIQueryDevice.c
parent2286282f965064176b3b1492646c6e2e0f4ab7dd (diff)
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>
Diffstat (limited to 'src/XIQueryDevice.c')
-rw-r--r--src/XIQueryDevice.c36
1 files changed, 34 insertions, 2 deletions
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: