diff --git a/SOURCES/0001-Avoid-recursing-through-_XError-due-to-sequence-adju.patch b/SOURCES/0001-Avoid-recursing-through-_XError-due-to-sequence-adju.patch new file mode 100644 index 0000000..7135626 --- /dev/null +++ b/SOURCES/0001-Avoid-recursing-through-_XError-due-to-sequence-adju.patch @@ -0,0 +1,166 @@ +From 8c92ef59890c6d6e2be456658d3b9c145eda8629 Mon Sep 17 00:00:00 2001 +From: Keith Packard +Date: Sat, 7 Nov 2020 22:22:47 -0800 +Subject: [PATCH libX11] Avoid recursing through _XError due to sequence + adjustment + +This patch is based on research done by Dmitry Osipenko to uncover the +cause of a large class of Xlib lockups. + +_XError must unlock and re-lock the display around the call to the +user error handler function. When re-locking the display, two +functions are called to ensure that the display is ready to generate a request: + + _XIDHandler(dpy); + _XSeqSyncFunction(dpy); + +The first ensures that there is at least one XID available to use +(possibly calling _xcb_generate_id to do so). The second makes sure a +reply is received at least every 65535 requests to keep sequence +numbers in sync (possibly generating a GetInputFocus request and +synchronously awaiting the reply). + +If the second of these does generate a GetInputFocus request and wait +for the reply, then a pending error will cause recursion into _XError, +which deadlocks the display. + +One seemingly easy fix is to have _XError avoid those calls by +invoking InternalLockDisplay instead of LockDisplay. That function +does everything that LockDisplay does *except* call those final two +functions which may end up receiving an error. + +However, that doesn't protect the system from applications which call +some legal Xlib function from within their error handler. Any Xlib +function which cannot generate protocol or wait for events is valid, +including many which invoke LockDisplay. + +What we need to do is make LockDisplay skip these two function calls +precisely when it is called from within the _XError context for the +same display. + +This patch accomplishes this by creating a list of threads in the +display which are in _XError, and then having LockDisplay check the +current thread against those list elements. + +Inspired-by: Dmitry Osipenko +Signed-off-by: Keith Packard +Tested-by: Dmitry Osipenko +Reviewed-by: Dmitry Osipenko +(cherry picked from commit 30ccef3a48029bf4fc31d4abda2d2778d0ad6277) +--- + include/X11/Xlibint.h | 2 ++ + src/OpenDis.c | 1 + + src/XlibInt.c | 10 ++++++++++ + src/locking.c | 12 ++++++++++++ + src/locking.h | 12 ++++++++++++ + 5 files changed, 37 insertions(+) + +diff --git a/include/X11/Xlibint.h b/include/X11/Xlibint.h +index 6b95bcf7..09078e3f 100644 +--- a/include/X11/Xlibint.h ++++ b/include/X11/Xlibint.h +@@ -202,6 +202,8 @@ struct _XDisplay + unsigned long last_request_read_upper32bit; + unsigned long request_upper32bit; + #endif ++ ++ struct _XErrorThreadInfo *error_threads; + }; + + #define XAllocIDs(dpy,ids,n) (*(dpy)->idlist_alloc)(dpy,ids,n) +diff --git a/src/OpenDis.c b/src/OpenDis.c +index 82723578..85901168 100644 +--- a/src/OpenDis.c ++++ b/src/OpenDis.c +@@ -201,6 +201,7 @@ XOpenDisplay ( + X_DPY_SET_LAST_REQUEST_READ(dpy, 0); + dpy->default_screen = iscreen; /* Value returned by ConnectDisplay */ + dpy->last_req = (char *)&_dummy_request; ++ dpy->error_threads = NULL; + + /* Initialize the display lock */ + if (InitDisplayLock(dpy) != 0) { +diff --git a/src/XlibInt.c b/src/XlibInt.c +index 4e45e62b..8771b791 100644 +--- a/src/XlibInt.c ++++ b/src/XlibInt.c +@@ -1482,6 +1482,11 @@ int _XError ( + if (_XErrorFunction != NULL) { + int rtn_val; + #ifdef XTHREADS ++ struct _XErrorThreadInfo thread_info = { ++ .error_thread = xthread_self(), ++ .next = dpy->error_threads ++ }, **prev; ++ dpy->error_threads = &thread_info; + if (dpy->lock) + (*dpy->lock->user_lock_display)(dpy); + UnlockDisplay(dpy); +@@ -1491,6 +1496,11 @@ int _XError ( + LockDisplay(dpy); + if (dpy->lock) + (*dpy->lock->user_unlock_display)(dpy); ++ ++ /* unlink thread_info from the list */ ++ for (prev = &dpy->error_threads; *prev != &thread_info; prev = &(*prev)->next) ++ ; ++ *prev = thread_info.next; + #endif + return rtn_val; + } else { +diff --git a/src/locking.c b/src/locking.c +index 9f4fe067..bcadc857 100644 +--- a/src/locking.c ++++ b/src/locking.c +@@ -453,6 +453,9 @@ static void _XLockDisplay( + XTHREADS_FILE_LINE_ARGS + ) + { ++#ifdef XTHREADS ++ struct _XErrorThreadInfo *ti; ++#endif + #ifdef XTHREADS_WARN + _XLockDisplayWarn(dpy, file, line); + #else +@@ -460,6 +463,15 @@ static void _XLockDisplay( + #endif + if (dpy->lock->locking_level > 0) + _XDisplayLockWait(dpy); ++#ifdef XTHREADS ++ /* ++ * Skip the two function calls below which may generate requests ++ * when LockDisplay is called from within _XError. ++ */ ++ for (ti = dpy->error_threads; ti; ti = ti->next) ++ if (ti->error_thread == xthread_self()) ++ return; ++#endif + _XIDHandler(dpy); + _XSeqSyncFunction(dpy); + } +diff --git a/src/locking.h b/src/locking.h +index 5251a60c..59fc866e 100644 +--- a/src/locking.h ++++ b/src/locking.h +@@ -149,6 +149,18 @@ typedef struct _LockInfoRec { + xmutex_t lock; + } LockInfoRec; + ++/* A list of threads currently invoking error handlers on this display ++ * LockDisplay operates differently for these threads, avoiding ++ * generating any requests or reading any events as that can cause ++ * recursion into the error handling code, which will deadlock the ++ * thread. ++ */ ++struct _XErrorThreadInfo ++{ ++ struct _XErrorThreadInfo *next; ++ xthread_t error_thread; ++}; ++ + /* XOpenDis.c */ + extern int (*_XInitDisplayLock_fn)(Display *dpy); + extern void (*_XFreeDisplayLock_fn)(Display *dpy); +-- +2.43.0 + diff --git a/SOURCES/0001-CVE-2023-43785-out-of-bounds-memory-access-in-_XkbRe.patch b/SOURCES/0001-CVE-2023-43785-out-of-bounds-memory-access-in-_XkbRe.patch new file mode 100644 index 0000000..6427fc2 --- /dev/null +++ b/SOURCES/0001-CVE-2023-43785-out-of-bounds-memory-access-in-_XkbRe.patch @@ -0,0 +1,58 @@ +From 6858d468d9ca55fb4c5fd70b223dbc78a3358a7f Mon Sep 17 00:00:00 2001 +From: Alan Coopersmith +Date: Sun, 17 Sep 2023 14:19:40 -0700 +Subject: [PATCH] CVE-2023-43785: out-of-bounds memory access in + _XkbReadKeySyms() + +Make sure we allocate enough memory in the first place, and +also handle error returns from _XkbReadBufferCopyKeySyms() when +it detects out-of-bounds issues. + +Reported-by: Gregory James DUCK +Signed-off-by: Alan Coopersmith +--- + src/xkb/XKBGetMap.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/src/xkb/XKBGetMap.c b/src/xkb/XKBGetMap.c +index 2891d21e..31199e4a 100644 +--- a/src/xkb/XKBGetMap.c ++++ b/src/xkb/XKBGetMap.c +@@ -182,7 +182,8 @@ _XkbReadKeySyms(XkbReadBufferPtr buf, XkbDescPtr xkb, xkbGetMapReply *rep) + if (offset + newMap->nSyms >= map->size_syms) { + register int sz; + +- sz = map->size_syms + 128; ++ sz = offset + newMap->nSyms; ++ sz = ((sz + (unsigned) 128) / 128) * 128; + _XkbResizeArray(map->syms, map->size_syms, sz, KeySym); + if (map->syms == NULL) { + map->size_syms = 0; +@@ -191,8 +192,9 @@ _XkbReadKeySyms(XkbReadBufferPtr buf, XkbDescPtr xkb, xkbGetMapReply *rep) + map->size_syms = sz; + } + if (newMap->nSyms > 0) { +- _XkbReadBufferCopyKeySyms(buf, (KeySym *) &map->syms[offset], +- newMap->nSyms); ++ if (_XkbReadBufferCopyKeySyms(buf, (KeySym *) &map->syms[offset], ++ newMap->nSyms) == 0) ++ return BadLength; + offset += newMap->nSyms; + } + else { +@@ -222,8 +224,10 @@ _XkbReadKeySyms(XkbReadBufferPtr buf, XkbDescPtr xkb, xkbGetMapReply *rep) + newSyms = XkbResizeKeySyms(xkb, i + rep->firstKeySym, tmp); + if (newSyms == NULL) + return BadAlloc; +- if (newMap->nSyms > 0) +- _XkbReadBufferCopyKeySyms(buf, newSyms, newMap->nSyms); ++ if (newMap->nSyms > 0) { ++ if (_XkbReadBufferCopyKeySyms(buf, newSyms, newMap->nSyms) == 0) ++ return BadLength; ++ } + else + newSyms[0] = NoSymbol; + oldMap->kt_index[0] = newMap->ktIndex[0]; +-- +2.41.0 + diff --git a/SOURCES/0001-CVE-2023-43786-stack-exhaustion-from-infinite-recurs.patch b/SOURCES/0001-CVE-2023-43786-stack-exhaustion-from-infinite-recurs.patch new file mode 100644 index 0000000..8f6a446 --- /dev/null +++ b/SOURCES/0001-CVE-2023-43786-stack-exhaustion-from-infinite-recurs.patch @@ -0,0 +1,37 @@ +From 204c3393c4c90a29ed6bef64e43849536e863a86 Mon Sep 17 00:00:00 2001 +From: Alan Coopersmith +Date: Thu, 7 Sep 2023 15:54:30 -0700 +Subject: [PATCH 1/3] CVE-2023-43786: stack exhaustion from infinite recursion + in PutSubImage() + +When splitting a single line of pixels into chunks to send to the +X server, be sure to take into account the number of bits per pixel, +so we don't just loop forever trying to send more pixels than fit in +the given request size and not breaking them down into a small enough +chunk to fix. + +Fixes: "almost complete rewrite" (Dec. 12, 1987) from X11R2 +Signed-off-by: Alan Coopersmith +--- + src/PutImage.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/PutImage.c b/src/PutImage.c +index 857ee916..a6db7b42 100644 +--- a/src/PutImage.c ++++ b/src/PutImage.c +@@ -914,8 +914,9 @@ PutSubImage ( + req_width, req_height - SubImageHeight, + dest_bits_per_pixel, dest_scanline_pad); + } else { +- int SubImageWidth = (((Available << 3) / dest_scanline_pad) +- * dest_scanline_pad) - left_pad; ++ int SubImageWidth = ((((Available << 3) / dest_scanline_pad) ++ * dest_scanline_pad) - left_pad) ++ / dest_bits_per_pixel; + + PutSubImage(dpy, d, gc, image, req_xoffset, req_yoffset, x, y, + (unsigned int) SubImageWidth, 1, +-- +2.41.0 + diff --git a/SOURCES/0001-CVE-2023-43787-Integer-overflow-in-XCreateImage-lead.patch b/SOURCES/0001-CVE-2023-43787-Integer-overflow-in-XCreateImage-lead.patch new file mode 100644 index 0000000..3468d6e --- /dev/null +++ b/SOURCES/0001-CVE-2023-43787-Integer-overflow-in-XCreateImage-lead.patch @@ -0,0 +1,59 @@ +From 7916869d16bdd115ac5be30a67c3749907aea6a0 Mon Sep 17 00:00:00 2001 +From: Yair Mizrahi +Date: Thu, 7 Sep 2023 16:15:32 -0700 +Subject: [PATCH] CVE-2023-43787: Integer overflow in XCreateImage() leading to + a heap overflow + +When the format is `Pixmap` it calculates the size of the image data as: + ROUNDUP((bits_per_pixel * width), image->bitmap_pad); +There is no validation on the `width` of the image, and so this +calculation exceeds the capacity of a 4-byte integer, causing an overflow. + +Signed-off-by: Alan Coopersmith +--- + src/ImUtil.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/src/ImUtil.c b/src/ImUtil.c +index 36f08a03..fbfad33e 100644 +--- a/src/ImUtil.c ++++ b/src/ImUtil.c +@@ -30,6 +30,7 @@ in this Software without prior written authorization from The Open Group. + #include + #include + #include ++#include + #include "ImUtil.h" + + static int _XDestroyImage(XImage *); +@@ -361,13 +362,22 @@ XImage *XCreateImage ( + /* + * compute per line accelerator. + */ +- { +- if (format == ZPixmap) ++ if (format == ZPixmap) { ++ if ((INT_MAX / bits_per_pixel) < width) { ++ Xfree(image); ++ return NULL; ++ } ++ + min_bytes_per_line = +- ROUNDUP((bits_per_pixel * width), image->bitmap_pad); +- else ++ ROUNDUP((bits_per_pixel * width), image->bitmap_pad); ++ } else { ++ if ((INT_MAX - offset) < width) { ++ Xfree(image); ++ return NULL; ++ } ++ + min_bytes_per_line = +- ROUNDUP((width + offset), image->bitmap_pad); ++ ROUNDUP((width + offset), image->bitmap_pad); + } + if (image_bytes_per_line == 0) { + image->bytes_per_line = min_bytes_per_line; +-- +2.41.0 + diff --git a/SOURCES/0002-XPutImage-clip-images-to-maximum-height-width-allowe.patch b/SOURCES/0002-XPutImage-clip-images-to-maximum-height-width-allowe.patch new file mode 100644 index 0000000..27b5912 --- /dev/null +++ b/SOURCES/0002-XPutImage-clip-images-to-maximum-height-width-allowe.patch @@ -0,0 +1,41 @@ +From 73a37d5f2fcadd6540159b432a70d80f442ddf4a Mon Sep 17 00:00:00 2001 +From: Alan Coopersmith +Date: Thu, 7 Sep 2023 15:55:04 -0700 +Subject: [PATCH 2/3] XPutImage: clip images to maximum height & width allowed + by protocol + +The PutImage request specifies height & width of the image as CARD16 +(unsigned 16-bit integer), same as the maximum dimensions of an X11 +Drawable, which the image is being copied to. + +Signed-off-by: Alan Coopersmith +--- + src/PutImage.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/PutImage.c b/src/PutImage.c +index a6db7b42..ba411e36 100644 +--- a/src/PutImage.c ++++ b/src/PutImage.c +@@ -30,6 +30,7 @@ in this Software without prior written authorization from The Open Group. + #include "Xlibint.h" + #include "Xutil.h" + #include ++#include + #include "Cr.h" + #include "ImUtil.h" + #include "reallocarray.h" +@@ -962,6 +963,10 @@ XPutImage ( + height = image->height - req_yoffset; + if ((width <= 0) || (height <= 0)) + return 0; ++ if (width > USHRT_MAX) ++ width = USHRT_MAX; ++ if (height > USHRT_MAX) ++ height = USHRT_MAX; + + if ((image->bits_per_pixel == 1) || (image->format != ZPixmap)) { + dest_bits_per_pixel = 1; +-- +2.41.0 + diff --git a/SOURCES/0003-XCreatePixmap-trigger-BadValue-error-for-out-of-rang.patch b/SOURCES/0003-XCreatePixmap-trigger-BadValue-error-for-out-of-rang.patch new file mode 100644 index 0000000..0900498 --- /dev/null +++ b/SOURCES/0003-XCreatePixmap-trigger-BadValue-error-for-out-of-rang.patch @@ -0,0 +1,47 @@ +From b4031fc023816aca07fbd592ed97010b9b48784b Mon Sep 17 00:00:00 2001 +From: Alan Coopersmith +Date: Thu, 7 Sep 2023 16:12:27 -0700 +Subject: [PATCH 3/3] XCreatePixmap: trigger BadValue error for out-of-range + dimensions + +The CreatePixmap request specifies height & width of the image as CARD16 +(unsigned 16-bit integer), so if either is larger than that, set it to 0 +so the X server returns a BadValue error as the protocol requires. + +Signed-off-by: Alan Coopersmith +--- + src/CrPixmap.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/CrPixmap.c b/src/CrPixmap.c +index cdf31207..3cb2ca6d 100644 +--- a/src/CrPixmap.c ++++ b/src/CrPixmap.c +@@ -28,6 +28,7 @@ in this Software without prior written authorization from The Open Group. + #include + #endif + #include "Xlibint.h" ++#include + + #ifdef USE_DYNAMIC_XCURSOR + void +@@ -47,6 +48,16 @@ Pixmap XCreatePixmap ( + Pixmap pid; + register xCreatePixmapReq *req; + ++ /* ++ * Force a BadValue X Error if the requested dimensions are larger ++ * than the X11 protocol has room for, since that's how callers expect ++ * to get notified of errors. ++ */ ++ if (width > USHRT_MAX) ++ width = 0; ++ if (height > USHRT_MAX) ++ height = 0; ++ + LockDisplay(dpy); + GetReq(CreatePixmap, req); + req->drawable = d; +-- +2.41.0 + diff --git a/SPECS/libX11.spec b/SPECS/libX11.spec index 5dd0676..fefcf70 100644 --- a/SPECS/libX11.spec +++ b/SPECS/libX11.spec @@ -5,7 +5,7 @@ Summary: Core X11 protocol client library Name: libX11 Version: 1.6.8 -Release: 6%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} +Release: 8%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} License: MIT Group: System Environment/Libraries URL: http://www.x.org @@ -28,6 +28,20 @@ Patch6: CVE-2021-31535.patch # CVE-2023-3138 Patch7: 0001-InitExt.c-Add-bounds-checks-for-extension-request-ev.patch +# CVE-2023-43785 +Patch8: 0001-CVE-2023-43785-out-of-bounds-memory-access-in-_XkbRe.patch + +# CVE-2023-43786 +Patch9: 0001-CVE-2023-43786-stack-exhaustion-from-infinite-recurs.patch +Patch10: 0002-XPutImage-clip-images-to-maximum-height-width-allowe.patch +Patch11: 0003-XCreatePixmap-trigger-BadValue-error-for-out-of-rang.patch + +# CVE-2023-43787 +Patch12: 0001-CVE-2023-43787-Integer-overflow-in-XCreateImage-lead.patch + +# RHEL-23452 +Patch13: 0001-Avoid-recursing-through-_XError-due-to-sequence-adju.patch + BuildRequires: xorg-x11-util-macros >= 1.11 BuildRequires: pkgconfig(xproto) >= 7.0.15 BuildRequires: xorg-x11-xtrans-devel >= 1.0.3-4 @@ -73,6 +87,12 @@ libX11/libxcb interoperability library %patch5 -p1 -b .fix-an-integer-overflow-in-init_om %patch6 -p1 -b .cve-2021-31535 %patch7 -p1 -b .cve-2023-3138 +%patch8 -p1 -b .cve-2023-43785 +%patch9 -p1 -b .cve-2023-43786 +%patch10 -p1 -b .xputimage-clip-images-to-maximum-height-width-allowe +%patch11 -p1 -b .xcreatepixmap-trigger-badvalue-error-for-out-of-rang +%patch12 -p1 -b .cve-2023-43787 +%patch13 -p1 -b .rhel-23452 %build autoreconf -v --install --force @@ -137,6 +157,16 @@ make %{?_smp_mflags} check %{_mandir}/man5/*.5* %changelog +* Tue Jan 30 2024 Olivier Fourdan - 1.6.8-8 +- Backport fix for Xlib lockups due to recursive XError (RHEL-23452) + +* Wed Oct 11 2023 José Expósito - 1.6.8-7 +- Fix CVE-2023-43785: out-of-bounds memory access in _XkbReadKeySyms() +- Fix CVE-2023-43786: stack exhaustion from infinite recursion in + PutSubImage() +- Fix CVE-2023-43787: integer overflow in XCreateImage() leading to + a heap overflow + * Wed Jul 05 2023 Olivier Fourdan - 1.6.8-6 - CVE fix for: CVE-2023-3138 Resolve: rhbz#2213762