From e2fccd6b734c6ae00768ef0d8c0720b3cc34e492 Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 17 Dec 2024 21:17:30 -0500 Subject: [PATCH 01/17] turbojpeg-jni.c: Fix comp. warnings w/ 32-bit code --- common/turbojpeg-jni/turbojpeg-jni.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/turbojpeg-jni/turbojpeg-jni.c b/common/turbojpeg-jni/turbojpeg-jni.c index 262383976..59081d028 100644 --- a/common/turbojpeg-jni/turbojpeg-jni.c +++ b/common/turbojpeg-jni/turbojpeg-jni.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2011-2012, 2014-2015, 2017-2019, 2021 D. R. Commander. - * All Rights Reserved. +/* Copyright (C) 2011-2012, 2014-2015, 2017-2019, 2021, 2024 + * D. R. Commander. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -63,7 +63,7 @@ JNIEXPORT jlong JNICALL Java_com_turbovnc_rfb_TightDecoder_tjInitDecompress THROW(tjGetErrorStr()); bailout: - return (jlong)handle; + return (jlong)(size_t)handle; } @@ -88,7 +88,7 @@ static void decompress BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); BAILIF0NOEC(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); - if (tjDecompress2((tjhandle)handle, jpegBuf, (unsigned long)jpegSize, + if (tjDecompress2((tjhandle)(size_t)handle, jpegBuf, (unsigned long)jpegSize, &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width, pitch, height, pf, flags) == -1) { SAFE_RELEASE(dst, dstBuf); @@ -128,7 +128,7 @@ JNIEXPORT void JNICALL Java_com_turbovnc_rfb_TightDecoder_tjDestroy if (!handle) THROW("Invalid argument in tjDestroy()"); - if (tjDestroy((tjhandle)handle) == -1) THROW(tjGetErrorStr()); + if (tjDestroy((tjhandle)(size_t)handle) == -1) THROW(tjGetErrorStr()); bailout: return; From 9675954ab014f4b8d1cc543c3d9a4744eb242f4a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 3 Oct 2023 11:53:05 +1000 Subject: [PATCH 02/17] Xi/randr: fix handling of PropModeAppend/Prepend The handling of appending/prepending properties was incorrect, with at least two bugs: the property length was set to the length of the new part only, i.e. appending or prepending N elements to a property with P existing elements always resulted in the property having N elements instead of N + P. Second, when pre-pending a value to a property, the offset for the old values was incorrect, leaving the new property with potentially uninitalized values and/or resulting in OOB memory writes. For example, prepending a 3 element value to a 5 element property would result in this 8 value array: [N, N, N, ?, ?, P, P, P ] P, P ^OOB write The XI2 code is a copy/paste of the RandR code, so the bug exists in both. CVE-2023-5367, ZDI-CAN-22153 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative Signed-off-by: Peter Hutterer (cherry picked from commit 541ab2ecd41d4d8689e71855d93e492bc554719a) --- unix/Xvnc/programs/Xserver/Xi/xiproperty.c | 4 ++-- unix/Xvnc/programs/Xserver/randr/rrproperty.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/unix/Xvnc/programs/Xserver/Xi/xiproperty.c b/unix/Xvnc/programs/Xserver/Xi/xiproperty.c index 0cfa6e3b6..172ddac27 100644 --- a/unix/Xvnc/programs/Xserver/Xi/xiproperty.c +++ b/unix/Xvnc/programs/Xserver/Xi/xiproperty.c @@ -730,7 +730,7 @@ XIChangeDeviceProperty(DeviceIntPtr dev, Atom property, Atom type, XIDestroyDeviceProperty(prop); return BadAlloc; } - new_value.size = len; + new_value.size = total_len; new_value.type = type; new_value.format = format; @@ -747,7 +747,7 @@ XIChangeDeviceProperty(DeviceIntPtr dev, Atom property, Atom type, case PropModePrepend: new_data = new_value.data; old_data = (void *) (((char *) new_value.data) + - (prop_value->size * size_in_bytes)); + (len * size_in_bytes)); break; } if (new_data) diff --git a/unix/Xvnc/programs/Xserver/randr/rrproperty.c b/unix/Xvnc/programs/Xserver/randr/rrproperty.c index c2fb9585c..25469f57b 100644 --- a/unix/Xvnc/programs/Xserver/randr/rrproperty.c +++ b/unix/Xvnc/programs/Xserver/randr/rrproperty.c @@ -209,7 +209,7 @@ RRChangeOutputProperty(RROutputPtr output, Atom property, Atom type, RRDestroyOutputProperty(prop); return BadAlloc; } - new_value.size = len; + new_value.size = total_len; new_value.type = type; new_value.format = format; @@ -226,7 +226,7 @@ RRChangeOutputProperty(RROutputPtr output, Atom property, Atom type, case PropModePrepend: new_data = new_value.data; old_data = (void *) (((char *) new_value.data) + - (prop_value->size * size_in_bytes)); + (len * size_in_bytes)); break; } if (new_data) From 25ab7eb7fee18fd3c9570b878cb3ec8c616740fc Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 27 Nov 2023 16:27:49 +1000 Subject: [PATCH 03/17] randr: avoid integer truncation in length check of ProcRRChange*Property Affected are ProcRRChangeProviderProperty and ProcRRChangeOutputProperty. See also xserver@8f454b79 where this same bug was fixed for the core protocol and XI. This fixes an OOB read and the resulting information disclosure. Length calculation for the request was clipped to a 32-bit integer. With the correct stuff->nUnits value the expected request size was truncated, passing the REQUEST_FIXED_SIZE check. The server then proceeded with reading at least stuff->num_items bytes (depending on stuff->format) from the request and stuffing whatever it finds into the property. In the process it would also allocate at least stuff->nUnits bytes, i.e. 4GB. CVE-2023-6478, ZDI-CAN-22561 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative (cherry picked from commit 14f480010a93ff962fef66a16412fafff81ad632) --- unix/Xvnc/programs/Xserver/randr/rrproperty.c | 2 +- unix/Xvnc/programs/Xserver/randr/rrproviderproperty.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unix/Xvnc/programs/Xserver/randr/rrproperty.c b/unix/Xvnc/programs/Xserver/randr/rrproperty.c index 25469f57b..c4fef8a1f 100644 --- a/unix/Xvnc/programs/Xserver/randr/rrproperty.c +++ b/unix/Xvnc/programs/Xserver/randr/rrproperty.c @@ -530,7 +530,7 @@ ProcRRChangeOutputProperty(ClientPtr client) char format, mode; unsigned long len; int sizeInBytes; - int totalSize; + uint64_t totalSize; int err; REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq); diff --git a/unix/Xvnc/programs/Xserver/randr/rrproviderproperty.c b/unix/Xvnc/programs/Xserver/randr/rrproviderproperty.c index b79c17f9b..90c5a9a93 100644 --- a/unix/Xvnc/programs/Xserver/randr/rrproviderproperty.c +++ b/unix/Xvnc/programs/Xserver/randr/rrproviderproperty.c @@ -498,7 +498,7 @@ ProcRRChangeProviderProperty(ClientPtr client) char format, mode; unsigned long len; int sizeInBytes; - int totalSize; + uint64_t totalSize; int err; REQUEST_AT_LEAST_SIZE(xRRChangeProviderPropertyReq); From fe941232b213f90b160a1523c3a91a5fa4d55e20 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 28 Nov 2023 15:19:04 +1000 Subject: [PATCH 04/17] Xi: allocate enough XkbActions for our buttons button->xkb_acts is supposed to be an array sufficiently large for all our buttons, not just a single XkbActions struct. Allocating insufficient memory here means when we memcpy() later in XkbSetDeviceInfo we write into memory that wasn't ours to begin with, leading to the usual security ooopsiedaisies. CVE-2023-6377, ZDI-CAN-22412, ZDI-CAN-22413 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative (cherry picked from commit 0c1a93d319558fe3ab2d94f51d174b4f93810afd) --- unix/Xvnc/programs/Xserver/Xi/exevents.c | 12 ++++++------ unix/Xvnc/programs/Xserver/dix/devices.c | 10 ++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/unix/Xvnc/programs/Xserver/Xi/exevents.c b/unix/Xvnc/programs/Xserver/Xi/exevents.c index 0cb8d789c..c59de7a55 100644 --- a/unix/Xvnc/programs/Xserver/Xi/exevents.c +++ b/unix/Xvnc/programs/Xserver/Xi/exevents.c @@ -567,13 +567,13 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to) } if (from->button->xkb_acts) { - if (!to->button->xkb_acts) { - to->button->xkb_acts = calloc(1, sizeof(XkbAction)); - if (!to->button->xkb_acts) - FatalError("[Xi] not enough memory for xkb_acts.\n"); - } + size_t maxbuttons = max(to->button->numButtons, from->button->numButtons); + to->button->xkb_acts = xnfreallocarray(to->button->xkb_acts, + maxbuttons, + sizeof(XkbAction)); + memset(to->button->xkb_acts, 0, maxbuttons * sizeof(XkbAction)); memcpy(to->button->xkb_acts, from->button->xkb_acts, - sizeof(XkbAction)); + from->button->numButtons * sizeof(XkbAction)); } else { free(to->button->xkb_acts); diff --git a/unix/Xvnc/programs/Xserver/dix/devices.c b/unix/Xvnc/programs/Xserver/dix/devices.c index e7c74d7b7..7776498f8 100644 --- a/unix/Xvnc/programs/Xserver/dix/devices.c +++ b/unix/Xvnc/programs/Xserver/dix/devices.c @@ -2502,6 +2502,8 @@ RecalculateMasterButtons(DeviceIntPtr slave) if (master->button && master->button->numButtons != maxbuttons) { int i; + int last_num_buttons = master->button->numButtons; + DeviceChangedEvent event = { .header = ET_Internal, .type = ET_DeviceChanged, @@ -2512,6 +2514,14 @@ RecalculateMasterButtons(DeviceIntPtr slave) }; master->button->numButtons = maxbuttons; + if (last_num_buttons < maxbuttons) { + master->button->xkb_acts = xnfreallocarray(master->button->xkb_acts, + maxbuttons, + sizeof(XkbAction)); + memset(&master->button->xkb_acts[last_num_buttons], + 0, + (maxbuttons - last_num_buttons) * sizeof(XkbAction)); + } memcpy(&event.buttons.names, master->button->labels, maxbuttons * sizeof(Atom)); From b8690baaf78235c8b2f3ccb274d6c33c938f4750 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 14 Dec 2023 11:29:49 +1000 Subject: [PATCH 05/17] dix: allocate enough space for logical button maps Both DeviceFocusEvent and the XIQueryPointer reply contain a bit for each logical button currently down. Since buttons can be arbitrarily mapped to anything up to 255 make sure we have enough bits for the maximum mapping. CVE-2023-6816, ZDI-CAN-22664, ZDI-CAN-22665 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative (cherry picked from commit 9e2ecb2af8302dedc49cb6a63ebe063c58a9e7e3) --- unix/Xvnc/programs/Xserver/Xi/xiquerypointer.c | 3 +-- unix/Xvnc/programs/Xserver/dix/enterleave.c | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/unix/Xvnc/programs/Xserver/Xi/xiquerypointer.c b/unix/Xvnc/programs/Xserver/Xi/xiquerypointer.c index 5b77b1a44..2b05ac5f3 100644 --- a/unix/Xvnc/programs/Xserver/Xi/xiquerypointer.c +++ b/unix/Xvnc/programs/Xserver/Xi/xiquerypointer.c @@ -149,8 +149,7 @@ ProcXIQueryPointer(ClientPtr client) if (pDev->button) { int i; - rep.buttons_len = - bytes_to_int32(bits_to_bytes(pDev->button->numButtons)); + rep.buttons_len = bytes_to_int32(bits_to_bytes(256)); /* button map up to 255 */ rep.length += rep.buttons_len; buttons = calloc(rep.buttons_len, 4); if (!buttons) diff --git a/unix/Xvnc/programs/Xserver/dix/enterleave.c b/unix/Xvnc/programs/Xserver/dix/enterleave.c index a2f625bc9..9f0b69a48 100644 --- a/unix/Xvnc/programs/Xserver/dix/enterleave.c +++ b/unix/Xvnc/programs/Xserver/dix/enterleave.c @@ -784,8 +784,9 @@ DeviceFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, mouse = IsFloating(dev) ? dev : GetMaster(dev, MASTER_POINTER); - /* XI 2 event */ - btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; + /* XI 2 event contains the logical button map - maps are CARD8 + * so we need 256 bits for the possibly maximum mapping */ + btlen = (mouse->button) ? bits_to_bytes(256) : 0; btlen = bytes_to_int32(btlen); len = sizeof(xXIFocusInEvent) + btlen * 4; From b1c144b63f9a79e71540589fa8568c68703ab3f3 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 18 Dec 2023 14:27:50 +1000 Subject: [PATCH 06/17] dix: Allocate sufficient xEvents for our DeviceStateNotify If a device has both a button class and a key class and numButtons is zero, we can get an OOB write due to event under-allocation. This function seems to assume a device has either keys or buttons, not both. It has two virtually identical code paths, both of which assume they're applying to the first event in the sequence. A device with both a key and button class triggered a logic bug - only one xEvent was allocated but the deviceStateNotify pointer was pushed on once per type. So effectively this logic code: int count = 1; if (button && nbuttons > 32) count++; if (key && nbuttons > 0) count++; if (key && nkeys > 32) count++; // this is basically always true // count is at 2 for our keys + zero button device ev = alloc(count * sizeof(xEvent)); FixDeviceStateNotify(ev); if (button) FixDeviceStateNotify(ev++); if (key) FixDeviceStateNotify(ev++); // santa drops into the wrong chimney here If the device has more than 3 valuators, the OOB is pushed back - we're off by one so it will happen when the last deviceValuator event is written instead. Fix this by allocating the maximum number of events we may allocate. Note that the current behavior is not protocol-correct anyway, this patch fixes only the allocation issue. Note that this issue does not trigger if the device has at least one button. While the server does not prevent a button class with zero buttons, it is very unlikely. CVE-2024-0229, ZDI-CAN-22678 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative (cherry picked from commit ece23be888a93b741aa1209d1dbf64636109d6a5) --- unix/Xvnc/programs/Xserver/dix/enterleave.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unix/Xvnc/programs/Xserver/dix/enterleave.c b/unix/Xvnc/programs/Xserver/dix/enterleave.c index 9f0b69a48..085c7b9fb 100644 --- a/unix/Xvnc/programs/Xserver/dix/enterleave.c +++ b/unix/Xvnc/programs/Xserver/dix/enterleave.c @@ -675,7 +675,8 @@ static void DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win) { int evcount = 1; - deviceStateNotify *ev, *sev; + deviceStateNotify sev[6 + (MAX_VALUATORS + 2)/3]; + deviceStateNotify *ev; deviceKeyStateNotify *kev; deviceButtonStateNotify *bev; @@ -714,7 +715,7 @@ DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win) } } - sev = ev = xallocarray(evcount, sizeof(xEvent)); + ev = sev; FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first); if (b != NULL) { @@ -770,7 +771,6 @@ DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win) DeliverEventsToWindow(dev, win, (xEvent *) sev, evcount, DeviceStateNotifyMask, NullGrab); - free(sev); } void From 60cf63ffb6718dea1cfe5931090372d3ed697cd0 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 18 Dec 2023 12:26:20 +1000 Subject: [PATCH 07/17] dix: fix DeviceStateNotify event calculation The previous code only made sense if one considers buttons and keys to be mutually exclusive on a device. That is not necessarily true, causing a number of issues. This function allocates and fills in the number of xEvents we need to send the device state down the wire. This is split across multiple 32-byte devices including one deviceStateNotify event and optional deviceKeyStateNotify, deviceButtonStateNotify and (possibly multiple) deviceValuator events. The previous behavior would instead compose a sequence of [state, buttonstate, state, keystate, valuator...]. This is not protocol correct, and on top of that made the code extremely convoluted. Fix this by streamlining: add both button and key into the deviceStateNotify and then append the key state and button state, followed by the valuators. Finally, the deviceValuator events contain up to 6 valuators per event but we only ever sent through 3 at a time. Let's double that troughput. CVE-2024-0229, ZDI-CAN-22678 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative (cherry picked from commit 219c54b8a3337456ce5270ded6a67bcde53553d5) --- unix/Xvnc/programs/Xserver/dix/enterleave.c | 121 +++++++++----------- 1 file changed, 52 insertions(+), 69 deletions(-) diff --git a/unix/Xvnc/programs/Xserver/dix/enterleave.c b/unix/Xvnc/programs/Xserver/dix/enterleave.c index 085c7b9fb..72a953f9a 100644 --- a/unix/Xvnc/programs/Xserver/dix/enterleave.c +++ b/unix/Xvnc/programs/Xserver/dix/enterleave.c @@ -615,9 +615,15 @@ FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v, ev->type = DeviceValuator; ev->deviceid = dev->id; - ev->num_valuators = nval < 3 ? nval : 3; + ev->num_valuators = nval < 6 ? nval : 6; ev->first_valuator = first; switch (ev->num_valuators) { + case 6: + ev->valuator2 = v->axisVal[first + 5]; + case 5: + ev->valuator2 = v->axisVal[first + 4]; + case 4: + ev->valuator2 = v->axisVal[first + 3]; case 3: ev->valuator2 = v->axisVal[first + 2]; case 2: @@ -626,7 +632,6 @@ FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v, ev->valuator0 = v->axisVal[first]; break; } - first += ev->num_valuators; } static void @@ -646,7 +651,7 @@ FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, ev->num_buttons = b->numButtons; memcpy((char *) ev->buttons, (char *) b->down, 4); } - else if (k) { + if (k) { ev->classes_reported |= (1 << KeyClass); ev->num_keys = k->xkbInfo->desc->max_key_code - k->xkbInfo->desc->min_key_code; @@ -670,15 +675,26 @@ FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, } } - +/** + * The device state notify event is split across multiple 32-byte events. + * The first one contains the first 32 button state bits, the first 32 + * key state bits, and the first 3 valuator values. + * + * If a device has more than that, the server sends out: + * - one deviceButtonStateNotify for buttons 32 and above + * - one deviceKeyStateNotify for keys 32 and above + * - one deviceValuator event per 6 valuators above valuator 4 + * + * All events but the last one have the deviceid binary ORed with MORE_EVENTS, + */ static void DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win) { + /* deviceStateNotify, deviceKeyStateNotify, deviceButtonStateNotify + * and one deviceValuator for each 6 valuators */ + deviceStateNotify sev[3 + (MAX_VALUATORS + 6)/6]; int evcount = 1; - deviceStateNotify sev[6 + (MAX_VALUATORS + 2)/3]; - deviceStateNotify *ev; - deviceKeyStateNotify *kev; - deviceButtonStateNotify *bev; + deviceStateNotify *ev = sev; KeyClassPtr k; ButtonClassPtr b; @@ -691,82 +707,49 @@ DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win) if ((b = dev->button) != NULL) { nbuttons = b->numButtons; - if (nbuttons > 32) + if (nbuttons > 32) /* first 32 are encoded in deviceStateNotify */ evcount++; } if ((k = dev->key) != NULL) { nkeys = k->xkbInfo->desc->max_key_code - k->xkbInfo->desc->min_key_code; - if (nkeys > 32) + if (nkeys > 32) /* first 32 are encoded in deviceStateNotify */ evcount++; - if (nbuttons > 0) { - evcount++; - } } if ((v = dev->valuator) != NULL) { nval = v->numAxes; - - if (nval > 3) - evcount++; - if (nval > 6) { - if (!(k && b)) - evcount++; - if (nval > 9) - evcount += ((nval - 7) / 3); - } + /* first three are encoded in deviceStateNotify, then + * it's 6 per deviceValuator event */ + evcount += ((nval - 3) + 6)/6; } - ev = sev; - FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first); - - if (b != NULL) { - FixDeviceStateNotify(dev, ev++, NULL, b, v, first); - first += 3; - nval -= 3; - if (nbuttons > 32) { - (ev - 1)->deviceid |= MORE_EVENTS; - bev = (deviceButtonStateNotify *) ev++; - bev->type = DeviceButtonStateNotify; - bev->deviceid = dev->id; - memcpy((char *) &bev->buttons[4], (char *) &b->down[4], - DOWN_LENGTH - 4); - } - if (nval > 0) { - (ev - 1)->deviceid |= MORE_EVENTS; - FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); - first += 3; - nval -= 3; - } + BUG_RETURN(evcount <= ARRAY_SIZE(sev)); + + FixDeviceStateNotify(dev, ev, k, b, v, first); + + if (b != NULL && nbuttons > 32) { + deviceButtonStateNotify *bev = (deviceButtonStateNotify *) ++ev; + (ev - 1)->deviceid |= MORE_EVENTS; + bev->type = DeviceButtonStateNotify; + bev->deviceid = dev->id; + memcpy((char *) &bev->buttons[4], (char *) &b->down[4], + DOWN_LENGTH - 4); } - if (k != NULL) { - FixDeviceStateNotify(dev, ev++, k, NULL, v, first); - first += 3; - nval -= 3; - if (nkeys > 32) { - (ev - 1)->deviceid |= MORE_EVENTS; - kev = (deviceKeyStateNotify *) ev++; - kev->type = DeviceKeyStateNotify; - kev->deviceid = dev->id; - memmove((char *) &kev->keys[0], (char *) &k->down[4], 28); - } - if (nval > 0) { - (ev - 1)->deviceid |= MORE_EVENTS; - FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); - first += 3; - nval -= 3; - } + if (k != NULL && nkeys > 32) { + deviceKeyStateNotify *kev = (deviceKeyStateNotify *) ++ev; + (ev - 1)->deviceid |= MORE_EVENTS; + kev->type = DeviceKeyStateNotify; + kev->deviceid = dev->id; + memmove((char *) &kev->keys[0], (char *) &k->down[4], 28); } + first = 3; + nval -= 3; while (nval > 0) { - FixDeviceStateNotify(dev, ev++, NULL, NULL, v, first); - first += 3; - nval -= 3; - if (nval > 0) { - (ev - 1)->deviceid |= MORE_EVENTS; - FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); - first += 3; - nval -= 3; - } + ev->deviceid |= MORE_EVENTS; + FixDeviceValuator(dev, (deviceValuator *) ++ev, v, first); + first += 6; + nval -= 6; } DeliverEventsToWindow(dev, win, (xEvent *) sev, evcount, From 05a2410883833dda34ac8737cf308e97414d65c4 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 21 Dec 2023 13:48:10 +1000 Subject: [PATCH 08/17] Xi: when creating a new ButtonClass, set the number of buttons There's a racy sequence where a master device may copy the button class from the slave, without ever initializing numButtons. This leads to a device with zero buttons but a button class which is invalid. Let's copy the numButtons value from the source - by definition if we don't have a button class yet we do not have any other slave devices with more than this number of buttons anyway. CVE-2024-0229, ZDI-CAN-22678 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative (cherry picked from commit df3c65706eb169d5938df0052059f3e0d5981b74) --- unix/Xvnc/programs/Xserver/Xi/exevents.c | 1 + 1 file changed, 1 insertion(+) diff --git a/unix/Xvnc/programs/Xserver/Xi/exevents.c b/unix/Xvnc/programs/Xserver/Xi/exevents.c index c59de7a55..1930089d3 100644 --- a/unix/Xvnc/programs/Xserver/Xi/exevents.c +++ b/unix/Xvnc/programs/Xserver/Xi/exevents.c @@ -561,6 +561,7 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to) to->button = calloc(1, sizeof(ButtonClassRec)); if (!to->button) FatalError("[Xi] no memory for class shift.\n"); + to->button->numButtons = from->button->numButtons; } else classes->button = NULL; From 57eed00b3a8ac92d834dec06517fb7bdd3b7cc8d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 4 Jan 2024 10:01:24 +1000 Subject: [PATCH 09/17] Xi: flush hierarchy events after adding/removing master devices The `XISendDeviceHierarchyEvent()` function allocates space to store up to `MAXDEVICES` (256) `xXIHierarchyInfo` structures in `info`. If a device with a given ID was removed and a new device with the same ID added both in the same operation, the single device ID will lead to two info structures being written to `info`. Since this case can occur for every device ID at once, a total of two times `MAXDEVICES` info structures might be written to the allocation. To avoid it, once one add/remove master is processed, send out the device hierarchy event for the current state and continue. That event thus only ever has exactly one of either added/removed in it (and optionally slave attached/detached). CVE-2024-21885, ZDI-CAN-22744 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative (cherry picked from commit 4a5e9b1895627d40d26045bd0b7ef3dce503cbd1) --- .../programs/Xserver/Xi/xichangehierarchy.c | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/unix/Xvnc/programs/Xserver/Xi/xichangehierarchy.c b/unix/Xvnc/programs/Xserver/Xi/xichangehierarchy.c index ad89a3112..cb0c6dfba 100644 --- a/unix/Xvnc/programs/Xserver/Xi/xichangehierarchy.c +++ b/unix/Xvnc/programs/Xserver/Xi/xichangehierarchy.c @@ -416,6 +416,11 @@ ProcXIChangeHierarchy(ClientPtr client) size_t len; /* length of data remaining in request */ int rc = Success; int flags[MAXDEVICES] = { 0 }; + enum { + NO_CHANGE, + FLUSH, + CHANGED, + } changes = NO_CHANGE; REQUEST(xXIChangeHierarchyReq); REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq); @@ -465,8 +470,9 @@ ProcXIChangeHierarchy(ClientPtr client) rc = add_master(client, c, flags); if (rc != Success) goto unwind; - } + changes = FLUSH; break; + } case XIRemoveMaster: { xXIRemoveMasterInfo *r = (xXIRemoveMasterInfo *) any; @@ -475,8 +481,9 @@ ProcXIChangeHierarchy(ClientPtr client) rc = remove_master(client, r, flags); if (rc != Success) goto unwind; - } + changes = FLUSH; break; + } case XIDetachSlave: { xXIDetachSlaveInfo *c = (xXIDetachSlaveInfo *) any; @@ -485,8 +492,9 @@ ProcXIChangeHierarchy(ClientPtr client) rc = detach_slave(client, c, flags); if (rc != Success) goto unwind; - } + changes = CHANGED; break; + } case XIAttachSlave: { xXIAttachSlaveInfo *c = (xXIAttachSlaveInfo *) any; @@ -495,16 +503,25 @@ ProcXIChangeHierarchy(ClientPtr client) rc = attach_slave(client, c, flags); if (rc != Success) goto unwind; + changes = CHANGED; + break; } + default: break; } + if (changes == FLUSH) { + XISendDeviceHierarchyEvent(flags); + memset(flags, 0, sizeof(flags)); + changes = NO_CHANGE; + } + len -= any->length * 4; any = (xXIAnyHierarchyChangeInfo *) ((char *) any + any->length * 4); } unwind: - - XISendDeviceHierarchyEvent(flags); + if (changes != NO_CHANGE) + XISendDeviceHierarchyEvent(flags); return rc; } From 07991b81228ec1d303c874fe9ff826a66e6b9ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Fri, 22 Dec 2023 18:28:31 +0100 Subject: [PATCH 10/17] Xi: do not keep linked list pointer during recursion The `DisableDevice()` function is called whenever an enabled device is disabled and it moves the device from the `inputInfo.devices` linked list to the `inputInfo.off_devices` linked list. However, its link/unlink operation has an issue during the recursive call to `DisableDevice()` due to the `prev` pointer pointing to a removed device. This issue leads to a length mismatch between the total number of devices and the number of device in the list, leading to a heap overflow and, possibly, to local privilege escalation. Simplify the code that checked whether the device passed to `DisableDevice()` was in `inputInfo.devices` or not and find the previous device after the recursion. CVE-2024-21886, ZDI-CAN-22840 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative (cherry picked from commit bc1fdbe46559dd947674375946bbef54dd0ce36b) --- unix/Xvnc/programs/Xserver/dix/devices.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/unix/Xvnc/programs/Xserver/dix/devices.c b/unix/Xvnc/programs/Xserver/dix/devices.c index 7776498f8..316ddbbdb 100644 --- a/unix/Xvnc/programs/Xserver/dix/devices.c +++ b/unix/Xvnc/programs/Xserver/dix/devices.c @@ -451,14 +451,20 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) { DeviceIntPtr *prev, other; BOOL enabled; + BOOL dev_in_devices_list = FALSE; int flags[MAXDEVICES] = { 0 }; if (!dev->enabled) return TRUE; - for (prev = &inputInfo.devices; - *prev && (*prev != dev); prev = &(*prev)->next); - if (*prev != dev) + for (other = inputInfo.devices; other; other = other->next) { + if (other == dev) { + dev_in_devices_list = TRUE; + break; + } + } + + if (!dev_in_devices_list) return FALSE; TouchEndPhysicallyActiveTouches(dev); @@ -508,6 +514,9 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) LeaveWindow(dev); SetFocusOut(dev); + for (prev = &inputInfo.devices; + *prev && (*prev != dev); prev = &(*prev)->next); + *prev = dev->next; dev->next = inputInfo.off_devices; inputInfo.off_devices = dev; From 48e0ad130a765f4ad42423e32cc898bdd87d5590 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 5 Jan 2024 09:40:27 +1000 Subject: [PATCH 11/17] dix: when disabling a master, float disabled slaved devices too Disabling a master device floats all slave devices but we didn't do this to already-disabled slave devices. As a result those devices kept their reference to the master device resulting in access to already freed memory if the master device was removed before the corresponding slave device. And to match this behavior, also forcibly reset that pointer during CloseDownDevices(). Related to CVE-2024-21886, ZDI-CAN-22840 (cherry picked from commit 26769aa71fcbe0a8403b7fb13b7c9010cc07c3a8) --- unix/Xvnc/programs/Xserver/dix/devices.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/unix/Xvnc/programs/Xserver/dix/devices.c b/unix/Xvnc/programs/Xserver/dix/devices.c index 316ddbbdb..bf1aa1cb5 100644 --- a/unix/Xvnc/programs/Xserver/dix/devices.c +++ b/unix/Xvnc/programs/Xserver/dix/devices.c @@ -480,6 +480,13 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) flags[other->id] |= XISlaveDetached; } } + + for (other = inputInfo.off_devices; other; other = other->next) { + if (!IsMaster(other) && GetMaster(other, MASTER_ATTACHED) == dev) { + AttachDevice(NULL, other, NULL); + flags[other->id] |= XISlaveDetached; + } + } } else { for (other = inputInfo.devices; other; other = other->next) { @@ -1076,6 +1083,11 @@ CloseDownDevices(void) dev->master = NULL; } + for (dev = inputInfo.off_devices; dev; dev = dev->next) { + if (!IsMaster(dev) && !IsFloating(dev)) + dev->master = NULL; + } + CloseDeviceList(&inputInfo.devices); CloseDeviceList(&inputInfo.off_devices); From 33efc9cd8dd633d8a6d9b43a98d622a792aa7ca9 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Wed, 6 Dec 2023 12:09:41 +0100 Subject: [PATCH 12/17] glx: Call XACE hooks on the GLX buffer The XSELINUX code will label resources at creation by checking the access mode. When the access mode is DixCreateAccess, it will call the function to label the new resource SELinuxLabelResource(). However, GLX buffers do not go through the XACE hooks when created, hence leaving the resource actually unlabeled. When, later, the client tries to create another resource using that drawable (like a GC for example), the XSELINUX code would try to use the security ID of that object which has never been labeled, get a NULL pointer and crash when checking whether the requested permissions are granted for subject security ID. To avoid the issue, make sure to call the XACE hooks when creating the GLX buffers. Credit goes to Donn Seeley for providing the patch. CVE-2024-0408 Signed-off-by: Olivier Fourdan Acked-by: Peter Hutterer (cherry picked from commit e5e8586a12a3ec915673edffa10dc8fe5e15dac3) --- unix/Xvnc/programs/Xserver/glx/glxcmds.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/unix/Xvnc/programs/Xserver/glx/glxcmds.c b/unix/Xvnc/programs/Xserver/glx/glxcmds.c index c82ce2c78..f493252cb 100644 --- a/unix/Xvnc/programs/Xserver/glx/glxcmds.c +++ b/unix/Xvnc/programs/Xserver/glx/glxcmds.c @@ -48,6 +48,7 @@ #include "indirect_util.h" #include "protocol-versions.h" #include "glxvndabi.h" +#include "xace.h" static char GLXServerVendorName[] = "SGI"; @@ -1379,6 +1380,13 @@ DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId, if (!pPixmap) return BadAlloc; + err = XaceHook(XACE_RESOURCE_ACCESS, client, glxDrawableId, RT_PIXMAP, + pPixmap, RT_NONE, NULL, DixCreateAccess); + if (err != Success) { + (*pGlxScreen->pScreen->DestroyPixmap) (pPixmap); + return err; + } + /* Assign the pixmap the same id as the pbuffer and add it as a * resource so it and the DRI2 drawable will be reclaimed when the * pbuffer is destroyed. */ From d896b7c2abe16baf0c1c11afb385c00f9c4c22fd Mon Sep 17 00:00:00 2001 From: Alan Coopersmith Date: Fri, 22 Mar 2024 18:51:45 -0700 Subject: [PATCH 13/17] Xi: ProcXIGetSelectedEvents needs to use unswapped length to send reply CVE-2024-31080 Reported-by: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=69762 Fixes: 53e821ab4 ("Xi: add request processing for XIGetSelectedEvents.") Signed-off-by: Alan Coopersmith Part-of: (cherry picked from commit 96798fc1967491c80a4d0c8d9e0a80586cb2152b) --- unix/Xvnc/programs/Xserver/Xi/xiselectev.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/unix/Xvnc/programs/Xserver/Xi/xiselectev.c b/unix/Xvnc/programs/Xserver/Xi/xiselectev.c index 0498e0188..b96924237 100644 --- a/unix/Xvnc/programs/Xserver/Xi/xiselectev.c +++ b/unix/Xvnc/programs/Xserver/Xi/xiselectev.c @@ -297,6 +297,7 @@ ProcXIGetSelectedEvents(ClientPtr client) InputClientsPtr others = NULL; xXIEventMask *evmask = NULL; DeviceIntPtr dev; + uint32_t length; REQUEST(xXIGetSelectedEventsReq); REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq); @@ -366,10 +367,12 @@ ProcXIGetSelectedEvents(ClientPtr client) } } + /* save the value before SRepXIGetSelectedEvents swaps it */ + length = reply.length; WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply); if (reply.num_masks) - WriteToClient(client, reply.length * 4, buffer); + WriteToClient(client, length * 4, buffer); free(buffer); return Success; From 27848d452be7fd0c8fc284944f5dca824ceb0e49 Mon Sep 17 00:00:00 2001 From: Alan Coopersmith Date: Fri, 22 Mar 2024 18:56:27 -0700 Subject: [PATCH 14/17] Xi: ProcXIPassiveGrabDevice needs to use unswapped length to send reply CVE-2024-31081 Fixes: d220d6907 ("Xi: add GrabButton and GrabKeysym code.") Signed-off-by: Alan Coopersmith Part-of: (cherry picked from commit 3e77295f888c67fc7645db5d0c00926a29ffecee) --- unix/Xvnc/programs/Xserver/Xi/xipassivegrab.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/unix/Xvnc/programs/Xserver/Xi/xipassivegrab.c b/unix/Xvnc/programs/Xserver/Xi/xipassivegrab.c index 89a591098..bf9b09482 100644 --- a/unix/Xvnc/programs/Xserver/Xi/xipassivegrab.c +++ b/unix/Xvnc/programs/Xserver/Xi/xipassivegrab.c @@ -93,6 +93,7 @@ ProcXIPassiveGrabDevice(ClientPtr client) GrabParameters param; void *tmp; int mask_len; + uint32_t length; REQUEST(xXIPassiveGrabDeviceReq); REQUEST_FIXED_SIZE(xXIPassiveGrabDeviceReq, @@ -234,9 +235,11 @@ ProcXIPassiveGrabDevice(ClientPtr client) } } + /* save the value before SRepXIPassiveGrabDevice swaps it */ + length = rep.length; WriteReplyToClient(client, sizeof(rep), &rep); if (rep.num_modifiers) - WriteToClient(client, rep.length * 4, modifiers_failed); + WriteToClient(client, length * 4, modifiers_failed); out: free(modifiers_failed); From 1b9aa53a5a7a0dde66a9bf70386e719b5f96f0c3 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 30 Jan 2024 13:13:35 +1000 Subject: [PATCH 15/17] render: fix refcounting of glyphs during ProcRenderAddGlyphs Previously, AllocateGlyph would return a new glyph with refcount=0 and a re-used glyph would end up not changing the refcount at all. The resulting glyph_new array would thus have multiple entries pointing to the same non-refcounted glyphs. AddGlyph may free a glyph, resulting in a UAF when the same glyph pointer is then later used. Fix this by returning a refcount of 1 for a new glyph and always incrementing the refcount for a re-used glyph, followed by dropping that refcount back down again when we're done with it. CVE-2024-31083, ZDI-CAN-22880 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative Part-of: (cherry picked from commit bdca6c3d1f5057eeb31609b1280fc93237b00c77) --- unix/Xvnc/programs/Xserver/render/glyph.c | 5 +++-- unix/Xvnc/programs/Xserver/render/glyphstr.h | 2 ++ unix/Xvnc/programs/Xserver/render/render.c | 15 +++++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/unix/Xvnc/programs/Xserver/render/glyph.c b/unix/Xvnc/programs/Xserver/render/glyph.c index f3ed9cf4c..d5fc5f3c9 100644 --- a/unix/Xvnc/programs/Xserver/render/glyph.c +++ b/unix/Xvnc/programs/Xserver/render/glyph.c @@ -245,10 +245,11 @@ FreeGlyphPicture(GlyphPtr glyph) } } -static void +void FreeGlyph(GlyphPtr glyph, int format) { CheckDuplicates(&globalGlyphs[format], "FreeGlyph"); + BUG_RETURN(glyph->refcnt == 0); if (--glyph->refcnt == 0) { GlyphRefPtr gr; int i; @@ -354,7 +355,7 @@ AllocateGlyph(xGlyphInfo * gi, int fdepth) glyph = (GlyphPtr) malloc(size); if (!glyph) return 0; - glyph->refcnt = 0; + glyph->refcnt = 1; glyph->size = size + sizeof(xGlyphInfo); glyph->info = *gi; dixInitPrivates(glyph, (char *) glyph + head_size, PRIVATE_GLYPH); diff --git a/unix/Xvnc/programs/Xserver/render/glyphstr.h b/unix/Xvnc/programs/Xserver/render/glyphstr.h index 2f51bd244..e8034556d 100644 --- a/unix/Xvnc/programs/Xserver/render/glyphstr.h +++ b/unix/Xvnc/programs/Xserver/render/glyphstr.h @@ -109,6 +109,8 @@ extern GlyphPtr FindGlyph(GlyphSetPtr glyphSet, Glyph id); extern GlyphPtr AllocateGlyph(xGlyphInfo * gi, int format); +extern void FreeGlyph(GlyphPtr glyph, int format); + extern Bool ResizeGlyphSet(GlyphSetPtr glyphSet, CARD32 change); diff --git a/unix/Xvnc/programs/Xserver/render/render.c b/unix/Xvnc/programs/Xserver/render/render.c index 456f156d4..5bc2a204b 100644 --- a/unix/Xvnc/programs/Xserver/render/render.c +++ b/unix/Xvnc/programs/Xserver/render/render.c @@ -1076,6 +1076,7 @@ ProcRenderAddGlyphs(ClientPtr client) if (glyph_new->glyph && glyph_new->glyph != DeletedGlyph) { glyph_new->found = TRUE; + ++glyph_new->glyph->refcnt; } else { GlyphPtr glyph; @@ -1168,8 +1169,10 @@ ProcRenderAddGlyphs(ClientPtr client) err = BadAlloc; goto bail; } - for (i = 0; i < nglyphs; i++) + for (i = 0; i < nglyphs; i++) { AddGlyph(glyphSet, glyphs[i].glyph, glyphs[i].id); + FreeGlyph(glyphs[i].glyph, glyphSet->fdepth); + } if (glyphsBase != glyphsLocal) free(glyphsBase); @@ -1179,9 +1182,13 @@ ProcRenderAddGlyphs(ClientPtr client) FreePicture((void *) pSrc, 0); if (pSrcPix) FreeScratchPixmapHeader(pSrcPix); - for (i = 0; i < nglyphs; i++) - if (glyphs[i].glyph && !glyphs[i].found) - free(glyphs[i].glyph); + for (i = 0; i < nglyphs; i++) { + if (glyphs[i].glyph) { + --glyphs[i].glyph->refcnt; + if (!glyphs[i].found) + free(glyphs[i].glyph); + } + } if (glyphsBase != glyphsLocal) free(glyphsBase); return err; From cab07e50c7a7f5d9f0e6aaca607da6b0620d887f Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Thu, 10 Oct 2024 10:37:28 +0200 Subject: [PATCH 16/17] xkb: Fix buffer overflow in _XkbSetCompatMap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The _XkbSetCompatMap() function attempts to resize the `sym_interpret` buffer. However, It didn't update its size properly. It updated `num_si` only, without updating `size_si`. This may lead to local privilege escalation if the server is run as root or remote code execution (e.g. x11 over ssh). CVE-2024-9632, ZDI-CAN-24756 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative Reviewed-by: Peter Hutterer Tested-by: Peter Hutterer Reviewed-by: José Expósito Part-of: --- unix/Xvnc/programs/Xserver/xkb/xkb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/unix/Xvnc/programs/Xserver/xkb/xkb.c b/unix/Xvnc/programs/Xserver/xkb/xkb.c index 3363b1d68..7b5c623fe 100644 --- a/unix/Xvnc/programs/Xserver/xkb/xkb.c +++ b/unix/Xvnc/programs/Xserver/xkb/xkb.c @@ -2993,13 +2993,13 @@ _XkbSetCompatMap(ClientPtr client, DeviceIntPtr dev, XkbSymInterpretPtr sym; unsigned int skipped = 0; - if ((unsigned) (req->firstSI + req->nSI) > compat->num_si) { - compat->num_si = req->firstSI + req->nSI; + if ((unsigned) (req->firstSI + req->nSI) > compat->size_si) { + compat->num_si = compat->size_si = req->firstSI + req->nSI; compat->sym_interpret = reallocarray(compat->sym_interpret, - compat->num_si, + compat->size_si, sizeof(XkbSymInterpretRec)); if (!compat->sym_interpret) { - compat->num_si = 0; + compat->num_si = compat->size_si = 0; return BadAlloc; } } From f071dba584f1f7f43e621601dc60debed0834d43 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 19 Dec 2024 13:47:35 -0500 Subject: [PATCH 17/17] Document xorg-server 21.1.x security patches (+ add them to our xorg-server patch) Fixes #433 --- ChangeLog.md | 5 + unix/Xvnc/programs/Xserver/turbovnc.patch | 646 +++++++++++++++++++++- 2 files changed, 641 insertions(+), 10 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 390ed2433..0a55c4c3c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -12,6 +12,11 @@ SSH client now allows the value of the `SSHPort` parameter, if specified on the command line or in a connection info file, to override any SSH ports specified in the OpenSSH config file. +3. The TurboVNC Server now includes various security fixes (CVE-2023-5367, +CVE-2023-6377, CVE-2023-6478, CVE-2023-6816, CVE-2024-0229, CVE-2024-0408, +CVE-2024-9632, CVE-2024-21885, CVE-2024-21886, CVE-2024-31080, CVE-2024-31081, +and CVE-2024-31083) from the xorg-server 21.1.x code base. + 3.1.3 ===== diff --git a/unix/Xvnc/programs/Xserver/turbovnc.patch b/unix/Xvnc/programs/Xserver/turbovnc.patch index eacee6f8a..ffc3952aa 100644 --- a/unix/Xvnc/programs/Xserver/turbovnc.patch +++ b/unix/Xvnc/programs/Xserver/turbovnc.patch @@ -77,12 +77,33 @@ index c520c7d..5f4c174 100644 } if (!tpn->client) diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/exevents.c b/Xserver/Xi/exevents.c -index 659816a..0cb8d78 100644 +index 659816a..1930089 100644 --- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/exevents.c +++ b/Xserver/Xi/exevents.c -@@ -575,8 +575,10 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to) +@@ -561,22 +561,25 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to) + to->button = calloc(1, sizeof(ButtonClassRec)); + if (!to->button) + FatalError("[Xi] no memory for class shift.\n"); ++ to->button->numButtons = from->button->numButtons; + } + else + classes->button = NULL; + } + + if (from->button->xkb_acts) { +- if (!to->button->xkb_acts) { +- to->button->xkb_acts = calloc(1, sizeof(XkbAction)); +- if (!to->button->xkb_acts) +- FatalError("[Xi] not enough memory for xkb_acts.\n"); +- } ++ size_t maxbuttons = max(to->button->numButtons, from->button->numButtons); ++ to->button->xkb_acts = xnfreallocarray(to->button->xkb_acts, ++ maxbuttons, ++ sizeof(XkbAction)); ++ memset(to->button->xkb_acts, 0, maxbuttons * sizeof(XkbAction)); memcpy(to->button->xkb_acts, from->button->xkb_acts, - sizeof(XkbAction)); +- sizeof(XkbAction)); ++ from->button->numButtons * sizeof(XkbAction)); } - else + else { @@ -93,7 +114,7 @@ index 659816a..0cb8d78 100644 memcpy(to->button->labels, from->button->labels, from->button->numButtons * sizeof(Atom)); diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/xichangehierarchy.c b/Xserver/Xi/xichangehierarchy.c -index 504defe..ad89a31 100644 +index 504defe..cb0c6df 100644 --- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/xichangehierarchy.c +++ b/Xserver/Xi/xichangehierarchy.c @@ -140,7 +140,7 @@ add_master(ClientPtr client, xXIAddMasterInfo * c, int flags[MAXDEVICES]) @@ -132,11 +153,92 @@ index 504defe..ad89a31 100644 XIBarrierRemoveMasterDevice(clients[i], ptr->id); /* disable the remove the devices, XTest devices must be done first +@@ -416,6 +416,11 @@ ProcXIChangeHierarchy(ClientPtr client) + size_t len; /* length of data remaining in request */ + int rc = Success; + int flags[MAXDEVICES] = { 0 }; ++ enum { ++ NO_CHANGE, ++ FLUSH, ++ CHANGED, ++ } changes = NO_CHANGE; + + REQUEST(xXIChangeHierarchyReq); + REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq); +@@ -465,8 +470,9 @@ ProcXIChangeHierarchy(ClientPtr client) + rc = add_master(client, c, flags); + if (rc != Success) + goto unwind; +- } ++ changes = FLUSH; + break; ++ } + case XIRemoveMaster: + { + xXIRemoveMasterInfo *r = (xXIRemoveMasterInfo *) any; +@@ -475,8 +481,9 @@ ProcXIChangeHierarchy(ClientPtr client) + rc = remove_master(client, r, flags); + if (rc != Success) + goto unwind; +- } ++ changes = FLUSH; + break; ++ } + case XIDetachSlave: + { + xXIDetachSlaveInfo *c = (xXIDetachSlaveInfo *) any; +@@ -485,8 +492,9 @@ ProcXIChangeHierarchy(ClientPtr client) + rc = detach_slave(client, c, flags); + if (rc != Success) + goto unwind; +- } ++ changes = CHANGED; + break; ++ } + case XIAttachSlave: + { + xXIAttachSlaveInfo *c = (xXIAttachSlaveInfo *) any; +@@ -495,16 +503,25 @@ ProcXIChangeHierarchy(ClientPtr client) + rc = attach_slave(client, c, flags); + if (rc != Success) + goto unwind; ++ changes = CHANGED; ++ break; + } ++ default: + break; + } + ++ if (changes == FLUSH) { ++ XISendDeviceHierarchyEvent(flags); ++ memset(flags, 0, sizeof(flags)); ++ changes = NO_CHANGE; ++ } ++ + len -= any->length * 4; + any = (xXIAnyHierarchyChangeInfo *) ((char *) any + any->length * 4); + } + + unwind: +- +- XISendDeviceHierarchyEvent(flags); ++ if (changes != NO_CHANGE) ++ XISendDeviceHierarchyEvent(flags); + return rc; + } diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/xipassivegrab.c b/Xserver/Xi/xipassivegrab.c -index d30f51f..89a5910 100644 +index d30f51f..bf9b094 100644 --- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/xipassivegrab.c +++ b/Xserver/Xi/xipassivegrab.c -@@ -133,6 +133,12 @@ ProcXIPassiveGrabDevice(ClientPtr client) +@@ -93,6 +93,7 @@ ProcXIPassiveGrabDevice(ClientPtr client) + GrabParameters param; + void *tmp; + int mask_len; ++ uint32_t length; + + REQUEST(xXIPassiveGrabDeviceReq); + REQUEST_FIXED_SIZE(xXIPassiveGrabDeviceReq, +@@ -133,6 +134,12 @@ ProcXIPassiveGrabDevice(ClientPtr client) return BadValue; } @@ -149,7 +251,7 @@ index d30f51f..89a5910 100644 if (XICheckInvalidMaskBits(client, (unsigned char *) &stuff[1], stuff->mask_len * 4) != Success) return BadValue; -@@ -203,14 +209,8 @@ ProcXIPassiveGrabDevice(ClientPtr client) +@@ -203,14 +210,8 @@ ProcXIPassiveGrabDevice(ClientPtr client) ¶m, XI2, &mask); break; case XIGrabtypeKeycode: @@ -166,7 +268,20 @@ index d30f51f..89a5910 100644 break; case XIGrabtypeEnter: case XIGrabtypeFocusIn: -@@ -319,6 +319,12 @@ ProcXIPassiveUngrabDevice(ClientPtr client) +@@ -234,9 +235,11 @@ ProcXIPassiveGrabDevice(ClientPtr client) + } + } + ++ /* save the value before SRepXIPassiveGrabDevice swaps it */ ++ length = rep.length; + WriteReplyToClient(client, sizeof(rep), &rep); + if (rep.num_modifiers) +- WriteToClient(client, rep.length * 4, modifiers_failed); ++ WriteToClient(client, length * 4, modifiers_failed); + + out: + free(modifiers_failed); +@@ -319,6 +322,12 @@ ProcXIPassiveUngrabDevice(ClientPtr client) return BadValue; } @@ -180,9 +295,27 @@ index d30f51f..89a5910 100644 if (rc != Success) return rc; diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/xiproperty.c b/Xserver/Xi/xiproperty.c -index 6ec419e..0cfa6e3 100644 +index 6ec419e..172ddac 100644 --- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/xiproperty.c +++ b/Xserver/Xi/xiproperty.c +@@ -730,7 +730,7 @@ XIChangeDeviceProperty(DeviceIntPtr dev, Atom property, Atom type, + XIDestroyDeviceProperty(prop); + return BadAlloc; + } +- new_value.size = len; ++ new_value.size = total_len; + new_value.type = type; + new_value.format = format; + +@@ -747,7 +747,7 @@ XIChangeDeviceProperty(DeviceIntPtr dev, Atom property, Atom type, + case PropModePrepend: + new_data = new_value.data; + old_data = (void *) (((char *) new_value.data) + +- (prop_value->size * size_in_bytes)); ++ (len * size_in_bytes)); + break; + } + if (new_data) @@ -890,7 +890,7 @@ ProcXChangeDeviceProperty(ClientPtr client) REQUEST(xChangeDevicePropertyReq); DeviceIntPtr dev; @@ -201,6 +334,46 @@ index 6ec419e..0cfa6e3 100644 unsigned long len; REQUEST(xXIChangePropertyReq); +diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/xiquerypointer.c b/Xserver/Xi/xiquerypointer.c +index 5b77b1a..2b05ac5 100644 +--- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/xiquerypointer.c ++++ b/Xserver/Xi/xiquerypointer.c +@@ -149,8 +149,7 @@ ProcXIQueryPointer(ClientPtr client) + if (pDev->button) { + int i; + +- rep.buttons_len = +- bytes_to_int32(bits_to_bytes(pDev->button->numButtons)); ++ rep.buttons_len = bytes_to_int32(bits_to_bytes(256)); /* button map up to 255 */ + rep.length += rep.buttons_len; + buttons = calloc(rep.buttons_len, 4); + if (!buttons) +diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/xiselectev.c b/Xserver/Xi/xiselectev.c +index 0498e01..b969242 100644 +--- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/Xi/xiselectev.c ++++ b/Xserver/Xi/xiselectev.c +@@ -297,6 +297,7 @@ ProcXIGetSelectedEvents(ClientPtr client) + InputClientsPtr others = NULL; + xXIEventMask *evmask = NULL; + DeviceIntPtr dev; ++ uint32_t length; + + REQUEST(xXIGetSelectedEventsReq); + REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq); +@@ -366,10 +367,12 @@ ProcXIGetSelectedEvents(ClientPtr client) + } + } + ++ /* save the value before SRepXIGetSelectedEvents swaps it */ ++ length = reply.length; + WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply); + + if (reply.num_masks) +- WriteToClient(client, reply.length * 4, buffer); ++ WriteToClient(client, length * 4, buffer); + + free(buffer); + return Success; diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/composite/compwindow.c b/Xserver/composite/compwindow.c index 54b4e6a..8db9d03 100644 --- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/composite/compwindow.c @@ -217,6 +390,291 @@ index 54b4e6a..8db9d03 100644 /* compCheckTree (pWin->drawable.pScreen); can't check -- tree isn't good*/ return ret; } +diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/dix/devices.c b/Xserver/dix/devices.c +index e7c74d7..bf1aa1c 100644 +--- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/dix/devices.c ++++ b/Xserver/dix/devices.c +@@ -451,14 +451,20 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) + { + DeviceIntPtr *prev, other; + BOOL enabled; ++ BOOL dev_in_devices_list = FALSE; + int flags[MAXDEVICES] = { 0 }; + + if (!dev->enabled) + return TRUE; + +- for (prev = &inputInfo.devices; +- *prev && (*prev != dev); prev = &(*prev)->next); +- if (*prev != dev) ++ for (other = inputInfo.devices; other; other = other->next) { ++ if (other == dev) { ++ dev_in_devices_list = TRUE; ++ break; ++ } ++ } ++ ++ if (!dev_in_devices_list) + return FALSE; + + TouchEndPhysicallyActiveTouches(dev); +@@ -474,6 +480,13 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) + flags[other->id] |= XISlaveDetached; + } + } ++ ++ for (other = inputInfo.off_devices; other; other = other->next) { ++ if (!IsMaster(other) && GetMaster(other, MASTER_ATTACHED) == dev) { ++ AttachDevice(NULL, other, NULL); ++ flags[other->id] |= XISlaveDetached; ++ } ++ } + } + else { + for (other = inputInfo.devices; other; other = other->next) { +@@ -508,6 +521,9 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) + LeaveWindow(dev); + SetFocusOut(dev); + ++ for (prev = &inputInfo.devices; ++ *prev && (*prev != dev); prev = &(*prev)->next); ++ + *prev = dev->next; + dev->next = inputInfo.off_devices; + inputInfo.off_devices = dev; +@@ -1067,6 +1083,11 @@ CloseDownDevices(void) + dev->master = NULL; + } + ++ for (dev = inputInfo.off_devices; dev; dev = dev->next) { ++ if (!IsMaster(dev) && !IsFloating(dev)) ++ dev->master = NULL; ++ } ++ + CloseDeviceList(&inputInfo.devices); + CloseDeviceList(&inputInfo.off_devices); + +@@ -2502,6 +2523,8 @@ RecalculateMasterButtons(DeviceIntPtr slave) + + if (master->button && master->button->numButtons != maxbuttons) { + int i; ++ int last_num_buttons = master->button->numButtons; ++ + DeviceChangedEvent event = { + .header = ET_Internal, + .type = ET_DeviceChanged, +@@ -2512,6 +2535,14 @@ RecalculateMasterButtons(DeviceIntPtr slave) + }; + + master->button->numButtons = maxbuttons; ++ if (last_num_buttons < maxbuttons) { ++ master->button->xkb_acts = xnfreallocarray(master->button->xkb_acts, ++ maxbuttons, ++ sizeof(XkbAction)); ++ memset(&master->button->xkb_acts[last_num_buttons], ++ 0, ++ (maxbuttons - last_num_buttons) * sizeof(XkbAction)); ++ } + + memcpy(&event.buttons.names, master->button->labels, maxbuttons * + sizeof(Atom)); +diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/dix/enterleave.c b/Xserver/dix/enterleave.c +index a2f625b..72a953f 100644 +--- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/dix/enterleave.c ++++ b/Xserver/dix/enterleave.c +@@ -615,9 +615,15 @@ FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v, + + ev->type = DeviceValuator; + ev->deviceid = dev->id; +- ev->num_valuators = nval < 3 ? nval : 3; ++ ev->num_valuators = nval < 6 ? nval : 6; + ev->first_valuator = first; + switch (ev->num_valuators) { ++ case 6: ++ ev->valuator2 = v->axisVal[first + 5]; ++ case 5: ++ ev->valuator2 = v->axisVal[first + 4]; ++ case 4: ++ ev->valuator2 = v->axisVal[first + 3]; + case 3: + ev->valuator2 = v->axisVal[first + 2]; + case 2: +@@ -626,7 +632,6 @@ FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v, + ev->valuator0 = v->axisVal[first]; + break; + } +- first += ev->num_valuators; + } + + static void +@@ -646,7 +651,7 @@ FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, + ev->num_buttons = b->numButtons; + memcpy((char *) ev->buttons, (char *) b->down, 4); + } +- else if (k) { ++ if (k) { + ev->classes_reported |= (1 << KeyClass); + ev->num_keys = k->xkbInfo->desc->max_key_code - + k->xkbInfo->desc->min_key_code; +@@ -670,14 +675,26 @@ FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, + } + } + +- ++/** ++ * The device state notify event is split across multiple 32-byte events. ++ * The first one contains the first 32 button state bits, the first 32 ++ * key state bits, and the first 3 valuator values. ++ * ++ * If a device has more than that, the server sends out: ++ * - one deviceButtonStateNotify for buttons 32 and above ++ * - one deviceKeyStateNotify for keys 32 and above ++ * - one deviceValuator event per 6 valuators above valuator 4 ++ * ++ * All events but the last one have the deviceid binary ORed with MORE_EVENTS, ++ */ + static void + DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win) + { ++ /* deviceStateNotify, deviceKeyStateNotify, deviceButtonStateNotify ++ * and one deviceValuator for each 6 valuators */ ++ deviceStateNotify sev[3 + (MAX_VALUATORS + 6)/6]; + int evcount = 1; +- deviceStateNotify *ev, *sev; +- deviceKeyStateNotify *kev; +- deviceButtonStateNotify *bev; ++ deviceStateNotify *ev = sev; + + KeyClassPtr k; + ButtonClassPtr b; +@@ -690,87 +707,53 @@ DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win) + + if ((b = dev->button) != NULL) { + nbuttons = b->numButtons; +- if (nbuttons > 32) ++ if (nbuttons > 32) /* first 32 are encoded in deviceStateNotify */ + evcount++; + } + if ((k = dev->key) != NULL) { + nkeys = k->xkbInfo->desc->max_key_code - k->xkbInfo->desc->min_key_code; +- if (nkeys > 32) ++ if (nkeys > 32) /* first 32 are encoded in deviceStateNotify */ + evcount++; +- if (nbuttons > 0) { +- evcount++; +- } + } + if ((v = dev->valuator) != NULL) { + nval = v->numAxes; +- +- if (nval > 3) +- evcount++; +- if (nval > 6) { +- if (!(k && b)) +- evcount++; +- if (nval > 9) +- evcount += ((nval - 7) / 3); +- } ++ /* first three are encoded in deviceStateNotify, then ++ * it's 6 per deviceValuator event */ ++ evcount += ((nval - 3) + 6)/6; + } + +- sev = ev = xallocarray(evcount, sizeof(xEvent)); +- FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first); +- +- if (b != NULL) { +- FixDeviceStateNotify(dev, ev++, NULL, b, v, first); +- first += 3; +- nval -= 3; +- if (nbuttons > 32) { +- (ev - 1)->deviceid |= MORE_EVENTS; +- bev = (deviceButtonStateNotify *) ev++; +- bev->type = DeviceButtonStateNotify; +- bev->deviceid = dev->id; +- memcpy((char *) &bev->buttons[4], (char *) &b->down[4], +- DOWN_LENGTH - 4); +- } +- if (nval > 0) { +- (ev - 1)->deviceid |= MORE_EVENTS; +- FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); +- first += 3; +- nval -= 3; +- } ++ BUG_RETURN(evcount <= ARRAY_SIZE(sev)); ++ ++ FixDeviceStateNotify(dev, ev, k, b, v, first); ++ ++ if (b != NULL && nbuttons > 32) { ++ deviceButtonStateNotify *bev = (deviceButtonStateNotify *) ++ev; ++ (ev - 1)->deviceid |= MORE_EVENTS; ++ bev->type = DeviceButtonStateNotify; ++ bev->deviceid = dev->id; ++ memcpy((char *) &bev->buttons[4], (char *) &b->down[4], ++ DOWN_LENGTH - 4); + } + +- if (k != NULL) { +- FixDeviceStateNotify(dev, ev++, k, NULL, v, first); +- first += 3; +- nval -= 3; +- if (nkeys > 32) { +- (ev - 1)->deviceid |= MORE_EVENTS; +- kev = (deviceKeyStateNotify *) ev++; +- kev->type = DeviceKeyStateNotify; +- kev->deviceid = dev->id; +- memmove((char *) &kev->keys[0], (char *) &k->down[4], 28); +- } +- if (nval > 0) { +- (ev - 1)->deviceid |= MORE_EVENTS; +- FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); +- first += 3; +- nval -= 3; +- } ++ if (k != NULL && nkeys > 32) { ++ deviceKeyStateNotify *kev = (deviceKeyStateNotify *) ++ev; ++ (ev - 1)->deviceid |= MORE_EVENTS; ++ kev->type = DeviceKeyStateNotify; ++ kev->deviceid = dev->id; ++ memmove((char *) &kev->keys[0], (char *) &k->down[4], 28); + } + ++ first = 3; ++ nval -= 3; + while (nval > 0) { +- FixDeviceStateNotify(dev, ev++, NULL, NULL, v, first); +- first += 3; +- nval -= 3; +- if (nval > 0) { +- (ev - 1)->deviceid |= MORE_EVENTS; +- FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); +- first += 3; +- nval -= 3; +- } ++ ev->deviceid |= MORE_EVENTS; ++ FixDeviceValuator(dev, (deviceValuator *) ++ev, v, first); ++ first += 6; ++ nval -= 6; + } + + DeliverEventsToWindow(dev, win, (xEvent *) sev, evcount, + DeviceStateNotifyMask, NullGrab); +- free(sev); + } + + void +@@ -784,8 +767,9 @@ DeviceFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, + + mouse = IsFloating(dev) ? dev : GetMaster(dev, MASTER_POINTER); + +- /* XI 2 event */ +- btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; ++ /* XI 2 event contains the logical button map - maps are CARD8 ++ * so we need 256 bits for the possibly maximum mapping */ ++ btlen = (mouse->button) ? bits_to_bytes(256) : 0; + btlen = bytes_to_int32(btlen); + len = sizeof(xXIFocusInEvent) + btlen * 4; + diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/dix/events.c b/Xserver/dix/events.c index 427b891..0f32bd8 100644 --- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/dix/events.c @@ -397,6 +855,32 @@ index bd24728..801df20 100644 dst[i] &= pm; } } +diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/glx/glxcmds.c b/Xserver/glx/glxcmds.c +index c82ce2c..f493252 100644 +--- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/glx/glxcmds.c ++++ b/Xserver/glx/glxcmds.c +@@ -48,6 +48,7 @@ + #include "indirect_util.h" + #include "protocol-versions.h" + #include "glxvndabi.h" ++#include "xace.h" + + static char GLXServerVendorName[] = "SGI"; + +@@ -1379,6 +1380,13 @@ DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId, + if (!pPixmap) + return BadAlloc; + ++ err = XaceHook(XACE_RESOURCE_ACCESS, client, glxDrawableId, RT_PIXMAP, ++ pPixmap, RT_NONE, NULL, DixCreateAccess); ++ if (err != Success) { ++ (*pGlxScreen->pScreen->DestroyPixmap) (pPixmap); ++ return err; ++ } ++ + /* Assign the pixmap the same id as the pbuffer and add it as a + * resource so it and the DRI2 drawable will be reclaimed when the + * pbuffer is destroyed. */ diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/glx/glxdricommon.c b/Xserver/glx/glxdricommon.c index 2e00bab..a16e1bc 100644 --- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/glx/glxdricommon.c @@ -560,6 +1044,130 @@ index d34025b..d76a24d 100644 mode = malloc(sizeof(RRModeRec) + modeInfo->nameLength + 1); if (!mode) return NULL; +diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/randr/rrproperty.c b/Xserver/randr/rrproperty.c +index c2fb958..c4fef8a 100644 +--- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/randr/rrproperty.c ++++ b/Xserver/randr/rrproperty.c +@@ -209,7 +209,7 @@ RRChangeOutputProperty(RROutputPtr output, Atom property, Atom type, + RRDestroyOutputProperty(prop); + return BadAlloc; + } +- new_value.size = len; ++ new_value.size = total_len; + new_value.type = type; + new_value.format = format; + +@@ -226,7 +226,7 @@ RRChangeOutputProperty(RROutputPtr output, Atom property, Atom type, + case PropModePrepend: + new_data = new_value.data; + old_data = (void *) (((char *) new_value.data) + +- (prop_value->size * size_in_bytes)); ++ (len * size_in_bytes)); + break; + } + if (new_data) +@@ -530,7 +530,7 @@ ProcRRChangeOutputProperty(ClientPtr client) + char format, mode; + unsigned long len; + int sizeInBytes; +- int totalSize; ++ uint64_t totalSize; + int err; + + REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq); +diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/randr/rrproviderproperty.c b/Xserver/randr/rrproviderproperty.c +index b79c17f..90c5a9a 100644 +--- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/randr/rrproviderproperty.c ++++ b/Xserver/randr/rrproviderproperty.c +@@ -498,7 +498,7 @@ ProcRRChangeProviderProperty(ClientPtr client) + char format, mode; + unsigned long len; + int sizeInBytes; +- int totalSize; ++ uint64_t totalSize; + int err; + + REQUEST_AT_LEAST_SIZE(xRRChangeProviderPropertyReq); +diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/render/glyph.c b/Xserver/render/glyph.c +index f3ed9cf..d5fc5f3 100644 +--- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/render/glyph.c ++++ b/Xserver/render/glyph.c +@@ -245,10 +245,11 @@ FreeGlyphPicture(GlyphPtr glyph) + } + } + +-static void ++void + FreeGlyph(GlyphPtr glyph, int format) + { + CheckDuplicates(&globalGlyphs[format], "FreeGlyph"); ++ BUG_RETURN(glyph->refcnt == 0); + if (--glyph->refcnt == 0) { + GlyphRefPtr gr; + int i; +@@ -354,7 +355,7 @@ AllocateGlyph(xGlyphInfo * gi, int fdepth) + glyph = (GlyphPtr) malloc(size); + if (!glyph) + return 0; +- glyph->refcnt = 0; ++ glyph->refcnt = 1; + glyph->size = size + sizeof(xGlyphInfo); + glyph->info = *gi; + dixInitPrivates(glyph, (char *) glyph + head_size, PRIVATE_GLYPH); +diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/render/glyphstr.h b/Xserver/render/glyphstr.h +index 2f51bd2..e803455 100644 +--- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/render/glyphstr.h ++++ b/Xserver/render/glyphstr.h +@@ -109,6 +109,8 @@ extern GlyphPtr FindGlyph(GlyphSetPtr glyphSet, Glyph id); + + extern GlyphPtr AllocateGlyph(xGlyphInfo * gi, int format); + ++extern void FreeGlyph(GlyphPtr glyph, int format); ++ + extern Bool + ResizeGlyphSet(GlyphSetPtr glyphSet, CARD32 change); + +diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/render/render.c b/Xserver/render/render.c +index 456f156..5bc2a20 100644 +--- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/render/render.c ++++ b/Xserver/render/render.c +@@ -1076,6 +1076,7 @@ ProcRenderAddGlyphs(ClientPtr client) + + if (glyph_new->glyph && glyph_new->glyph != DeletedGlyph) { + glyph_new->found = TRUE; ++ ++glyph_new->glyph->refcnt; + } + else { + GlyphPtr glyph; +@@ -1168,8 +1169,10 @@ ProcRenderAddGlyphs(ClientPtr client) + err = BadAlloc; + goto bail; + } +- for (i = 0; i < nglyphs; i++) ++ for (i = 0; i < nglyphs; i++) { + AddGlyph(glyphSet, glyphs[i].glyph, glyphs[i].id); ++ FreeGlyph(glyphs[i].glyph, glyphSet->fdepth); ++ } + + if (glyphsBase != glyphsLocal) + free(glyphsBase); +@@ -1179,9 +1182,13 @@ ProcRenderAddGlyphs(ClientPtr client) + FreePicture((void *) pSrc, 0); + if (pSrcPix) + FreeScratchPixmapHeader(pSrcPix); +- for (i = 0; i < nglyphs; i++) +- if (glyphs[i].glyph && !glyphs[i].found) +- free(glyphs[i].glyph); ++ for (i = 0; i < nglyphs; i++) { ++ if (glyphs[i].glyph) { ++ --glyphs[i].glyph->refcnt; ++ if (!glyphs[i].found) ++ free(glyphs[i].glyph); ++ } ++ } + if (glyphsBase != glyphsLocal) + free(glyphsBase); + return err; diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/xfixes/xfixes.c b/Xserver/xfixes/xfixes.c index 53a6bd6..28248d4 100644 --- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/xfixes/xfixes.c @@ -593,9 +1201,27 @@ index 53a6bd6..28248d4 100644 ProcXFixesDispatch, SProcXFixesDispatch, NULL, StandardMinorOpcode)) != 0) { diff --git a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/xkb/xkb.c b/Xserver/xkb/xkb.c -index 68c59df..3363b1d 100644 +index 68c59df..7b5c623 100644 --- a/xserver-dbf6d1c24a00a1f598756c71028876ff2b3db17f/xkb/xkb.c +++ b/Xserver/xkb/xkb.c +@@ -2993,13 +2993,13 @@ _XkbSetCompatMap(ClientPtr client, DeviceIntPtr dev, + XkbSymInterpretPtr sym; + unsigned int skipped = 0; + +- if ((unsigned) (req->firstSI + req->nSI) > compat->num_si) { +- compat->num_si = req->firstSI + req->nSI; ++ if ((unsigned) (req->firstSI + req->nSI) > compat->size_si) { ++ compat->num_si = compat->size_si = req->firstSI + req->nSI; + compat->sym_interpret = reallocarray(compat->sym_interpret, +- compat->num_si, ++ compat->size_si, + sizeof(XkbSymInterpretRec)); + if (!compat->sym_interpret) { +- compat->num_si = 0; ++ compat->num_si = compat->size_si = 0; + return BadAlloc; + } + } @@ -5157,7 +5157,7 @@ _GetCountedString(char **wire_inout, ClientPtr client, char **str) }