Backport fix for Xlib lockups due to recursive XError
Resolves: https://issues.redhat.com/browse/RHEL-23452
This commit is contained in:
		
							parent
							
								
									78f64db9c8
								
							
						
					
					
						commit
						39ea10b841
					
				
							
								
								
									
										166
									
								
								0001-Avoid-recursing-through-_XError-due-to-sequence-adju.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								0001-Avoid-recursing-through-_XError-due-to-sequence-adju.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | ||||
| From 8c92ef59890c6d6e2be456658d3b9c145eda8629 Mon Sep 17 00:00:00 2001 | ||||
| From: Keith Packard <keithp@keithp.com> | ||||
| 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 <digetx@gmail.com> | ||||
| Signed-off-by: Keith Packard <keithp@keithp.com> | ||||
| Tested-by: Dmitry Osipenko <digetx@gmail.com> | ||||
| Reviewed-by: Dmitry Osipenko <digetx@gmail.com> | ||||
| (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 | ||||
| 
 | ||||
| @ -5,7 +5,7 @@ | ||||
| Summary: Core X11 protocol client library | ||||
| Name: libX11 | ||||
| Version: 1.6.8 | ||||
| Release: 7%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} | ||||
| Release: 8%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} | ||||
| License: MIT | ||||
| Group: System Environment/Libraries | ||||
| URL: http://www.x.org | ||||
| @ -39,6 +39,9 @@ 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 | ||||
| @ -89,6 +92,7 @@ libX11/libxcb interoperability library | ||||
| %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 | ||||
| @ -153,6 +157,9 @@ make %{?_smp_mflags} check | ||||
| %{_mandir}/man5/*.5* | ||||
| 
 | ||||
| %changelog | ||||
| * Tue Jan 30 2024 Olivier Fourdan <ofourdan@redhat.com> - 1.6.8-8 | ||||
| - Backport fix for Xlib lockups due to recursive XError (RHEL-23452) | ||||
| 
 | ||||
| * Wed Oct 11 2023 José Expósito <jexposit@redhat.com> - 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 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user