untrusted comment: verify with openbsd-80-base.pub RWSMSt0erHTctU257K7wp5Yzgbtl651cnFeHPffcymEkiw9BZA5X4+EJtVrqLNIOS8GIScgt0TEghlIBbvgP2261N9u71U/UHgo= OpenBSD 8.0 errata 007, November 5, 2026: Multiple security issues in X.Org X client libraries. CVE-2026-88806 CVE-2026-88807 CVE-2026-93541 CVE-2026-93542 CVE-2026-93543 CVE-2026-93544 CVE-2026-93545 CVE-2026-94281 CVE-2026-94282 CVE-2026-94283 CVE-2026-94284 CVE-2026-94285 CVE-2026-94286 CVE-2026-94287 CVE-2026-109088 CVE-2026-109089 CVE-2026-109090 Apply by doing: signify -Vep /etc/signify/openbsd-80-base.pub -x 007_xlibs.patch.sig \ -m - | (cd /usr/xenocara && patch -p0) And then rebuild and install affected libraries: cd /usr/xenocara/lib/libX11 make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper build cd /usr/xenocara/lib/libXi make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper build cd /usr/xenocara/lib/libXpm make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper build cd /usr/xenocara/lib/libXrender make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper build cd /usr/xenocara/lib/libXtst make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper build Index: lib/libX11/modules/im/ximcp/imDefIm.c =================================================================== RCS file: /cvs/xenocara/lib/libX11/modules/im/ximcp/imDefIm.c,v diff -u -p -r1.14 imDefIm.c --- lib/libX11/modules/im/ximcp/imDefIm.c 30 Apr 2025 17:26:10 -0000 1.14 +++ lib/libX11/modules/im/ximcp/imDefIm.c 23 Oct 2026 23:02:42 -0000 @@ -867,6 +867,15 @@ _XimOpen( im->private.proto.imid = buf_s[0]; /* imid */ + if (len < (INT16)(XIM_HEADER_SIZE + sizeof(CARD16))) { + if (reply != preply) + Xfree(preply); + return False; + } + /* remaining OPEN_REPLY bytes after imid; read by _XimGetAttributeID */ + im->private.proto.open_attr_length = + (CARD16)((size_t)len - XIM_HEADER_SIZE - sizeof(CARD16)); + if (!(_XimGetAttributeID(im, &buf_s[1]))) { if(reply != preply) Xfree(preply); Index: lib/libX11/modules/im/ximcp/imDefLkup.c =================================================================== RCS file: /cvs/xenocara/lib/libX11/modules/im/ximcp/imDefLkup.c,v diff -u -p -r1.13 imDefLkup.c --- lib/libX11/modules/im/ximcp/imDefLkup.c 8 May 2026 13:21:23 -0000 1.13 +++ lib/libX11/modules/im/ximcp/imDefLkup.c 23 Oct 2026 23:02:42 -0000 @@ -498,10 +498,12 @@ _XimForwardEventCallback( static Bool _XimRegisterTriggerkey( Xim im, - XPointer buf) + XPointer buf, + size_t buf_len) { CARD32 *buf_l = (CARD32 *)buf; - CARD32 len; + size_t len; + size_t remaining; CARD32 *key; if (IS_DYNAMIC_EVENT_FLOW(im)) /* already Dynamic event flow mode */ @@ -510,9 +512,11 @@ _XimRegisterTriggerkey( /* * register onkeylist */ - - len = buf_l[0]; /* length of on-keys */ - len += sizeof(INT32); /* sizeof length of on-keys */ + if (buf_len < sizeof(CARD32)) + return False; + if ((size_t)buf_l[0] > buf_len - sizeof(CARD32)) + return False; + len = (size_t)buf_l[0] + sizeof(CARD32); if (!(key = Xmalloc(len))) { _XimError(im, 0, XIM_BadAlloc, (INT16)0, (CARD16)0, (char *)NULL); @@ -526,10 +530,13 @@ _XimRegisterTriggerkey( /* * register offkeylist */ - + remaining = buf_len - len; + if (remaining < sizeof(CARD32)) + return False; buf_l = (CARD32 *)((char *)buf + len); - len = buf_l[0]; /* length of off-keys */ - len += sizeof(INT32); /* sizeof length of off-keys */ + if ((size_t)buf_l[0] > remaining - sizeof(CARD32)) + return False; + len = (size_t)buf_l[0] + sizeof(CARD32); if (!(key = Xmalloc(len))) { _XimError(im, 0, XIM_BadAlloc, (INT16)0, (CARD16)0, (char *)NULL); @@ -551,8 +558,12 @@ _XimRegisterTriggerKeysCallback( { CARD16 *buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE); Xim im = (Xim)call_data; + size_t payload_len; - (void )_XimRegisterTriggerkey(im, (XPointer)&buf_s[2]); + if (len < (INT16)(XIM_HEADER_SIZE + 2 * sizeof(CARD16))) + return True; + payload_len = (size_t)len - XIM_HEADER_SIZE - 2 * sizeof(CARD16); + (void)_XimRegisterTriggerkey(im, (XPointer)&buf_s[2], payload_len); return True; } Index: lib/libX11/modules/im/ximcp/imRmAttr.c =================================================================== RCS file: /cvs/xenocara/lib/libX11/modules/im/ximcp/imRmAttr.c,v diff -u -p -r1.13 imRmAttr.c --- lib/libX11/modules/im/ximcp/imRmAttr.c 4 Aug 2024 17:15:57 -0000 1.13 +++ lib/libX11/modules/im/ximcp/imRmAttr.c 23 Oct 2026 23:02:42 -0000 @@ -1399,6 +1399,7 @@ _XimCountNumberOfAttr( unsigned int *names_len) { unsigned int n; + unsigned int entry_size; CARD16 len; CARD16 min_len = sizeof(CARD16) /* sizeof attribute ID */ + sizeof(CARD16) /* sizeof type of value */ @@ -1411,10 +1412,15 @@ _XimCountNumberOfAttr( if (len > (total - min_len)) { return 0; } + entry_size = (unsigned int)min_len + (unsigned int)len + + (unsigned int)XIM_PAD(len + 2); + + if (entry_size > total) + return 0; + *names_len += (len + 1); - len += (min_len + XIM_PAD(len + 2)); - total -= len; - attr = (CARD16 *)((char *)attr + len); + total -= entry_size; + attr = (CARD16 *)((char *)attr + entry_size); n++; } return n; @@ -1433,6 +1439,8 @@ _XimGetAttributeID( char **values; register int i; CARD16 len; + CARD16 *buf_s = buf; + size_t remain = (size_t)im->private.proto.open_attr_length; CARD16 min_len = sizeof(CARD16) /* sizeof attribute ID */ + sizeof(CARD16) /* sizeof type of value */ + sizeof(INT16); /* sizeof length of attr */ @@ -1440,6 +1448,10 @@ _XimGetAttributeID( * IM attribute ID */ + if (remain < sizeof(CARD16) || + (size_t)buf[0] > remain - sizeof(CARD16)) + return False; + if (!(n = _XimCountNumberOfAttr(buf[0], &buf[1], &names_len))) return False; @@ -1484,6 +1496,14 @@ _XimGetAttributeID( /* * IC attribute ID */ + remain -= sizeof(CARD16) + (size_t)buf_s[0]; + buf = (CARD16 *)((char *)(buf_s + 1) + buf_s[0]); + + if (remain < (2 * sizeof(CARD16))) + return False; + + if ((size_t)buf[0] > remain - (2 * sizeof(CARD16))) + return False; if (!(n = _XimCountNumberOfAttr(buf[0], &buf[2], &names_len))) return False; Index: lib/libX11/modules/lc/gen/lcGenConv.c =================================================================== RCS file: /cvs/xenocara/lib/libX11/modules/lc/gen/lcGenConv.c,v diff -u -p -r1.12 lcGenConv.c --- lib/libX11/modules/lc/gen/lcGenConv.c 10 Jul 2024 08:04:08 -0000 1.12 +++ lib/libX11/modules/lc/gen/lcGenConv.c 23 Oct 2026 23:02:42 -0000 @@ -321,7 +321,8 @@ mb_parse_codeset( static CodeSet byteM_parse_codeset( XLCd lcd, - const char *inbufptr) + const char *inbufptr, + int remaining_bytes) { unsigned char ch; CodeSet codeset; @@ -340,6 +341,8 @@ byteM_parse_codeset( byteM = codeset->byteM; if (codeset->side != XlcNONE || byteM == NULL) continue; + if (codeset->length > remaining_bytes) + continue; for (j = 0; j < codeset->length; j++) { ch = *((const unsigned char *)(inbufptr + j)); @@ -800,7 +803,7 @@ mbstowcs_org( } /* next mb char data for byteM ? */ - if ((codeset = byteM_parse_codeset(lcd, (inbufptr - 1)))) + if ((codeset = byteM_parse_codeset(lcd, (inbufptr - 1), (*from_left) + 1))) goto next_mb_char; /* next mb char data for GL or GR side ? */ @@ -1691,7 +1694,7 @@ mbstostr( } /* next char data : byteM ? */ - if ((codeset = byteM_parse_codeset(lcd, (inbufptr - 1)))) + if ((codeset = byteM_parse_codeset(lcd, (inbufptr - 1), (*from_left) + 1))) goto next_mb_char; /* next char data : GL or GR side ? */ @@ -1802,7 +1805,7 @@ mbtocs( } /* next mb char data for byteM ? */ - if ((codeset = byteM_parse_codeset(lcd, (inbufptr - 1)))) + if ((codeset = byteM_parse_codeset(lcd, (inbufptr - 1), (*from_left) + 1))) goto next_mb_char; /* next mb char data for GL or GR side ? */ Index: lib/libX11/src/xkb/XKBGetMap.c =================================================================== RCS file: /cvs/xenocara/lib/libX11/src/xkb/XKBGetMap.c,v diff -u -p -r1.9 XKBGetMap.c --- lib/libX11/src/xkb/XKBGetMap.c 3 Oct 2023 15:55:58 -0000 1.9 +++ lib/libX11/src/xkb/XKBGetMap.c 23 Oct 2026 23:02:42 -0000 @@ -253,6 +253,9 @@ _XkbReadKeyActions(XkbReadBufferPtr buf, if ((nKeyActs = rep->nKeyActs) > 0) { XkbSymMapPtr symMap; + if (((int) rep->firstKeyAct + rep->nKeyActs) > (info->max_key_code + 1)) + return BadLength; + if (nKeyActs < sizeof numDescBuf) numDesc = numDescBuf; else Index: lib/libX11/src/xlibi18n/XimintP.h =================================================================== RCS file: /cvs/xenocara/lib/libX11/src/xlibi18n/XimintP.h,v diff -u -p -r1.10 XimintP.h --- lib/libX11/src/xlibi18n/XimintP.h 8 May 2026 13:21:24 -0000 1.10 +++ lib/libX11/src/xlibi18n/XimintP.h 23 Oct 2026 23:02:42 -0000 @@ -115,7 +115,7 @@ typedef struct _XimProtoPrivateRec { Window im_window; XIMID imid; - CARD16 unused; + CARD16 open_attr_length; XIMStyles *default_styles; CARD32 *im_onkeylist; CARD32 *im_offkeylist; Index: lib/libXi/src/XExtInt.c =================================================================== RCS file: /cvs/xenocara/lib/libXi/src/XExtInt.c,v diff -u -p -r1.20 XExtInt.c --- lib/libXi/src/XExtInt.c 12 Jul 2026 10:19:32 -0000 1.20 +++ lib/libXi/src/XExtInt.c 23 Oct 2026 23:02:42 -0000 @@ -56,6 +56,7 @@ SOFTWARE. #include #include +#include #include #include #include @@ -73,8 +74,8 @@ SOFTWARE. #define DONT_ENQUEUE False #define FP1616toDBL(x) ((x) * 1.0 / (1 << 16)) -int copy_classes(XIDeviceInfo *to, xXIAnyInfo* from, int *nclasses); -int size_classes(xXIAnyInfo* from, int nclasses); +int copy_classes(XIDeviceInfo *to, xXIAnyInfo* from, int *nclasses, char *end); +int size_classes(xXIAnyInfo* from, int nclasses, char *end); static XExtensionInfo *xinput_info; static const char *xinput_extension_name = INAME; @@ -110,28 +111,33 @@ static Bool XInputCopyCookie( ); static int -wireToDeviceEvent(xXIDeviceEvent *in, XGenericEventCookie* out); +wireToDeviceEvent(xXIDeviceEvent *in, size_t event_bytes, + XGenericEventCookie* out); static int -wireToDeviceChangedEvent(xXIDeviceChangedEvent *in, XGenericEventCookie *cookie); +wireToDeviceChangedEvent(xXIDeviceChangedEvent *in, size_t event_bytes, + XGenericEventCookie *cookie); static int -wireToHierarchyChangedEvent(xXIHierarchyEvent *in, XGenericEventCookie *cookie); +wireToHierarchyChangedEvent(xXIHierarchyEvent *in, size_t event_bytes, + XGenericEventCookie *cookie); static int -wireToRawEvent(XExtDisplayInfo *info, xXIRawEvent *in, XGenericEventCookie *cookie); +wireToRawEvent(XExtDisplayInfo *info, xXIRawEvent *in, size_t event_bytes, + XGenericEventCookie *cookie); static int -wireToEnterLeave(xXIEnterEvent *in, XGenericEventCookie *cookie); +wireToEnterLeave(xXIEnterEvent *in, size_t event_bytes, + XGenericEventCookie *cookie); static int wireToPropertyEvent(xXIPropertyEvent *in, XGenericEventCookie *cookie); static int -wireToTouchOwnershipEvent(xXITouchOwnershipEvent *in, +wireToTouchOwnershipEvent(xXITouchOwnershipEvent *in, size_t event_bytes, XGenericEventCookie *cookie); static int -wireToBarrierEvent(xXIBarrierEvent *in, +wireToBarrierEvent(xXIBarrierEvent *in, size_t event_bytes, XGenericEventCookie *cookie); static int -wireToPinchEvent(xXIGesturePinchEvent *in, +wireToPinchEvent(xXIGesturePinchEvent *in, size_t event_bytes, XGenericEventCookie *cookie); static int -wireToSwipeEvent(xXIGestureSwipeEvent *in, +wireToSwipeEvent(xXIGestureSwipeEvent *in, size_t event_bytes, XGenericEventCookie *cookie); static /* const */ XEvent emptyevent; @@ -985,7 +991,9 @@ XInputWireToCookie( case XI_TouchUpdate: case XI_TouchEnd: *cookie = *(XGenericEventCookie*)save; - if (!wireToDeviceEvent((xXIDeviceEvent*)event, cookie)) + if (!wireToDeviceEvent((xXIDeviceEvent*)event, + sizeof(xEvent) + ((size_t)ge->length * 4), + cookie)) { printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", ge->evtype); @@ -994,7 +1002,9 @@ XInputWireToCookie( return ENQUEUE_EVENT; case XI_DeviceChanged: *cookie = *(XGenericEventCookie*)save; - if (!wireToDeviceChangedEvent((xXIDeviceChangedEvent*)event, cookie)) + if (!wireToDeviceChangedEvent((xXIDeviceChangedEvent*)event, + sizeof(xEvent) + ((size_t)ge->length * 4), + cookie)) { printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", ge->evtype); @@ -1003,7 +1013,9 @@ XInputWireToCookie( return ENQUEUE_EVENT; case XI_HierarchyChanged: *cookie = *(XGenericEventCookie*)save; - if (!wireToHierarchyChangedEvent((xXIHierarchyEvent*)event, cookie)) + if (!wireToHierarchyChangedEvent((xXIHierarchyEvent*)event, + sizeof(xEvent) + ((size_t)ge->length * 4), + cookie)) { printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", ge->evtype); @@ -1013,6 +1025,7 @@ XInputWireToCookie( case XI_TouchOwnership: *cookie = *(XGenericEventCookie*)save; if (!wireToTouchOwnershipEvent((xXITouchOwnershipEvent*)event, + sizeof(xEvent) + ((size_t)ge->length * 4), cookie)) { printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", @@ -1030,7 +1043,9 @@ XInputWireToCookie( case XI_RawTouchUpdate: case XI_RawTouchEnd: *cookie = *(XGenericEventCookie*)save; - if (!wireToRawEvent(info, (xXIRawEvent*)event, cookie)) + if (!wireToRawEvent(info, (xXIRawEvent*)event, + sizeof(xEvent) + ((size_t)ge->length * 4), + cookie)) { printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", ge->evtype); @@ -1042,7 +1057,9 @@ XInputWireToCookie( case XI_FocusIn: case XI_FocusOut: *cookie = *(XGenericEventCookie*)save; - if (!wireToEnterLeave((xXIEnterEvent*)event, cookie)) + if (!wireToEnterLeave((xXIEnterEvent*)event, + sizeof(xEvent) + ((size_t)ge->length * 4), + cookie)) { printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", ge->evtype); @@ -1061,7 +1078,9 @@ XInputWireToCookie( case XI_BarrierHit: case XI_BarrierLeave: *cookie = *(XGenericEventCookie*)save; - if (!wireToBarrierEvent((xXIBarrierEvent*)event, cookie)) + if (!wireToBarrierEvent((xXIBarrierEvent*)event, + sizeof(xEvent) + ((size_t)ge->length * 4), + cookie)) { printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", ge->evtype); @@ -1072,7 +1091,9 @@ XInputWireToCookie( case XI_GesturePinchUpdate: case XI_GesturePinchEnd: *cookie = *(XGenericEventCookie*)save; - if (!wireToPinchEvent((xXIGesturePinchEvent*)event, cookie)) + if (!wireToPinchEvent((xXIGesturePinchEvent*)event, + sizeof(xEvent) + ((size_t)ge->length * 4), + cookie)) { printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", ge->evtype); @@ -1083,7 +1104,9 @@ XInputWireToCookie( case XI_GestureSwipeUpdate: case XI_GestureSwipeEnd: *cookie = *(XGenericEventCookie*)save; - if (!wireToSwipeEvent((xXIGestureSwipeEvent*)event, cookie)) + if (!wireToSwipeEvent((xXIGestureSwipeEvent*)event, + sizeof(xEvent) + ((size_t)ge->length * 4), + cookie)) { printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", ge->evtype); @@ -1609,17 +1632,36 @@ XInputCopyCookie(Display *dpy, XGenericE } static int -wireToDeviceEvent(xXIDeviceEvent *in, XGenericEventCookie* cookie) +wireToDeviceEvent(xXIDeviceEvent *in, size_t event_bytes, + XGenericEventCookie* cookie) { int len, i; unsigned char *ptr; void *ptr_lib; FP3232 *values; XIDeviceEvent *out; + size_t buttons_bytes, valuators_bytes, trailing, values_bytes; + int nvals; + + if (event_bytes < sizeof(*in)) + return 0; - ptr = (unsigned char*)&in[1] + in->buttons_len * 4; + buttons_bytes = (size_t) in->buttons_len * 4; + valuators_bytes = (size_t) in->valuators_len * 4; + trailing = event_bytes - sizeof(*in); - len = sizeDeviceEvent(in->buttons_len * 4, in->valuators_len * 4, ptr); + if (buttons_bytes > trailing || + valuators_bytes > trailing - buttons_bytes) + return 0; + + /* valuator mask follows the button mask */ + ptr = (unsigned char *) &in[1] + buttons_bytes; + nvals = count_bits(ptr, (int) valuators_bytes); + values_bytes = (size_t) nvals * sizeof(FP3232); + if (values_bytes > trailing - buttons_bytes - valuators_bytes) + return 0; + + len = sizeDeviceEvent((int) buttons_bytes, (int) valuators_bytes, ptr); cookie->data = ptr_lib = malloc(len); if (!ptr_lib) @@ -1652,26 +1694,25 @@ wireToDeviceEvent(xXIDeviceEvent *in, XG out->group.locked = in->group.locked_group; out->group.latched = in->group.latched_group; out->group.effective = in->group.effective_group; - out->buttons.mask_len = in->buttons_len * 4; - out->valuators.mask_len = in->valuators_len * 4; + out->buttons.mask_len = (int) buttons_bytes; + out->valuators.mask_len = (int) valuators_bytes; out->buttons.mask = next_block(&ptr_lib, out->buttons.mask_len); /* buttons */ ptr = (unsigned char*)&in[1]; memcpy(out->buttons.mask, ptr, out->buttons.mask_len); - ptr += in->buttons_len * 4; + ptr += buttons_bytes; /* valuators */ out->valuators.mask = next_block(&ptr_lib, out->valuators.mask_len); memcpy(out->valuators.mask, ptr, out->valuators.mask_len); - ptr += in->valuators_len * 4; + ptr += valuators_bytes; - len = count_bits(out->valuators.mask, out->valuators.mask_len); - out->valuators.values = next_block(&ptr_lib, len * sizeof(double)); + out->valuators.values = next_block(&ptr_lib, nvals * sizeof(double)); values = (FP3232*)ptr; - for (i = 0; i < len; i++, values++) + for (i = 0; i < nvals; i++, values++) { out->valuators.values[i] = values->integral; out->valuators.values[i] += ((double)values->frac / (1 << 16) / (1 << 16)); @@ -1681,20 +1722,126 @@ wireToDeviceEvent(xXIDeviceEvent *in, XG return 1; } +static int +validate_class_header(char *ptr, char *end, xXIAnyInfo **any_out) +{ + xXIAnyInfo *any; + size_t remaining; + + if (ptr + sizeof(xXIAnyInfo) > end) + return -1; + + any = (xXIAnyInfo *) ptr; + if (any->length == 0) + return -1; + + remaining = (size_t) (end - ptr); + if ((size_t) any->length > remaining / 4) + return -1; + + *any_out = any; + + return 0; +} + +/* + * Reject class records whose type-specific header or payload cannot fit in + * the declared wire length (length is in 4-byte units). + */ +static int +validate_class_payload(xXIAnyInfo *any) +{ + size_t cls_len = (size_t) any->length * 4; + + switch (any->type) { + case XIButtonClass: + { + xXIButtonInfo *b = (xXIButtonInfo *) any; + size_t mask_size, labels_size, need; + + if (cls_len < sizeof(xXIButtonInfo)) + return -1; + + mask_size = ((size_t) b->num_buttons + 7) / 8; + mask_size = (mask_size + 3) / 4 * 4; + if (b->num_buttons > + (SIZE_MAX - sizeof(xXIButtonInfo) - mask_size) / 4) + return -1; + + labels_size = (size_t) b->num_buttons * 4; + need = sizeof(xXIButtonInfo) + mask_size + labels_size; + if (need > cls_len) + return -1; + + break; + } + case XIKeyClass: + { + xXIKeyInfo *k = (xXIKeyInfo *) any; + + if (cls_len < sizeof(xXIKeyInfo)) + return -1; + + /* copy_classes reads num_keycodes bytes from the wire */ + if ((size_t) k->num_keycodes > (cls_len - sizeof(xXIKeyInfo)) / 4) + return -1; + + break; + } + case XIValuatorClass: + if (cls_len < sizeof(xXIValuatorInfo)) + return -1; + break; + case XIScrollClass: + if (cls_len < sizeof(xXIScrollInfo)) + return -1; + break; + case XITouchClass: + if (cls_len < sizeof(xXITouchInfo)) + return -1; + break; + case XIGestureClass: + if (cls_len < sizeof(xXIGestureInfo)) + return -1; + break; + default: + break; + } + + return 0; +} + _X_HIDDEN int -size_classes(xXIAnyInfo* from, int nclasses) +size_classes(xXIAnyInfo* from, int nclasses, char *end) { - int len, i; + size_t len; + size_t ptr_bytes; + int i; xXIAnyInfo *any_wire; char *ptr_wire; + if (nclasses < 0) + return -1; + if ((size_t) nclasses > SIZE_MAX / sizeof(XIAnyClassInfo *)) + return -1; + + ptr_bytes = (size_t) nclasses * sizeof(XIAnyClassInfo *); + if (ptr_bytes > (size_t) INT_MAX) + return -1; + /* len for to->classes */ - len = pad_to_double(nclasses * sizeof(XIAnyClassInfo*)); + len = (size_t) pad_to_double((int) ptr_bytes); ptr_wire = (char*)from; for (i = 0; i < nclasses; i++) { int l = 0; - any_wire = (xXIAnyInfo*)ptr_wire; + + if (validate_class_header(ptr_wire, end, &any_wire) < 0) + return -1; + + if (validate_class_payload(any_wire) < 0) + return -1; + switch(any_wire->type) { case XIButtonClass: @@ -1719,11 +1866,15 @@ size_classes(xXIAnyInfo* from, int nclas break; } - len += l; + if (l < 0 || len > SIZE_MAX - (size_t) l) + return -1; + len += (size_t) l; ptr_wire += any_wire->length * 4; } - return len; + if (len > (size_t) INT_MAX) + return -1; + return (int) len; } #define FP3232_TO_DOUBLE(x) ((double) (x).integral + (double) (x).frac / (1ULL << 32)) @@ -1735,7 +1886,7 @@ size_classes(xXIAnyInfo* from, int nclas * |______________________^ */ _X_HIDDEN int -copy_classes(XIDeviceInfo* to, xXIAnyInfo* from, int *nclasses) +copy_classes(XIDeviceInfo* to, xXIAnyInfo* from, int *nclasses, char *end) { XIAnyClassInfo *any_lib; xXIAnyInfo *any_wire; @@ -1757,7 +1908,12 @@ copy_classes(XIDeviceInfo* to, xXIAnyInf for (i = 0; i < *nclasses; i++) { any_lib = (XIAnyClassInfo*)ptr_lib; - any_wire = (xXIAnyInfo*)ptr_wire; + + if (validate_class_header(ptr_wire, end, &any_wire) < 0) + return -1; + + if (validate_class_payload(any_wire) < 0) + return -1; switch(any_wire->type) { @@ -1907,14 +2063,22 @@ copy_classes(XIDeviceInfo* to, xXIAnyInf static int -wireToDeviceChangedEvent(xXIDeviceChangedEvent *in, XGenericEventCookie *cookie) +wireToDeviceChangedEvent(xXIDeviceChangedEvent *in, size_t event_bytes, + XGenericEventCookie *cookie) { XIDeviceChangedEvent *out; XIDeviceInfo info; int len; int nclasses = in->num_classes; + char *end; + + if (event_bytes < sizeof(*in)) + return 0; + end = (char *)in + event_bytes; - len = size_classes((xXIAnyInfo*)&in[1], in->num_classes); + len = size_classes((xXIAnyInfo*)&in[1], in->num_classes, end); + if (len < 0 || (size_t)len > SIZE_MAX - sizeof(XIDeviceChangedEvent)) + return 0; cookie->data = out = malloc(sizeof(XIDeviceChangedEvent) + len); if (!out) @@ -1935,21 +2099,41 @@ wireToDeviceChangedEvent(xXIDeviceChange info.classes = out->classes; - copy_classes(&info, (xXIAnyInfo*)&in[1], &nclasses); + if (copy_classes(&info, (xXIAnyInfo*)&in[1], &nclasses, end) < 0) { + free(out); + cookie->data = NULL; + return 0; + } out->num_classes = nclasses; return 1; } static int -wireToHierarchyChangedEvent(xXIHierarchyEvent *in, XGenericEventCookie *cookie) +wireToHierarchyChangedEvent(xXIHierarchyEvent *in, size_t event_bytes, + XGenericEventCookie *cookie) { int i; XIHierarchyInfo *info_out; xXIHierarchyInfo *info_in; XIHierarchyEvent *out; + size_t info_bytes; + + if (event_bytes < sizeof(*in)) + return 0; - cookie->data = out = malloc(sizeof(XIHierarchyEvent) + in->num_info * sizeof(XIHierarchyInfo)); + info_bytes = (size_t) in->num_info * sizeof(xXIHierarchyInfo); + if (sizeof(xXIHierarchyInfo) != 0 && + info_bytes / sizeof(xXIHierarchyInfo) != (size_t) in->num_info) + return 0; + if (info_bytes > event_bytes - sizeof(*in)) + return 0; + if ((size_t) in->num_info > + (SIZE_MAX - sizeof(XIHierarchyEvent)) / sizeof(XIHierarchyInfo)) + return 0; + + cookie->data = out = malloc(sizeof(XIHierarchyEvent) + + in->num_info * sizeof(XIHierarchyInfo)); if (!out) return 0; @@ -1980,16 +2164,31 @@ wireToHierarchyChangedEvent(xXIHierarchy } static int -wireToRawEvent(XExtDisplayInfo *info, xXIRawEvent *in, XGenericEventCookie *cookie) +wireToRawEvent(XExtDisplayInfo *info, xXIRawEvent *in, size_t event_bytes, + XGenericEventCookie *cookie) { int len, i, bits; FP3232 *values; XIRawEvent *out; void *ptr; + size_t valuators_bytes, values_bytes, trailing; + + if (event_bytes < sizeof(*in)) + return 0; + + valuators_bytes = (size_t) in->valuators_len * 4; + trailing = event_bytes - sizeof(*in); + if (valuators_bytes > trailing) + return 0; + + bits = count_bits((unsigned char*)&in[1], (int) valuators_bytes); + /* normal + raw valuator arrays follow the mask */ + values_bytes = (size_t) bits * sizeof(FP3232) * 2; + if (values_bytes > trailing - valuators_bytes) + return 0; len = pad_to_double(sizeof(XIRawEvent)) - + pad_to_double(in->valuators_len * 4); - bits = count_bits((unsigned char*)&in[1], in->valuators_len * 4); + + pad_to_double((int) valuators_bytes); len += bits * sizeof(double) * 2; /* raw + normal */ cookie->data = ptr = calloc(1, len); @@ -2014,7 +2213,7 @@ wireToRawEvent(XExtDisplayInfo *info, xX else out->sourceid = 0; - out->valuators.mask_len = in->valuators_len * 4; + out->valuators.mask_len = (int) valuators_bytes; out->valuators.mask = next_block(&ptr, pad_to_double(out->valuators.mask_len)); memcpy(out->valuators.mask, &in[1], out->valuators.mask_len); @@ -2022,7 +2221,7 @@ wireToRawEvent(XExtDisplayInfo *info, xX out->valuators.values = next_block(&ptr, bits * sizeof(double)); out->raw_values = next_block(&ptr, bits * sizeof(double)); - values = (FP3232*)(((char*)&in[1]) + in->valuators_len * 4); + values = (FP3232*)(((char*)&in[1]) + valuators_bytes); for (i = 0; i < bits; i++) { out->valuators.values[i] = values->integral; @@ -2039,12 +2238,20 @@ wireToRawEvent(XExtDisplayInfo *info, xX [event][modifiers][group][button] */ static int -wireToEnterLeave(xXIEnterEvent *in, XGenericEventCookie *cookie) +wireToEnterLeave(xXIEnterEvent *in, size_t event_bytes, + XGenericEventCookie *cookie) { - int len; + size_t mask_len, len; XIEnterEvent *out; - len = sizeof(XIEnterEvent) + in->buttons_len * 4; + mask_len = (size_t)in->buttons_len * 4; + + if (event_bytes < sizeof(*in) || mask_len > event_bytes - sizeof(*in)) + return 0; + if (mask_len > SIZE_MAX - sizeof(XIEnterEvent)) + return 0; + + len = sizeof(XIEnterEvent) + mask_len; cookie->data = out = malloc(len); if (!out) @@ -2082,8 +2289,8 @@ wireToEnterLeave(xXIEnterEvent *in, XGen out->group.latched = in->group.latched_group; out->group.effective = in->group.effective_group; - out->buttons.mask_len = in->buttons_len * 4; - memcpy(out->buttons.mask, &in[1], out->buttons.mask_len); + out->buttons.mask_len = (int) mask_len; + memcpy(out->buttons.mask, &in[1], mask_len); return 1; } @@ -2111,10 +2318,15 @@ wireToPropertyEvent(xXIPropertyEvent *in } static int -wireToTouchOwnershipEvent(xXITouchOwnershipEvent *in, +wireToTouchOwnershipEvent(xXITouchOwnershipEvent *in, size_t event_bytes, XGenericEventCookie *cookie) { - XITouchOwnershipEvent *out = malloc(sizeof(XITouchOwnershipEvent)); + XITouchOwnershipEvent *out; + + if (event_bytes < sizeof(*in)) + return 0; + + out = malloc(sizeof(XITouchOwnershipEvent)); cookie->data = out; if (!out) @@ -2139,9 +2351,15 @@ wireToTouchOwnershipEvent(xXITouchOwners } static int -wireToBarrierEvent(xXIBarrierEvent *in, XGenericEventCookie *cookie) +wireToBarrierEvent(xXIBarrierEvent *in, size_t event_bytes, + XGenericEventCookie *cookie) { - XIBarrierEvent *out = malloc(sizeof(XIBarrierEvent)); + XIBarrierEvent *out; + + if (event_bytes < sizeof(*in)) + return 0; + + out = malloc(sizeof(XIBarrierEvent)); cookie->data = out; if (!out) @@ -2171,11 +2389,14 @@ wireToBarrierEvent(xXIBarrierEvent *in, } static int -wireToPinchEvent(xXIGesturePinchEvent *in, +wireToPinchEvent(xXIGesturePinchEvent *in, size_t event_bytes, XGenericEventCookie *cookie) { XIGesturePinchEvent *out; + if (event_bytes < sizeof(*in)) + return 0; + cookie->data = out = malloc(sizeof(XIGesturePinchEvent)); if (!out) return 0; @@ -2218,10 +2439,13 @@ wireToPinchEvent(xXIGesturePinchEvent *i } static int -wireToSwipeEvent(xXIGestureSwipeEvent *in, +wireToSwipeEvent(xXIGestureSwipeEvent *in, size_t event_bytes, XGenericEventCookie *cookie) { XIGestureSwipeEvent *out; + + if (event_bytes < sizeof(*in)) + return 0; cookie->data = out = malloc(sizeof(XIGestureSwipeEvent)); if (!out) Index: lib/libXi/src/XGetDCtl.c =================================================================== RCS file: /cvs/xenocara/lib/libXi/src/XGetDCtl.c,v diff -u -p -r1.9 XGetDCtl.c --- lib/libXi/src/XGetDCtl.c 4 Oct 2016 15:01:03 -0000 1.9 +++ lib/libXi/src/XGetDCtl.c 23 Oct 2026 23:02:42 -0000 @@ -105,13 +105,17 @@ XGetDeviceControl( sav = d; _XRead(dpy, (char *)d, nbytes); + /* Allocation and fill must agree; reject a mismatched reply type. */ + if (d->control != control) + goto out; + /* In theory, we should just be able to use d->length to get the size. * Turns out that a number of X servers (up to and including server * 1.4) sent the wrong length value down the wire. So to not break * apps that run against older servers, we have to calculate the size * manually. */ - switch (d->control) { + switch (control) { case DEVICE_RESOLUTION: { xDeviceResolutionState *r; @@ -146,6 +150,13 @@ XGetDeviceControl( if (sizeof(xDeviceCoreState) > nbytes) goto out; size = sizeof(XDeviceCoreState); + break; + } + case DEVICE_ENABLE: + { + if (sizeof(xDeviceEnableState) > nbytes) + goto out; + size = sizeof(XDeviceEnableState); break; } default: Index: lib/libXi/src/XIQueryDevice.c =================================================================== RCS file: /cvs/xenocara/lib/libXi/src/XIQueryDevice.c,v diff -u -p -r1.8 XIQueryDevice.c --- lib/libXi/src/XIQueryDevice.c 5 Nov 2024 08:16:46 -0000 1.8 +++ lib/libXi/src/XIQueryDevice.c 23 Oct 2026 23:02:43 -0000 @@ -34,8 +34,9 @@ #include #include "XIint.h" -extern int copy_classes(XIDeviceInfo* to, xXIAnyInfo* from, int *nclasses); -extern int size_classes(xXIAnyInfo* from, int nclasses); +extern int copy_classes(XIDeviceInfo* to, xXIAnyInfo* from, int *nclasses, + char *end); +extern int size_classes(xXIAnyInfo* from, int nclasses, char *end); XIDeviceInfo* XIQueryDevice(Display *dpy, int deviceid, int *ndevices_return) @@ -88,9 +89,11 @@ XIQueryDevice(Display *dpy, int deviceid for (i = 0; i < reply.num_devices; i++) { int nclasses; - size_t sz; + int sz; + int wire_len; XIDeviceInfo *lib = &info[i]; xXIDeviceInfo *wire = (xXIDeviceInfo*)ptr; + size_t name_bytes; if (ptr + sizeof(xXIDeviceInfo) > end) goto error_loop; @@ -102,25 +105,39 @@ XIQueryDevice(Display *dpy, int deviceid nclasses = wire->num_classes; ptr += sizeof(xXIDeviceInfo); + name_bytes = ((size_t) wire->name_len + 3) / 4 * 4; - if (ptr + wire->name_len > end) + if (ptr + name_bytes > 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; + ptr += name_bytes; - sz = size_classes((xXIAnyInfo*)ptr, nclasses); + sz = size_classes((xXIAnyInfo*)ptr, nclasses, end); + if (sz < 0) + { + Xfree(lib->name); + goto error_loop; + } lib->classes = Xmalloc(sz); if (lib->classes == NULL) { Xfree(lib->name); goto error_loop; } - ptr += copy_classes(lib, (xXIAnyInfo*)ptr, &nclasses); + wire_len = copy_classes(lib, (xXIAnyInfo*)ptr, &nclasses, end); + if (wire_len < 0 || ptr + wire_len > end) + { + Xfree(lib->name); + Xfree(lib->classes); + goto error_loop; + } + ptr += wire_len; /* We skip over unused classes */ lib->num_classes = nclasses; } Index: lib/libXi/src/XListDev.c =================================================================== RCS file: /cvs/xenocara/lib/libXi/src/XListDev.c,v diff -u -p -r1.9 XListDev.c --- lib/libXi/src/XListDev.c 3 Nov 2016 09:28:22 -0000 1.9 +++ lib/libXi/src/XListDev.c 23 Oct 2026 23:02:43 -0000 @@ -78,32 +78,47 @@ SizeClassInfo(xAnyClassPtr *any, size_t { int j; size_t sz = 0; + int clen; for (j = 0; j < num_classes; j++) { + if (len < sizeof(xAnyClassInfo)) + return 1; + clen = (*any)->length; + if (clen < (int)sizeof(xAnyClassInfo) || (size_t)clen > len) + return 1; + switch ((*any)->class) { case KeyClass: + if (clen < (int)sizeof(xKeyInfo)) + return 1; sz += pad_to_xid(sizeof(XKeyInfo)); break; case ButtonClass: + if (clen < (int)sizeof(xButtonInfo)) + return 1; sz += pad_to_xid(sizeof(XButtonInfo)); break; case ValuatorClass: { xValuatorInfoPtr v; + size_t need; - if (len < sizeof(v)) + if (clen < (int)sizeof(xValuatorInfo)) return 1; v = (xValuatorInfoPtr) *any; + need = sizeof(xValuatorInfo) + + ((size_t)v->num_axes * sizeof(xAxisInfo)); + if (need > (size_t)clen) + return 1; sz += pad_to_xid(sizeof(XValuatorInfo) + (v->num_axes * sizeof(XAxisInfo))); break; } default: - break; + return 1; } - if ((*any)->length > len) - return 1; - *any = (xAnyClassPtr) ((char *)(*any) + (*any)->length); + *any = (xAnyClassPtr) ((char *)(*any) + clen); + len -= (size_t)clen; } *size = sz; @@ -111,12 +126,20 @@ SizeClassInfo(xAnyClassPtr *any, size_t return 0; } -static void -ParseClassInfo(xAnyClassPtr *any, XAnyClassPtr *Any, int num_classes) +static int +ParseClassInfo(xAnyClassPtr *any, XAnyClassPtr *Any, int num_classes, + char *end) { int j; + int clen; for (j = 0; j < num_classes; j++) { + if ((char *)(*any) + sizeof(xAnyClassInfo) > end) + return 1; + clen = (*any)->length; + if (clen < (int)sizeof(xAnyClassInfo) || (char *)(*any) + clen > end) + return 1; + switch ((*any)->class) { case KeyClass: { @@ -165,11 +188,12 @@ ParseClassInfo(xAnyClassPtr *any, XAnyCl break; } default: - break; + return 1; } - *any = (xAnyClassPtr) ((char *)(*any) + (*any)->length); + *any = (xAnyClassPtr) ((char *)(*any) + clen); *Any = (XAnyClassPtr) ((char *)(*Any) + (*Any)->length); } + return 0; } XDeviceInfo * @@ -191,6 +215,7 @@ XListInputDevices( unsigned long rlen; XExtDisplayInfo *info = XInput_find_display(dpy); int ndevices; + Bool free_sclist = False; LockDisplay(dpy); if (_XiCheckExtInit(dpy, XInput_Initial_Release, info) == -1) @@ -224,17 +249,21 @@ XListInputDevices( sav_any = any; 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; + 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++) { - if (nptr >= Nptr) + size_t name_len; + + if (nptr >= (unsigned char *)end) goto out; - size += *nptr + 1; - nptr += (*nptr + 1); + name_len = *nptr; + if (name_len > (size_t)((unsigned char *)end - nptr - 1)) + goto out; + size += name_len + 1; + nptr += name_len + 1; } clist = (XDeviceInfoPtr) Xmalloc(size); @@ -256,24 +285,42 @@ XListInputDevices( clist->num_classes = list->num_classes; clist->inputclassinfo = Any; - ParseClassInfo(&any, &Any, (int)list->num_classes); + if (ParseClassInfo(&any, &Any, (int)list->num_classes, end)) { + free_sclist = True; + goto out; + } } clist = sclist; nptr = (unsigned char *)any; Nptr = (unsigned char *)Any; for (i = 0; i < ndevices; i++, clist++) { + size_t name_len; + + if (nptr >= (unsigned char *)end) { + free_sclist = True; + goto out; + } + name_len = *nptr; + if (name_len > (size_t)((unsigned char *)end - nptr - 1)) { + free_sclist = True; + goto out; + } clist->name = (char *)Nptr; - memcpy(Nptr, nptr + 1, *nptr); - Nptr += (*nptr); + memcpy(Nptr, nptr + 1, name_len); + Nptr += name_len; *Nptr++ = '\0'; - nptr += (*nptr + 1); + nptr += name_len + 1; } } *ndevices_return = ndevices; out: + if (free_sclist) { + XFree((char *)sclist); + sclist = NULL; + } XFree((char *)slist); UnlockDisplay(dpy); SyncHandle(); Index: lib/libXi/src/XQueryDv.c =================================================================== RCS file: /cvs/xenocara/lib/libXi/src/XQueryDv.c,v diff -u -p -r1.7 XQueryDv.c --- lib/libXi/src/XQueryDv.c 4 Oct 2016 15:01:03 -0000 1.7 +++ lib/libXi/src/XQueryDv.c 23 Oct 2026 23:02:43 -0000 @@ -108,20 +108,45 @@ XQueryDeviceState( switch (any->class) { case KeyClass: + if (any->length < sizeof(xKeyState) || + (char *)any + sizeof(xKeyState) > end) + goto out; size += sizeof(XKeyState); break; case ButtonClass: + if (any->length < sizeof(xButtonState) || + (char *)any + sizeof(xButtonState) > end) + goto out; size += sizeof(XButtonState); break; case ValuatorClass: { xValuatorState *v = (xValuatorState *) any; + size_t nvals; + size_t needed; + + if (any->length < sizeof(xValuatorState)) + goto out; + if ((char *)any + sizeof(xValuatorState) > end) goto out; - size += (sizeof(XValuatorState) + - (v->num_valuators * sizeof(int))); + + nvals = v->num_valuators; + /* valuators follow the header; must fit in class length */ + if (nvals > (any->length - sizeof(xValuatorState)) / sizeof(CARD32)) + goto out; + + needed = sizeof(xValuatorState) + nvals * sizeof(CARD32); + if ((char *)any + needed > end) + goto out; + + size += sizeof(XValuatorState) + nvals * sizeof(int); } break; + default: + /* Unknown classes are not represented in state->data; rejecting + * keeps num_classes consistent with the populated entries. */ + goto out; } any = (XInputClass *) ((char *)any + any->length); } @@ -165,30 +190,37 @@ XQueryDeviceState( xValuatorState *v = (xValuatorState *) any; XValuatorState *V = (XValuatorState *) Any; CARD32 *valuators = (CARD32 *) (v + 1); + size_t nvals = v->num_valuators; V->class = v->class; - V->length = sizeof(XValuatorState) + - v->num_valuators * sizeof(int); + V->length = sizeof(XValuatorState) + nvals * sizeof(int); V->num_valuators = v->num_valuators; V->mode = v->mode; Any = (XInputClass *) (V + 1); V->valuators = (int *)Any; - for (j = 0; j < (int)V->num_valuators; j++) + for (j = 0; j < (int)nvals; j++) *(V->valuators + j) = *valuators++; - Any = (XInputClass *) ((char *)Any + - V->num_valuators * sizeof(int)); + Any = (XInputClass *) ((char *)Any + nvals * sizeof(int)); } break; + default: + goto out; } any = (XInputClass *) ((char *)any + any->length); } } -out: + Xfree(data); + UnlockDisplay(dpy); + SyncHandle(); + return state; +out: + Xfree(data); + Xfree(state); UnlockDisplay(dpy); SyncHandle(); - return (state); + return NULL; } void Index: lib/libXpm/src/parse.c =================================================================== RCS file: /cvs/xenocara/lib/libXpm/src/parse.c,v diff -u -p -r1.12 parse.c --- lib/libXpm/src/parse.c 8 May 2026 13:19:59 -0000 1.12 +++ lib/libXpm/src/parse.c 23 Oct 2026 23:02:43 -0000 @@ -414,10 +414,7 @@ ParsePixels( unsigned int a, x, y; int ErrorStatus; - if ((width == 0) && (height != 0)) - return (XpmFileInvalid); - - if ((height == 0) && (width != 0)) + if (width == 0 || height == 0) return (XpmFileInvalid); if ((height > 0 && width >= UINT_MAX / height) || Index: lib/libXrender/src/Xrender.c =================================================================== RCS file: /cvs/xenocara/lib/libXrender/src/Xrender.c,v diff -u -p -r1.7 Xrender.c --- lib/libXrender/src/Xrender.c 16 Mar 2025 12:08:39 -0000 1.7 +++ lib/libXrender/src/Xrender.c 23 Oct 2026 23:02:43 -0000 @@ -478,6 +478,7 @@ XRenderQueryFormats (Display *dpy) (rep.numDepths < ((INT_MAX / 4) / sizeof (XRenderDepth))) && (rep.numVisuals < ((INT_MAX / 4) / sizeof (XRenderVisual))) && (rep.numSubpixel < ((INT_MAX / 4) / 4)) && + (rep.numSubpixel <= rep.numScreens) && (rep.length < (INT_MAX >> 2)) ) { /* Zero-initialize so that pointers are NULL if there is a failure. */ xri = Xcalloc (1, sizeof (XRenderInfo)); Index: lib/libXtst/src/XRecord.c =================================================================== RCS file: /cvs/xenocara/lib/libXtst/src/XRecord.c,v diff -u -p -r1.8 XRecord.c --- lib/libXtst/src/XRecord.c 4 Aug 2024 17:31:05 -0000 1.8 +++ lib/libXtst/src/XRecord.c 23 Oct 2026 23:02:43 -0000 @@ -726,11 +726,15 @@ parse_reply_call_callback( { XRecordInterceptData *data; unsigned int current_index; + unsigned int end; int datum_bytes = 0; /* call the callback for each protocol element in the reply */ current_index = 0; + end = rep->length << 2; do { + unsigned int start_index = current_index; + data = alloc_inter_data(info); if (!data) return Error; @@ -806,6 +810,9 @@ parse_reply_call_callback( if (datum_bytes < 0 || datum_bytes > INT_MAX >> 2) goto out; datum_bytes <<= 2; + /* A client request cannot be zero-sized (incl. BIG-REQUESTS). */ + if (datum_bytes == 0) + goto out; break; case XRecordClientStarted: if (reply == NULL) @@ -836,13 +843,28 @@ parse_reply_call_callback( goto out; datum_bytes = 0; break; + default: + /* + * A follow-up on the previous fix for CVE-2016-7952: + * An unknown category would leave datum_bytes at 0 and + * "livelock" the loop. + */ + goto out; } + /* + * Malformed if this element neither grew nor advanced the index. + * StartOfData / EndOfData are already rejected if current_index < end + * so not a change in behavior. + */ + if (datum_bytes == 0 && current_index == start_index && current_index < end) + goto out; + if (datum_bytes > 0) { - if (INT_MAX - datum_bytes < (rep->length << 2) - current_index) { + if ((unsigned int)datum_bytes > end - current_index) { fprintf(stderr, - "XRecord: %lu-byte reply claims %d-byte element (seq %lu)\n", - (unsigned long)rep->length << 2, current_index + datum_bytes, + "XRecord: %u-byte reply claims %u-byte element (seq %lu)\n", + end, current_index + (unsigned int)datum_bytes, dpy->last_request_read); goto out; } @@ -861,7 +883,7 @@ parse_reply_call_callback( (*callback)(closure, data); current_index += datum_bytes; - } while (current_indexlength<<2); + } while (current_index < end); if (rep->category == XRecordEndOfData) return End;