From af3896eb0da1b8d34443310d498ebd21eaa5a6ce Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Wed, 24 Jun 2026 16:40:20 -0400 Subject: [PATCH] import Oracle_OSS freerdp-2.11.7-7.el9_8.3 --- ...nt-x11-fix-deadlock-on-output-expose.patch | 170 ++++++++ ...ent-x11-improve-rails-window-locking.patch | 331 ++++++++++++++ SOURCES/client-x11-lock-appwindow.patch | 404 ++++++++++++++++++ SOURCES/client-x11-refactor-locking.patch | 360 ++++++++++++++++ ...core-tcp-Don-t-ignore-connect-errors.patch | 55 +++ ...ferIPv6OverIPv4-fallback-to-IPv4-add.patch | 102 +++++ ...ry-next-DNS-entry-on-connect-failure.patch | 76 ++++ ...fix-double-free-in-get_next_addrinfo.patch | 39 ++ ...-retry-all-DNS-entries-until-success.patch | 100 +++++ SPECS/freerdp.spec | 63 ++- 10 files changed, 1681 insertions(+), 19 deletions(-) create mode 100644 SOURCES/client-x11-fix-deadlock-on-output-expose.patch create mode 100644 SOURCES/client-x11-improve-rails-window-locking.patch create mode 100644 SOURCES/client-x11-lock-appwindow.patch create mode 100644 SOURCES/client-x11-refactor-locking.patch create mode 100644 SOURCES/core-tcp-Don-t-ignore-connect-errors.patch create mode 100644 SOURCES/core-tcp-Fix-PreferIPv6OverIPv4-fallback-to-IPv4-add.patch create mode 100644 SOURCES/core-tcp-Try-next-DNS-entry-on-connect-failure.patch create mode 100644 SOURCES/core-tcp-fix-double-free-in-get_next_addrinfo.patch create mode 100644 SOURCES/core-tcp-retry-all-DNS-entries-until-success.patch diff --git a/SOURCES/client-x11-fix-deadlock-on-output-expose.patch b/SOURCES/client-x11-fix-deadlock-on-output-expose.patch new file mode 100644 index 0000000..6157356 --- /dev/null +++ b/SOURCES/client-x11-fix-deadlock-on-output-expose.patch @@ -0,0 +1,170 @@ +From a25a6b8c53602d2023dd0ad685000dc006179e94 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 27 Apr 2026 20:12:42 +0000 +Subject: [PATCH] [client,x11] fix deadlock on output expose + +Defer screen update from xf_event_Expose to after X11 lock is released, +preventing a deadlock between X11 lock and railWindows lock. + +Backport of commit a278ff74117444c635c50ffa5084ecf517171f5a. + +Adjusted hunk offsets for 2.11.7. + +Made-with: Cursor +--- + client/X11/xf_client.c | 3 ++ + client/X11/xf_event.c | 77 ++++++++++++++++++++++++++++-------------- + client/X11/xf_event.h | 2 ++ + client/X11/xfreerdp.h | 4 +++ + 4 files changed, 60 insertions(+), 26 deletions(-) + +diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c +index bd3eb0d..f14cb55 100644 +--- a/client/X11/xf_client.c ++++ b/client/X11/xf_client.c +@@ -516,6 +516,9 @@ static BOOL xf_process_x_events(freerdp* instance) + xf_unlock_x11(xfc); + if (!status) + break; ++ status = xf_event_update_screen(instance); ++ if (!status) ++ break; + } + + return status; +diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c +index e1421ad..524e5e3 100644 +--- a/client/X11/xf_event.c ++++ b/client/X11/xf_event.c +@@ -324,45 +324,34 @@ void xf_event_adjust_coordinates(xfContext* xfc, int* x, int* y) + } + static BOOL xf_event_Expose(xfContext* xfc, const XExposeEvent* event, BOOL app) + { +- int x, y; +- int w, h; ++ WINPR_ASSERT(xfc); ++ WINPR_ASSERT(event); ++ + rdpSettings* settings = xfc->context.settings; ++ WINPR_ASSERT(settings); + + if (!app && (settings->SmartSizing || settings->MultiTouchGestures)) + { +- x = 0; +- y = 0; +- w = settings->DesktopWidth; +- h = settings->DesktopHeight; ++ xfc->exposedArea.x = 0; ++ xfc->exposedArea.y = 0; ++ xfc->exposedArea.w = settings->DesktopWidth; ++ xfc->exposedArea.h = settings->DesktopHeight; + } + else + { +- x = event->x; +- y = event->y; +- w = event->width; +- h = event->height; ++ xfc->exposedArea.x = event->x; ++ xfc->exposedArea.y = event->y; ++ xfc->exposedArea.w = event->width; ++ xfc->exposedArea.h = event->height; + } + +- if (!app) +- { +- if (xfc->context.gdi->gfx) +- { +- xf_OutputExpose(xfc, x, y, w, h); +- return TRUE; +- } +- xf_draw_screen(xfc, x, y, w, h); +- } +- else +- { +- xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, event->window); +- if (appWindow) +- xf_UpdateWindowArea(xfc, appWindow, x, y, w, h); +- xf_rail_return_window(appWindow, FALSE); +- } ++ xfc->exposedWindow = event->window; ++ xfc->exposeRequested = TRUE; + + return TRUE; + } + ++ + static BOOL xf_event_VisibilityNotify(xfContext* xfc, const XVisibilityEvent* event, BOOL app) + { + WINPR_UNUSED(app); +@@ -1180,3 +1169,39 @@ BOOL xf_event_process(freerdp* instance, const XEvent* event) + XSync(xfc->display, FALSE); + return status; + } ++ ++BOOL xf_event_update_screen(freerdp* instance) ++{ ++ WINPR_ASSERT(instance); ++ ++ xfContext* xfc = (xfContext*)instance->context; ++ WINPR_ASSERT(xfc); ++ ++ rdpSettings* settings = xfc->context.settings; ++ WINPR_ASSERT(settings); ++ ++ if (!xfc->exposeRequested) ++ return TRUE; ++ xfc->exposeRequested = FALSE; ++ ++ if (!xfc->remote_app) ++ { ++ if (xfc->context.gdi->gfx) ++ { ++ xf_OutputExpose(xfc, xfc->exposedArea.x, xfc->exposedArea.y, ++ xfc->exposedArea.w, xfc->exposedArea.h); ++ return TRUE; ++ } ++ xf_draw_screen(xfc, xfc->exposedArea.x, xfc->exposedArea.y, xfc->exposedArea.w, ++ xfc->exposedArea.h); ++ } ++ else ++ { ++ xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, xfc->exposedWindow); ++ if (appWindow) ++ xf_UpdateWindowArea(xfc, appWindow, xfc->exposedArea.x, xfc->exposedArea.y, ++ xfc->exposedArea.w, xfc->exposedArea.h); ++ xf_rail_return_window(appWindow, FALSE); ++ } ++ return TRUE; ++} +diff --git a/client/X11/xf_event.h b/client/X11/xf_event.h +index 2269d3e..e025d19 100644 +--- a/client/X11/xf_event.h ++++ b/client/X11/xf_event.h +@@ -29,6 +29,8 @@ BOOL xf_event_action_script_init(xfContext* xfc); + void xf_event_action_script_free(xfContext* xfc); + + BOOL xf_event_process(freerdp* instance, const XEvent* event); ++ ++BOOL xf_event_update_screen(freerdp* instance); + void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, + ...); + +diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h +index 636e60a..a1a33b2 100644 +--- a/client/X11/xfreerdp.h ++++ b/client/X11/xfreerdp.h +@@ -261,6 +261,10 @@ struct xf_context + wHashTable* railWindows; + xfRailIconCache* railIconCache; + ++ BOOL exposeRequested; ++ GDI_RGN exposedArea; ++ Window exposedWindow; ++ + BOOL xkbAvailable; + BOOL xrenderAvailable; + +-- +2.53.0 + diff --git a/SOURCES/client-x11-improve-rails-window-locking.patch b/SOURCES/client-x11-improve-rails-window-locking.patch new file mode 100644 index 0000000..22dc762 --- /dev/null +++ b/SOURCES/client-x11-improve-rails-window-locking.patch @@ -0,0 +1,331 @@ +From e6edabe690ad8de63af327403e8371b6ef1319e2 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 27 Apr 2026 19:38:47 +0000 +Subject: [PATCH] [client,x11] improve rails window locking + +Backport of commit 78fd7f580d5f9e6d9d582d82e5ea96003844fbdf. + +Adapted for 2.11.7: C89 declaration style, simplified +`xfAppWindowsLockFrom`/`UnlockFrom` signatures (no +`WINPR_ATTR_UNUSED`), `XSetTransientForHint` inline error handling. + +Made-with: Cursor +--- + client/X11/xf_event.c | 7 ++---- + client/X11/xf_graphics.c | 4 +-- + client/X11/xf_rail.c | 53 +++++++++++++++++++-------------------- + client/X11/xf_rail.h | 10 ++++++-- + client/X11/xf_window.c | 54 ++++++++++++++++++++++++++++++++-------- + client/X11/xf_window.h | 11 ++++++-- + 6 files changed, 89 insertions(+), 50 deletions(-) + +diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c +index 8bebcd4..8801fbd 100644 +--- a/client/X11/xf_event.c ++++ b/client/X11/xf_event.c +@@ -354,13 +354,10 @@ static BOOL xf_event_Expose(xfContext* xfc, const XExposeEvent* event, BOOL app) + } + else + { +- xfAppWindow* appWindow; +- appWindow = xf_AppWindowFromX11Window(xfc, event->window); +- ++ xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, event->window); + if (appWindow) +- { + xf_UpdateWindowArea(xfc, appWindow, x, y, w, h); +- } ++ xf_rail_return_window(appWindow); + } + + return TRUE; +diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c +index 70979bd..f5b4f3d 100644 +--- a/client/X11/xf_graphics.c ++++ b/client/X11/xf_graphics.c +@@ -372,12 +372,12 @@ static Window xf_Pointer_get_window(xfContext* xfc) + if (xfc->remote_app) + { + Window w = 0; +- EnterCriticalSection(&xfc->railWindows->lock); ++ xf_AppWindowsLock(xfc); + if (!xfc->appWindow) + WLog_WARN(TAG, "xf_Pointer: Invalid appWindow"); + else + w = xfc->appWindow->handle; +- LeaveCriticalSection(&xfc->railWindows->lock); ++ xf_AppWindowsUnlock(xfc); + return w; + } + else +diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c +index 1938bdd..1e57046 100644 +--- a/client/X11/xf_rail.c ++++ b/client/X11/xf_rail.c +@@ -101,9 +101,10 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled) + xf_SetWindowStyle(xfc, appWindow, 0, 0); + + activate.windowId = appWindow->windowId; ++ xf_rail_return_window(appWindow); ++ + activate.enabled = enabled; + xfc->rail->ClientActivate(xfc->rail, &activate); +- xf_rail_return_window(appWindow); + } + + void xf_rail_send_client_system_command(xfContext* xfc, UINT32 windowId, UINT16 command) +@@ -260,6 +261,7 @@ void xf_rail_paint(xfContext* xfc, INT32 uleft, INT32 utop, UINT32 uright, UINT3 + static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_STATE_ORDER* windowState) + { ++ BOOL rc = FALSE; + xfContext* xfc = (xfContext*)context; + UINT32 fieldFlags = orderInfo->fieldFlags; + BOOL position_or_size_updated = FALSE; +@@ -379,14 +381,14 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* + if (!(title = _strdup(""))) + { + WLog_ERR(TAG, "failed to duplicate empty window title string"); +- return FALSE; ++ goto fail; + } + } + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)windowState->titleInfo.string, + windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert window title"); +- return FALSE; ++ goto fail; + } + + free(appWindow->title); +@@ -427,7 +429,7 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* + (RECTANGLE_16*)calloc(appWindow->numWindowRects, sizeof(RECTANGLE_16)); + + if (!appWindow->windowRects) +- return FALSE; ++ goto fail; + + CopyMemory(appWindow->windowRects, windowState->windowRects, + appWindow->numWindowRects * sizeof(RECTANGLE_16)); +@@ -456,7 +458,7 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* + (RECTANGLE_16*)calloc(appWindow->numVisibilityRects, sizeof(RECTANGLE_16)); + + if (!appWindow->visibilityRects) +- return FALSE; ++ goto fail; + + CopyMemory(appWindow->visibilityRects, windowState->visibilityRects, + appWindow->numVisibilityRects * sizeof(RECTANGLE_16)); +@@ -522,7 +524,10 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* + { + xf_SetWindowRects(xfc, appWindow, appWindow->windowRects, appWindow->numWindowRects); + }*/ +- return TRUE; ++ rc = TRUE; ++fail: ++ xf_rail_return_window(appWindow); ++ return rc; + } + + static BOOL xf_rail_window_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo) +@@ -1000,14 +1005,14 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context, + x = localMoveSize->posX; + y = localMoveSize->posY; + /* FIXME: local keyboard moves not working */ +- return CHANNEL_RC_OK; ++ break; + + case RAIL_WMSZ_KEYSIZE: + direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD; + x = localMoveSize->posX; + y = localMoveSize->posY; + /* FIXME: local keyboard moves not working */ +- return CHANNEL_RC_OK; ++ break; + } + + if (localMoveSize->isMoveSizeStart) +@@ -1173,9 +1178,17 @@ xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, UINT32 x, UINT32 y, U + appWindow->y = y; + appWindow->width = width; + appWindow->height = height; +- xf_AppWindowCreate(xfc, appWindow); +- HashTable_Add(xfc->railWindows, &appWindow->windowId, (void*)appWindow); ++ xf_AppWindowsLock(xfc); ++ if (xf_AppWindowCreate(xfc, appWindow) < 0) ++ goto fail; ++ ++ if (HashTable_Add(xfc->railWindows, &appWindow->windowId, (void*)appWindow) < 0) ++ goto fail; + return appWindow; ++fail: ++ free(appWindow); ++ xf_AppWindowsUnlock(xfc); ++ return NULL; + } + + BOOL xf_rail_del_window(xfContext* xfc, UINT64 id) +@@ -1189,26 +1202,10 @@ BOOL xf_rail_del_window(xfContext* xfc, UINT64 id) + return HashTable_Remove(xfc->railWindows, &id); + } + +-xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64 id) +-{ +- if (!xfc) +- return NULL; +- +- if (!xfc->railWindows) +- return NULL; +- +- EnterCriticalSection(&xfc->railWindows->lock); +- xfAppWindow* window = HashTable_GetItemValue(xfc->railWindows, &id); +- if (!window) +- LeaveCriticalSection(&xfc->railWindows->lock); +- +- return window; +-} +- +-void xf_rail_return_window(xfAppWindow* window) ++void xf_rail_return_windowFrom(xfAppWindow* window, const char* file, const char* fkt, size_t line) + { + if (!window) + return; + +- LeaveCriticalSection(&window->xfc->railWindows->lock); ++ xfAppWindowsUnlockFrom(window->xfc, file, fkt, line); + } +diff --git a/client/X11/xf_rail.h b/client/X11/xf_rail.h +index 5fbc316..83d5fff 100644 +--- a/client/X11/xf_rail.h ++++ b/client/X11/xf_rail.h +@@ -36,9 +36,15 @@ void xf_rail_disable_remoteapp_mode(xfContext* xfc); + xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, UINT32 x, UINT32 y, UINT32 width, + UINT32 height, UINT32 surfaceId); + +-void xf_rail_return_window(xfAppWindow* window); ++#define xf_rail_return_window(window) \ ++ xf_rail_return_windowFrom((window), __FILE__, __func__, __LINE__) ++void xf_rail_return_windowFrom(xfAppWindow* window, const char* file, const char* fkt, size_t line); + +-xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64 id); ++#define xf_rail_get_window(xfc, id) \ ++ xf_rail_get_windowFrom((xfc), (id), __FILE__, __func__, __LINE__) ++ ++xfAppWindow* xf_rail_get_windowFrom(xfContext* xfc, UINT64 id, const char* file, const char* fkt, ++ size_t line); + + BOOL xf_rail_del_window(xfContext* xfc, UINT64 id); + +diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c +index 7e936fe..09b4a81 100644 +--- a/client/X11/xf_window.c ++++ b/client/X11/xf_window.c +@@ -1116,39 +1116,71 @@ void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow) + free(appWindow); + } + +-xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd) ++static xfAppWindow* get_windowUnlocked(xfContext* xfc, UINT64 id) ++{ ++ WINPR_ASSERT(xfc); ++ return HashTable_GetItemValue(xfc->railWindows, &id); ++} ++ ++xfAppWindow* xf_rail_get_windowFrom(xfContext* xfc, UINT64 id, const char* file, const char* fkt, ++ size_t line) ++{ ++ if (!xfc) ++ return NULL; ++ ++ if (!xfc->railWindows) ++ return NULL; ++ ++ xfAppWindowsLockFrom(xfc, file, fkt, line); ++ xfAppWindow* window = get_windowUnlocked(xfc, id); ++ if (!window) ++ xfAppWindowsUnlockFrom(xfc, file, fkt, line); ++ ++ return window; ++} ++ ++xfAppWindow* xf_AppWindowFromX11WindowFrom(xfContext* xfc, Window wnd, const char* file, ++ const char* fkt, size_t line) + { +- int index; +- int count; + ULONG_PTR* pKeys = NULL; +- xfAppWindow* appWindow; + + if (!xfc->railWindows) + return NULL; + +- EnterCriticalSection(&xfc->railWindows->lock); +- count = HashTable_GetKeys(xfc->railWindows, &pKeys); ++ xfAppWindowsLockFrom(xfc, file, fkt, line); ++ size_t count = HashTable_GetKeys(xfc->railWindows, &pKeys); + +- for (index = 0; index < count; index++) ++ for (size_t index = 0; index < count; index++) + { +- appWindow = HashTable_GetItemValue(xfc->railWindows, (void*)pKeys[index]); ++ xfAppWindow* appWindow = get_windowUnlocked(xfc, *(UINT64*)pKeys[index]); + + if (!appWindow) + { +- LeaveCriticalSection(&xfc->railWindows->lock); ++ xfAppWindowsUnlockFrom(xfc, file, fkt, line); + free(pKeys); + return NULL; + } + + if (appWindow->handle == wnd) + { +- LeaveCriticalSection(&xfc->railWindows->lock); + free(pKeys); + return appWindow; + } + } + +- LeaveCriticalSection(&xfc->railWindows->lock); ++ xfAppWindowsUnlockFrom(xfc, file, fkt, line); + free(pKeys); + return NULL; + } ++ ++void xfAppWindowsLockFrom(xfContext* xfc, const char* file, const char* fkt, size_t line) ++{ ++ WINPR_ASSERT(xfc); ++ EnterCriticalSection(&xfc->railWindows->lock); ++} ++ ++void xfAppWindowsUnlockFrom(xfContext* xfc, const char* file, const char* fkt, size_t line) ++{ ++ WINPR_ASSERT(xfc); ++ LeaveCriticalSection(&xfc->railWindows->lock); ++} +diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h +index c7702ed..45d40bb 100644 +--- a/client/X11/xf_window.h ++++ b/client/X11/xf_window.h +@@ -187,8 +187,15 @@ void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, int maxWidth + int maxTrackWidth, int maxTrackHeight); + void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, int direction, int x, int y); + void xf_EndLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow); +-void xf_rail_return_window(xfAppWindow* window); ++#define xf_AppWindowFromX11Window(xfc, wnd) \ ++ xf_AppWindowFromX11WindowFrom((xfc), (wnd), __FILE__, __func__, __LINE__) ++xfAppWindow* xf_AppWindowFromX11WindowFrom(xfContext* xfc, Window wnd, const char* file, ++ const char* fkt, size_t line); + +-xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd); ++#define xf_AppWindowsLock(xfc) xfAppWindowsLockFrom((xfc), __FILE__, __func__, __LINE__) ++void xfAppWindowsLockFrom(xfContext* xfc, const char* file, const char* fkt, size_t line); ++ ++#define xf_AppWindowsUnlock(xfc) xfAppWindowsUnlockFrom((xfc), __FILE__, __func__, __LINE__) ++void xfAppWindowsUnlockFrom(xfContext* xfc, const char* file, const char* fkt, size_t line); + + #endif /* FREERDP_CLIENT_X11_WINDOW_H */ +-- +2.53.0 + diff --git a/SOURCES/client-x11-lock-appwindow.patch b/SOURCES/client-x11-lock-appwindow.patch new file mode 100644 index 0000000..50988a3 --- /dev/null +++ b/SOURCES/client-x11-lock-appwindow.patch @@ -0,0 +1,404 @@ +From 8152c347e96c1e3af15cb2551d4efb6740fe9f87 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 27 Apr 2026 19:37:40 +0000 +Subject: [PATCH] [client,x11] lock appWindow + +Backport of commit 1994e9844212a6dfe0ff12309fef520e888986b5. + +Adapted for 2.11.7: C89 declaration style, `(Atom)` cast for +`xfc->_NET_WM_STATE` comparison, `xf_rail_send_client_system_command` +return value handling adapted (no direct return), `HashTable_GetKeys` +variable pre-declared, `xf_AppWindowFromX11Window` loop adapted. + +Made-with: Cursor +--- + client/X11/xf_event.c | 46 ++++++++++++++++----------- + client/X11/xf_graphics.c | 10 +++--- + client/X11/xf_rail.c | 68 +++++++++++++++++++++++++--------------- + client/X11/xf_rail.h | 3 ++ + client/X11/xf_window.c | 13 +++++++- + client/X11/xf_window.h | 2 ++ + 6 files changed, 94 insertions(+), 48 deletions(-) + +diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c +index eb50ef1..8bebcd4 100644 +--- a/client/X11/xf_event.c ++++ b/client/X11/xf_event.c +@@ -388,7 +388,9 @@ BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window win + if (app) + { + /* make sure window exists */ +- if (!xf_AppWindowFromX11Window(xfc, window)) ++ xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, window); ++ xf_rail_return_window(appWindow); ++ if (!appWindow) + return TRUE; + + /* Translate to desktop coordinates */ +@@ -465,7 +467,9 @@ BOOL xf_generic_ButtonEvent(xfContext* xfc, int x, int y, int button, Window win + if (app) + { + /* make sure window exists */ +- if (!xf_AppWindowFromX11Window(xfc, window)) ++ xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, window); ++ xf_rail_return_window(appWindow); ++ if (!appWindow) + return TRUE; + + /* Translate to desktop coordinates */ +@@ -574,9 +578,8 @@ static BOOL xf_event_FocusIn(xfContext* xfc, const XFocusInEvent* event, BOOL ap + /* Update the server with any window changes that occurred while the window was not focused. + */ + if (appWindow) +- { + xf_rail_adjust_position(xfc, appWindow); +- } ++ xf_rail_return_window(appWindow); + } + + xf_keyboard_focus_in(xfc); +@@ -623,15 +626,13 @@ static BOOL xf_event_ClientMessage(xfContext* xfc, const XClientMessageEvent* ev + { + if (app) + { +- xfAppWindow* appWindow; +- appWindow = xf_AppWindowFromX11Window(xfc, event->window); ++ BOOL rc = TRUE; ++ xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, event->window); + + if (appWindow) +- { + xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_CLOSE); +- } +- +- return TRUE; ++ xf_rail_return_window(appWindow); ++ return rc; + } + else + { +@@ -665,6 +666,7 @@ static BOOL xf_event_EnterNotify(xfContext* xfc, const XEnterWindowEvent* event, + + /* keep track of which window has focus so that we can apply pointer updates */ + xfc->appWindow = appWindow; ++ xf_rail_return_window(appWindow); + } + + return TRUE; +@@ -684,6 +686,7 @@ static BOOL xf_event_LeaveNotify(xfContext* xfc, const XLeaveWindowEvent* event, + /* keep track of which window has focus so that we can apply pointer updates */ + if (xfc->appWindow == appWindow) + xfc->appWindow = NULL; ++ xf_rail_return_window(appWindow); + } + return TRUE; + } +@@ -774,6 +777,7 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, const XConfigureEvent* even + xf_rail_adjust_position(xfc, appWindow); + } + } ++ xf_rail_return_window(appWindow); + } + return xf_pointer_update_scale(xfc); + } +@@ -798,6 +802,7 @@ static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app) + // xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); + appWindow->is_mapped = TRUE; + } ++ xf_rail_return_window(appWindow); + } + + return TRUE; +@@ -813,15 +818,14 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, const XUnmapEvent* event, BOOL + xf_keyboard_release_all_keypress(xfc); + + if (!app) +- gdi_send_suppress_output(xfc->context.gdi, TRUE); +- else ++ return gdi_send_suppress_output(xfc->context.gdi, TRUE); ++ + { + appWindow = xf_AppWindowFromX11Window(xfc, event->window); + + if (appWindow) +- { + appWindow->is_mapped = FALSE; +- } ++ xf_rail_return_window(appWindow); + } + + return TRUE; +@@ -829,6 +833,7 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, const XUnmapEvent* event, BOOL + + static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, BOOL app) + { ++ BOOL rc = TRUE; + WINPR_ASSERT(xfc); + WINPR_ASSERT(event); + +@@ -856,7 +861,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, + appWindow = xf_AppWindowFromX11Window(xfc, event->window); + + if (!appWindow) +- return TRUE; ++ goto fail; + } + + if ((Atom)event->atom == xfc->_NET_WM_STATE) +@@ -949,10 +954,13 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, + } + } + else if (minimizedChanged) +- gdi_send_suppress_output(xfc->context.gdi, minimized); ++ rc = gdi_send_suppress_output(xfc->context.gdi, minimized); ++ ++ fail: ++ xf_rail_return_window(appWindow); + } + +- return TRUE; ++ return rc; + } + + static BOOL xf_event_suppress_events(xfContext* xfc, xfAppWindow* appWindow, const XEvent* event) +@@ -1060,7 +1068,9 @@ BOOL xf_event_process(freerdp* instance, const XEvent* event) + /* Update "current" window for cursor change orders */ + xfc->appWindow = appWindow; + +- if (xf_event_suppress_events(xfc, appWindow, event)) ++ BOOL suppress = xf_event_suppress_events(xfc, appWindow, event); ++ xf_rail_return_window(appWindow); ++ if (suppress) + return TRUE; + } + } +diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c +index d596b23..70979bd 100644 +--- a/client/X11/xf_graphics.c ++++ b/client/X11/xf_graphics.c +@@ -371,12 +371,14 @@ static Window xf_Pointer_get_window(xfContext* xfc) + } + if (xfc->remote_app) + { ++ Window w = 0; ++ EnterCriticalSection(&xfc->railWindows->lock); + if (!xfc->appWindow) +- { + WLog_WARN(TAG, "xf_Pointer: Invalid appWindow"); +- return 0; +- } +- return xfc->appWindow->handle; ++ else ++ w = xfc->appWindow->handle; ++ LeaveCriticalSection(&xfc->railWindows->lock); ++ return w; + } + else + { +diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c +index fdc2244..1938bdd 100644 +--- a/client/X11/xf_rail.c ++++ b/client/X11/xf_rail.c +@@ -103,6 +103,7 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled) + activate.windowId = appWindow->windowId; + activate.enabled = enabled; + xfc->rail->ClientActivate(xfc->rail, &activate); ++ xf_rail_return_window(appWindow); + } + + void xf_rail_send_client_system_command(xfContext* xfc, UINT32 windowId, UINT16 command) +@@ -658,61 +659,63 @@ static void xf_rail_set_window_icon(xfContext* xfc, xfAppWindow* railWindow, xfR + static BOOL xf_rail_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_ICON_ORDER* windowIcon) + { ++ BOOL rc = FALSE; + xfContext* xfc = (xfContext*)context; +- xfAppWindow* railWindow; +- xfRailIcon* icon; +- BOOL replaceIcon; +- railWindow = xf_rail_get_window(xfc, orderInfo->windowId); ++ BOOL replaceIcon = 0; ++ xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId); + + if (!railWindow) + return TRUE; + +- icon = RailIconCache_Lookup(xfc->railIconCache, windowIcon->iconInfo->cacheId, ++ xfRailIcon* icon = RailIconCache_Lookup(xfc->railIconCache, windowIcon->iconInfo->cacheId, + windowIcon->iconInfo->cacheEntry); + + if (!icon) + { + WLog_WARN(TAG, "failed to get icon from cache %02X:%04X", windowIcon->iconInfo->cacheId, + windowIcon->iconInfo->cacheEntry); +- return FALSE; + } +- +- if (!convert_rail_icon(windowIcon->iconInfo, icon)) ++ else if (!convert_rail_icon(windowIcon->iconInfo, icon)) + { + WLog_WARN(TAG, "failed to convert icon for window %08X", orderInfo->windowId); +- return FALSE; + } +- +- replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW); +- xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); +- return TRUE; ++ else ++ { ++ replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW); ++ xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); ++ rc = TRUE; ++ } ++ xf_rail_return_window(railWindow); ++ return rc; + } + + static BOOL xf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_CACHED_ICON_ORDER* windowCachedIcon) + { ++ BOOL rc = FALSE; + xfContext* xfc = (xfContext*)context; +- xfAppWindow* railWindow; +- xfRailIcon* icon; +- BOOL replaceIcon; +- railWindow = xf_rail_get_window(xfc, orderInfo->windowId); ++ BOOL replaceIcon = 0; ++ xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId); + + if (!railWindow) + return TRUE; + +- icon = RailIconCache_Lookup(xfc->railIconCache, windowCachedIcon->cachedIcon.cacheId, ++ xfRailIcon* icon = RailIconCache_Lookup(xfc->railIconCache, windowCachedIcon->cachedIcon.cacheId, + windowCachedIcon->cachedIcon.cacheEntry); + + if (!icon) + { + WLog_WARN(TAG, "failed to get icon from cache %02X:%04X", + windowCachedIcon->cachedIcon.cacheId, windowCachedIcon->cachedIcon.cacheEntry); +- return FALSE; + } +- +- replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW); +- xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); +- return TRUE; ++ else ++ { ++ replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW); ++ xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); ++ rc = TRUE; ++ } ++ xf_rail_return_window(railWindow); ++ return rc; + } + + static BOOL xf_rail_notify_icon_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, +@@ -1012,6 +1015,7 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context, + else + xf_EndLocalMoveSize(xfc, appWindow); + ++ xf_rail_return_window(appWindow); + return CHANNEL_RC_OK; + } + +@@ -1033,6 +1037,7 @@ static UINT xf_rail_server_min_max_info(RailClientContext* context, + minMaxInfo->minTrackHeight, minMaxInfo->maxTrackWidth, + minMaxInfo->maxTrackHeight); + } ++ xf_rail_return_window(appWindow); + + return CHANNEL_RC_OK; + } +@@ -1190,7 +1195,20 @@ xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64 id) + return NULL; + + if (!xfc->railWindows) +- return FALSE; ++ return NULL; ++ ++ EnterCriticalSection(&xfc->railWindows->lock); ++ xfAppWindow* window = HashTable_GetItemValue(xfc->railWindows, &id); ++ if (!window) ++ LeaveCriticalSection(&xfc->railWindows->lock); ++ ++ return window; ++} ++ ++void xf_rail_return_window(xfAppWindow* window) ++{ ++ if (!window) ++ return; + +- return HashTable_GetItemValue(xfc->railWindows, &id); ++ LeaveCriticalSection(&window->xfc->railWindows->lock); + } +diff --git a/client/X11/xf_rail.h b/client/X11/xf_rail.h +index c99ed70..5fbc316 100644 +--- a/client/X11/xf_rail.h ++++ b/client/X11/xf_rail.h +@@ -35,6 +35,9 @@ void xf_rail_disable_remoteapp_mode(xfContext* xfc); + + xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, UINT32 x, UINT32 y, UINT32 width, + UINT32 height, UINT32 surfaceId); ++ ++void xf_rail_return_window(xfAppWindow* window); ++ + xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64 id); + + BOOL xf_rail_del_window(xfContext* xfc, UINT64 id); +diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c +index 9b5b1c4..7e936fe 100644 +--- a/client/X11/xf_window.c ++++ b/client/X11/xf_window.c +@@ -1122,22 +1122,33 @@ xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd) + int count; + ULONG_PTR* pKeys = NULL; + xfAppWindow* appWindow; ++ ++ if (!xfc->railWindows) ++ return NULL; ++ ++ EnterCriticalSection(&xfc->railWindows->lock); + count = HashTable_GetKeys(xfc->railWindows, &pKeys); + + for (index = 0; index < count; index++) + { +- appWindow = xf_rail_get_window(xfc, *(UINT64*)pKeys[index]); ++ appWindow = HashTable_GetItemValue(xfc->railWindows, (void*)pKeys[index]); + + if (!appWindow) ++ { ++ LeaveCriticalSection(&xfc->railWindows->lock); ++ free(pKeys); + return NULL; ++ } + + if (appWindow->handle == wnd) + { ++ LeaveCriticalSection(&xfc->railWindows->lock); + free(pKeys); + return appWindow; + } + } + ++ LeaveCriticalSection(&xfc->railWindows->lock); + free(pKeys); + return NULL; + } +diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h +index 0f85af1..c7702ed 100644 +--- a/client/X11/xf_window.h ++++ b/client/X11/xf_window.h +@@ -187,6 +187,8 @@ void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, int maxWidth + int maxTrackWidth, int maxTrackHeight); + void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, int direction, int x, int y); + void xf_EndLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow); ++void xf_rail_return_window(xfAppWindow* window); ++ + xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd); + + #endif /* FREERDP_CLIENT_X11_WINDOW_H */ +-- +2.53.0 + diff --git a/SOURCES/client-x11-refactor-locking.patch b/SOURCES/client-x11-refactor-locking.patch new file mode 100644 index 0000000..a945a39 --- /dev/null +++ b/SOURCES/client-x11-refactor-locking.patch @@ -0,0 +1,360 @@ +From eeb38c3565473c46da5dea6b43f597064e89b717 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 27 Apr 2026 20:12:11 +0000 +Subject: [PATCH] [client,x11] refactor locking + +X11 and railWindows lock must be held at the same time to avoid +deadlocking. + +Backport of commit 4ff57b68c2960fa414d03c78ff0e0660be1cc5bd. + +Adapted for 2.11.7: C89 declaration style, direct X11 calls instead +of `LogDynAnd*` wrappers, `WINPR_ATTR_UNUSED` removed from +`xfAppWindowsLockFrom`/`UnlockFrom`. + +Made-with: Cursor +--- + client/X11/xf_event.c | 24 ++++++++++++------------ + client/X11/xf_rail.c | 35 +++++++++++++++++++++-------------- + client/X11/xf_rail.h | 14 ++++++++------ + client/X11/xf_window.c | 16 +++++++++------- + 4 files changed, 50 insertions(+), 39 deletions(-) + +diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c +index 8801fbd..e1421ad 100644 +--- a/client/X11/xf_event.c ++++ b/client/X11/xf_event.c +@@ -357,7 +357,7 @@ static BOOL xf_event_Expose(xfContext* xfc, const XExposeEvent* event, BOOL app) + xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, event->window); + if (appWindow) + xf_UpdateWindowArea(xfc, appWindow, x, y, w, h); +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + } + + return TRUE; +@@ -386,7 +386,7 @@ BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window win + { + /* make sure window exists */ + xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, window); +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + if (!appWindow) + return TRUE; + +@@ -465,7 +465,7 @@ BOOL xf_generic_ButtonEvent(xfContext* xfc, int x, int y, int button, Window win + { + /* make sure window exists */ + xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, window); +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + if (!appWindow) + return TRUE; + +@@ -576,7 +576,7 @@ static BOOL xf_event_FocusIn(xfContext* xfc, const XFocusInEvent* event, BOOL ap + */ + if (appWindow) + xf_rail_adjust_position(xfc, appWindow); +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + } + + xf_keyboard_focus_in(xfc); +@@ -628,7 +628,7 @@ static BOOL xf_event_ClientMessage(xfContext* xfc, const XClientMessageEvent* ev + + if (appWindow) + xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_CLOSE); +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + return rc; + } + else +@@ -663,7 +663,7 @@ static BOOL xf_event_EnterNotify(xfContext* xfc, const XEnterWindowEvent* event, + + /* keep track of which window has focus so that we can apply pointer updates */ + xfc->appWindow = appWindow; +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + } + + return TRUE; +@@ -683,7 +683,7 @@ static BOOL xf_event_LeaveNotify(xfContext* xfc, const XLeaveWindowEvent* event, + /* keep track of which window has focus so that we can apply pointer updates */ + if (xfc->appWindow == appWindow) + xfc->appWindow = NULL; +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + } + return TRUE; + } +@@ -774,7 +774,7 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, const XConfigureEvent* even + xf_rail_adjust_position(xfc, appWindow); + } + } +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + } + return xf_pointer_update_scale(xfc); + } +@@ -799,7 +799,7 @@ static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app) + // xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); + appWindow->is_mapped = TRUE; + } +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + } + + return TRUE; +@@ -822,7 +822,7 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, const XUnmapEvent* event, BOOL + + if (appWindow) + appWindow->is_mapped = FALSE; +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + } + + return TRUE; +@@ -954,7 +954,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, + rc = gdi_send_suppress_output(xfc->context.gdi, minimized); + + fail: +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + } + + return rc; +@@ -1066,7 +1066,7 @@ BOOL xf_event_process(freerdp* instance, const XEvent* event) + xfc->appWindow = appWindow; + + BOOL suppress = xf_event_suppress_events(xfc, appWindow, event); +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + if (suppress) + return TRUE; + } +diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c +index 1e57046..d42b864 100644 +--- a/client/X11/xf_rail.c ++++ b/client/X11/xf_rail.c +@@ -101,7 +101,7 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled) + xf_SetWindowStyle(xfc, appWindow, 0, 0); + + activate.windowId = appWindow->windowId; +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + + activate.enabled = enabled; + xfc->rail->ClientActivate(xfc->rail, &activate); +@@ -213,7 +213,7 @@ static void xf_rail_invalidate_region(xfContext* xfc, REGION16* invalidRegion) + + for (index = 0; index < count; index++) + { +- appWindow = xf_rail_get_window(xfc, *(UINT64*)pKeys[index]); ++ appWindow = xf_rail_get_window(xfc, *(UINT64*)pKeys[index], FALSE); + + if (appWindow) + { +@@ -265,7 +265,7 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* + xfContext* xfc = (xfContext*)context; + UINT32 fieldFlags = orderInfo->fieldFlags; + BOOL position_or_size_updated = FALSE; +- xfAppWindow* appWindow = xf_rail_get_window(xfc, orderInfo->windowId); ++ xfAppWindow* appWindow = xf_rail_get_window(xfc, orderInfo->windowId, FALSE); + + if (fieldFlags & WINDOW_ORDER_STATE_NEW) + { +@@ -526,7 +526,7 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* + }*/ + rc = TRUE; + fail: +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + return rc; + } + +@@ -667,7 +667,7 @@ static BOOL xf_rail_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* or + BOOL rc = FALSE; + xfContext* xfc = (xfContext*)context; + BOOL replaceIcon = 0; +- xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId); ++ xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId, FALSE); + + if (!railWindow) + return TRUE; +@@ -690,7 +690,7 @@ static BOOL xf_rail_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* or + xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); + rc = TRUE; + } +- xf_rail_return_window(railWindow); ++ xf_rail_return_window(railWindow, FALSE); + return rc; + } + +@@ -700,7 +700,7 @@ static BOOL xf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_I + BOOL rc = FALSE; + xfContext* xfc = (xfContext*)context; + BOOL replaceIcon = 0; +- xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId); ++ xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId, FALSE); + + if (!railWindow) + return TRUE; +@@ -719,7 +719,7 @@ static BOOL xf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_I + xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); + rc = TRUE; + } +- xf_rail_return_window(railWindow); ++ xf_rail_return_window(railWindow, FALSE); + return rc; + } + +@@ -939,7 +939,7 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context, + int direction = 0; + Window child_window; + xfContext* xfc = (xfContext*)context->custom; +- xfAppWindow* appWindow = xf_rail_get_window(xfc, localMoveSize->windowId); ++ xfAppWindow* appWindow = xf_rail_get_window(xfc, localMoveSize->windowId, FALSE); + + if (!appWindow) + return ERROR_INTERNAL_ERROR; +@@ -1020,7 +1020,7 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context, + else + xf_EndLocalMoveSize(xfc, appWindow); + +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + return CHANNEL_RC_OK; + } + +@@ -1033,7 +1033,7 @@ static UINT xf_rail_server_min_max_info(RailClientContext* context, + const RAIL_MINMAXINFO_ORDER* minMaxInfo) + { + xfContext* xfc = (xfContext*)context->custom; +- xfAppWindow* appWindow = xf_rail_get_window(xfc, minMaxInfo->windowId); ++ xfAppWindow* appWindow = xf_rail_get_window(xfc, minMaxInfo->windowId, FALSE); + + if (appWindow) + { +@@ -1042,7 +1042,7 @@ static UINT xf_rail_server_min_max_info(RailClientContext* context, + minMaxInfo->minTrackHeight, minMaxInfo->maxTrackWidth, + minMaxInfo->maxTrackHeight); + } +- xf_rail_return_window(appWindow); ++ xf_rail_return_window(appWindow, FALSE); + + return CHANNEL_RC_OK; + } +@@ -1199,13 +1199,20 @@ BOOL xf_rail_del_window(xfContext* xfc, UINT64 id) + if (!xfc->railWindows) + return FALSE; + +- return HashTable_Remove(xfc->railWindows, &id); ++ xf_lock_x11(xfc); ++ const BOOL res = HashTable_Remove(xfc->railWindows, &id); ++ xf_unlock_x11(xfc); ++ return res; + } + +-void xf_rail_return_windowFrom(xfAppWindow* window, const char* file, const char* fkt, size_t line) ++void xf_rail_return_windowFrom(xfAppWindow* window, BOOL alreadyLocked, const char* file, ++ const char* fkt, size_t line) + { + if (!window) + return; + ++ if (alreadyLocked) ++ return; ++ + xfAppWindowsUnlockFrom(window->xfc, file, fkt, line); + } +diff --git a/client/X11/xf_rail.h b/client/X11/xf_rail.h +index 83d5fff..a91c1bf 100644 +--- a/client/X11/xf_rail.h ++++ b/client/X11/xf_rail.h +@@ -36,14 +36,16 @@ void xf_rail_disable_remoteapp_mode(xfContext* xfc); + xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, UINT32 x, UINT32 y, UINT32 width, + UINT32 height, UINT32 surfaceId); + +-#define xf_rail_return_window(window) \ +- xf_rail_return_windowFrom((window), __FILE__, __func__, __LINE__) +-void xf_rail_return_windowFrom(xfAppWindow* window, const char* file, const char* fkt, size_t line); ++#define xf_rail_return_window(window, alreadyLocked) \ ++ xf_rail_return_windowFrom((window), (alreadyLocked), __FILE__, __func__, __LINE__) ++void xf_rail_return_windowFrom(xfAppWindow* window, BOOL alreadyLocked, const char* file, ++ const char* fkt, size_t line); + +-#define xf_rail_get_window(xfc, id) \ +- xf_rail_get_windowFrom((xfc), (id), __FILE__, __func__, __LINE__) ++#define xf_rail_get_window(xfc, id, alreadyLocked) \ ++ xf_rail_get_windowFrom((xfc), (id), (alreadyLocked), __FILE__, __func__, __LINE__) + +-xfAppWindow* xf_rail_get_windowFrom(xfContext* xfc, UINT64 id, const char* file, const char* fkt, ++xfAppWindow* xf_rail_get_windowFrom(xfContext* xfc, UINT64 id, BOOL alreadyLocked, const char* file, ++ const char* fkt, + size_t line); + + BOOL xf_rail_del_window(xfContext* xfc, UINT64 id); +diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c +index 09b4a81..8d09ced 100644 +--- a/client/X11/xf_window.c ++++ b/client/X11/xf_window.c +@@ -1070,8 +1070,6 @@ void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, i + if (ay + height > appWindow->windowOffsetY + appWindow->height) + height = (appWindow->windowOffsetY + appWindow->height - 1) - ay; + +- xf_lock_x11(xfc); +- + if (xfc->context.settings->SoftwareGdi) + { + XPutImage(xfc->display, xfc->primary, appWindow->gc, xfc->image, ax, ay, ax, ay, width, +@@ -1081,7 +1079,6 @@ void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, i + XCopyArea(xfc->display, xfc->primary, appWindow->handle, appWindow->gc, ax, ay, width, height, + x, y); + XFlush(xfc->display); +- xf_unlock_x11(xfc); + } + + void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow) +@@ -1122,8 +1119,8 @@ static xfAppWindow* get_windowUnlocked(xfContext* xfc, UINT64 id) + return HashTable_GetItemValue(xfc->railWindows, &id); + } + +-xfAppWindow* xf_rail_get_windowFrom(xfContext* xfc, UINT64 id, const char* file, const char* fkt, +- size_t line) ++xfAppWindow* xf_rail_get_windowFrom(xfContext* xfc, UINT64 id, BOOL alreadyLocked, const char* file, ++ const char* fkt, size_t line) + { + if (!xfc) + return NULL; +@@ -1131,9 +1128,12 @@ xfAppWindow* xf_rail_get_windowFrom(xfContext* xfc, UINT64 id, const char* file, + if (!xfc->railWindows) + return NULL; + +- xfAppWindowsLockFrom(xfc, file, fkt, line); ++ if (!alreadyLocked) ++ xfAppWindowsLockFrom(xfc, file, fkt, line); ++ + xfAppWindow* window = get_windowUnlocked(xfc, id); +- if (!window) ++ ++ if (!window && !alreadyLocked) + xfAppWindowsUnlockFrom(xfc, file, fkt, line); + + return window; +@@ -1176,6 +1176,7 @@ xfAppWindow* xf_AppWindowFromX11WindowFrom(xfContext* xfc, Window wnd, const cha + void xfAppWindowsLockFrom(xfContext* xfc, const char* file, const char* fkt, size_t line) + { + WINPR_ASSERT(xfc); ++ xf_lock_x11(xfc); + EnterCriticalSection(&xfc->railWindows->lock); + } + +@@ -1183,4 +1184,5 @@ void xfAppWindowsUnlockFrom(xfContext* xfc, const char* file, const char* fkt, s + { + WINPR_ASSERT(xfc); + LeaveCriticalSection(&xfc->railWindows->lock); ++ xf_unlock_x11(xfc); + } +-- +2.53.0 + diff --git a/SOURCES/core-tcp-Don-t-ignore-connect-errors.patch b/SOURCES/core-tcp-Don-t-ignore-connect-errors.patch new file mode 100644 index 0000000..fd09a11 --- /dev/null +++ b/SOURCES/core-tcp-Don-t-ignore-connect-errors.patch @@ -0,0 +1,55 @@ +From c3673aaa5b65e8670c218bdfb5916a4112b628c7 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Wed, 14 Jan 2026 13:29:34 +0100 +Subject: [PATCH] [core,tcp] Don't ignore connect errors + +Backport of commit 0bdd8da0993231216a7bb4d5e6e33e47d817a944. + +Co-Authored-By: Claude +--- + libfreerdp/core/tcp.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c +index 1d7eda92e..8a731f117 100644 +--- a/libfreerdp/core/tcp.c ++++ b/libfreerdp/core/tcp.c +@@ -26,8 +26,11 @@ + #include + #include + ++#include ++ + #include + #include ++#include + #include + + #if !defined(_WIN32) +@@ -846,12 +849,19 @@ static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct + if (WAIT_OBJECT_0 != status) + goto fail; + +- status = recv(sockfd, NULL, 0, 0); +- +- if (status == SOCKET_ERROR) + { +- if (WSAGetLastError() == WSAECONNRESET) ++ INT32 optval = 0; ++ socklen_t optlen = sizeof(optval); ++ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) ++ goto fail; ++ ++ if (optval != 0) ++ { ++ char ebuffer[256] = { 0 }; ++ WLog_DBG(TAG, "connect failed with error: %s [%" PRId32 "]", ++ winpr_strerror(optval, ebuffer, sizeof(ebuffer)), optval); + goto fail; ++ } + } + + status = WSAEventSelect(sockfd, handles[0], 0); +-- +2.52.0 + diff --git a/SOURCES/core-tcp-Fix-PreferIPv6OverIPv4-fallback-to-IPv4-add.patch b/SOURCES/core-tcp-Fix-PreferIPv6OverIPv4-fallback-to-IPv4-add.patch new file mode 100644 index 0000000..623108d --- /dev/null +++ b/SOURCES/core-tcp-Fix-PreferIPv6OverIPv4-fallback-to-IPv4-add.patch @@ -0,0 +1,102 @@ +From 462b02de4107845ab235e1668f78a43a31eb11fc Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Wed, 14 Jan 2026 13:38:42 +0100 +Subject: [PATCH] [core,tcp] Fix PreferIPv6OverIPv4 fallback to IPv4 addresses + +Backport of commit 0bdd8da0993231216a7bb4d5e6e33e47d817a944. + +Co-Authored-By: Claude +--- + libfreerdp/core/tcp.c | 61 ++++++++++++++++++++++++++++++++++++------- + 1 file changed, 51 insertions(+), 10 deletions(-) + +diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c +index 8a731f117..3cf24c160 100644 +--- a/libfreerdp/core/tcp.c ++++ b/libfreerdp/core/tcp.c +@@ -1064,6 +1064,53 @@ static BOOL freerdp_tcp_set_keep_alive_mode(const rdpSettings* settings, int soc + return TRUE; + } + ++static struct addrinfo* reorder_addrinfo_by_preference(rdpContext* context, struct addrinfo* addr) ++{ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(addr); ++ ++ const BOOL preferIPv6 = ++ freerdp_settings_get_bool(context->settings, FreeRDP_PreferIPv6OverIPv4); ++ if (!preferIPv6) ++ return addr; ++ ++ struct addrinfo* ipv6Head = NULL; ++ struct addrinfo* ipv6Tail = NULL; ++ struct addrinfo* otherHead = NULL; ++ struct addrinfo* otherTail = NULL; ++ ++ /* Partition the list into IPv6 and other addresses */ ++ while (addr) ++ { ++ struct addrinfo* next = addr->ai_next; ++ addr->ai_next = NULL; ++ ++ if (addr->ai_family == AF_INET6) ++ { ++ if (!ipv6Head) ++ ipv6Head = addr; ++ else ++ ipv6Tail->ai_next = addr; ++ ipv6Tail = addr; ++ } ++ else ++ { ++ if (!otherHead) ++ otherHead = addr; ++ else ++ otherTail->ai_next = addr; ++ otherTail = addr; ++ } ++ addr = next; ++ } ++ ++ /* Concatenate the lists */ ++ if (ipv6Tail) ++ ipv6Tail->ai_next = otherHead; ++ ++ return ipv6Head ? ipv6Head : otherHead; ++} ++ + static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct addrinfo** result, + UINT32 errorCode) + { +@@ -1074,14 +1121,6 @@ static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct + if (!addr) + goto fail; + +- if (freerdp_settings_get_bool(context->settings, FreeRDP_PreferIPv6OverIPv4)) +- { +- while (addr && (addr->ai_family != AF_INET6)) +- addr = addr->ai_next; +- if (!addr) +- addr = input; +- } +- + *result = addr; + return 0; + +@@ -1161,9 +1200,11 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* + freerdp_set_last_error_log(context, 0); + + /* +- * If PreferIPv6OverIPv4 = TRUE we force to IPv6 if there +- * is such an address available, but fall back to first if not found ++ * If PreferIPv6OverIPv4 = TRUE we reorder addresses by preference: ++ * IPv6 addresses come first, then other addresses. + */ ++ result = reorder_addrinfo_by_preference(context, result); ++ + const int rc = + get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND); + if (rc < 0) +-- +2.52.0 + diff --git a/SOURCES/core-tcp-Try-next-DNS-entry-on-connect-failure.patch b/SOURCES/core-tcp-Try-next-DNS-entry-on-connect-failure.patch new file mode 100644 index 0000000..eedb3ff --- /dev/null +++ b/SOURCES/core-tcp-Try-next-DNS-entry-on-connect-failure.patch @@ -0,0 +1,76 @@ +From 051218feec6c3404e625637c9d812817b7d69c26 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Wed, 14 Jan 2026 13:28:18 +0100 +Subject: [PATCH] [core,tcp] Try next DNS entry on connect failure + +Backport of commit bd67348eb3380a66b544835346191bd2138a5ba4. + +Co-Authored-By: Claude +--- + libfreerdp/core/tcp.c | 41 ++++++++++++++++++++++------------------- + 1 file changed, 22 insertions(+), 19 deletions(-) + +diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c +index efc2aec36..1d7eda92e 100644 +--- a/libfreerdp/core/tcp.c ++++ b/libfreerdp/core/tcp.c +@@ -1162,34 +1162,37 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* + do + { + sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); ++ if (sockfd >= 0) ++ { ++ if ((peerAddress = freerdp_tcp_address_to_string( ++ (const struct sockaddr_storage*)addr->ai_addr, NULL)) != NULL) ++ { ++ WLog_DBG(TAG, "connecting to peer %s", peerAddress); ++ free(peerAddress); ++ } ++ ++ if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, ++ addr->ai_addrlen, timeout)) ++ { ++ close(sockfd); ++ sockfd = -1; ++ } ++ } ++ + if (sockfd < 0) + { + const int rc = get_next_addrinfo(context, addr->ai_next, &addr, + FREERDP_ERROR_CONNECT_FAILED); + if (rc < 0) ++ { ++ freeaddrinfo(result); ++ freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED); ++ WLog_ERR(TAG, "failed to connect to %s", hostname); + return rc; ++ } + } + } while (sockfd < 0); + +- if ((peerAddress = freerdp_tcp_address_to_string( +- (const struct sockaddr_storage*)addr->ai_addr, NULL)) != NULL) +- { +- WLog_DBG(TAG, "connecting to peer %s", peerAddress); +- free(peerAddress); +- } +- +- if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen, +- timeout)) +- { +- freeaddrinfo(result); +- close(sockfd); +- +- freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED); +- +- WLog_ERR(TAG, "failed to connect to %s", hostname); +- return -1; +- } +- + freeaddrinfo(result); + } + } +-- +2.52.0 + diff --git a/SOURCES/core-tcp-fix-double-free-in-get_next_addrinfo.patch b/SOURCES/core-tcp-fix-double-free-in-get_next_addrinfo.patch new file mode 100644 index 0000000..a299191 --- /dev/null +++ b/SOURCES/core-tcp-fix-double-free-in-get_next_addrinfo.patch @@ -0,0 +1,39 @@ +From c13c873fcd3e95dcb21e5a811ac878c21ce38d80 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Wed, 14 Jan 2026 13:39:04 +0100 +Subject: [PATCH] [core,tcp] fix double free in get_next_addrinfo + +Backport of commit 48197426444b7b3587874b5eae175af1113beab8. + +Co-Authored-By: Claude +--- + libfreerdp/core/tcp.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c +index 3cf24c160..25632f882 100644 +--- a/libfreerdp/core/tcp.c ++++ b/libfreerdp/core/tcp.c +@@ -1126,7 +1126,7 @@ static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct + + fail: + freerdp_set_last_error_if_not(context, errorCode); +- freeaddrinfo(input); ++ *result = NULL; + return -1; + } + +@@ -1208,7 +1208,10 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* + const int rc = + get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND); + if (rc < 0) ++ { ++ freeaddrinfo(result); + return rc; ++ } + + do + { +-- +2.52.0 + diff --git a/SOURCES/core-tcp-retry-all-DNS-entries-until-success.patch b/SOURCES/core-tcp-retry-all-DNS-entries-until-success.patch new file mode 100644 index 0000000..8942938 --- /dev/null +++ b/SOURCES/core-tcp-retry-all-DNS-entries-until-success.patch @@ -0,0 +1,100 @@ +From 84f0e60c998d7c497d141492f7933bc940f7b239 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Tue, 6 Jan 2026 12:38:34 +0100 +Subject: [PATCH] [core,tcp] retry all DNS entries until success + +Backport of commit 4286a4c16495916fbfa6b8a6764c35fc82e1c5ba. + +Co-Authored-By: Claude +--- + libfreerdp/core/tcp.c | 63 +++++++++++++++++++++++++++++-------------- + 1 file changed, 43 insertions(+), 20 deletions(-) + +diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c +index 0d0641b82..efc2aec36 100644 +--- a/libfreerdp/core/tcp.c ++++ b/libfreerdp/core/tcp.c +@@ -1054,6 +1054,33 @@ static BOOL freerdp_tcp_set_keep_alive_mode(const rdpSettings* settings, int soc + return TRUE; + } + ++static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct addrinfo** result, ++ UINT32 errorCode) ++{ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(result); ++ ++ struct addrinfo* addr = input; ++ if (!addr) ++ goto fail; ++ ++ if (freerdp_settings_get_bool(context->settings, FreeRDP_PreferIPv6OverIPv4)) ++ { ++ while (addr && (addr->ai_family != AF_INET6)) ++ addr = addr->ai_next; ++ if (!addr) ++ addr = input; ++ } ++ ++ *result = addr; ++ return 0; ++ ++fail: ++ freerdp_set_last_error_if_not(context, errorCode); ++ freeaddrinfo(input); ++ return -1; ++} ++ + int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* hostname, int port, + DWORD timeout) + { +@@ -1123,30 +1150,26 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* + } + freerdp_set_last_error_log(context, 0); + +- addr = result; ++ /* ++ * If PreferIPv6OverIPv4 = TRUE we force to IPv6 if there ++ * is such an address available, but fall back to first if not found ++ */ ++ const int rc = ++ get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND); ++ if (rc < 0) ++ return rc; + +- if ((addr->ai_family == AF_INET6) && (addr->ai_next != 0) && +- !settings->PreferIPv6OverIPv4) ++ do + { +- while ((addr = addr->ai_next)) ++ sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); ++ if (sockfd < 0) + { +- if (addr->ai_family == AF_INET) +- break; ++ const int rc = get_next_addrinfo(context, addr->ai_next, &addr, ++ FREERDP_ERROR_CONNECT_FAILED); ++ if (rc < 0) ++ return rc; + } +- +- if (!addr) +- addr = result; +- } +- +- sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); +- +- if (sockfd < 0) +- { +- freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED); +- +- freeaddrinfo(result); +- return -1; +- } ++ } while (sockfd < 0); + + if ((peerAddress = freerdp_tcp_address_to_string( + (const struct sockaddr_storage*)addr->ai_addr, NULL)) != NULL) +-- +2.52.0 + diff --git a/SPECS/freerdp.spec b/SPECS/freerdp.spec index 9c9d229..0aaefa5 100644 --- a/SPECS/freerdp.spec +++ b/SPECS/freerdp.spec @@ -27,7 +27,7 @@ Name: freerdp Version: 2.11.7 -Release: 1%{?dist}.7 +Release: 7%{?dist}.3 Epoch: 2 Summary: Free implementation of the Remote Desktop Protocol (RDP) License: ASL 2.0 @@ -35,6 +35,13 @@ URL: http://www.freerdp.com/ Source0: https://github.com/FreeRDP/FreeRDP/archive/%{version}/FreeRDP-%{version}.tar.gz +# https://issues.redhat.com/browse/RHEL-113722 +Patch: core-tcp-retry-all-DNS-entries-until-success.patch +Patch: core-tcp-Try-next-DNS-entry-on-connect-failure.patch +Patch: core-tcp-Don-t-ignore-connect-errors.patch +Patch: core-tcp-Fix-PreferIPv6OverIPv4-fallback-to-IPv4-add.patch +Patch: core-tcp-fix-double-free-in-get_next_addrinfo.patch + # https://github.com/FreeRDP/FreeRDP/commit/c4a7c371342edf0d307cea728f56d3302f0ab38c Patch: gdi-gfx-properly-clamp-SurfaceToSurface.patch @@ -177,6 +184,16 @@ Patch: codec-dsp-fix-array-bounds-checks.patch # https://github.com/FreeRDP/FreeRDP/commit/c49d1ad43b8c7b32794d0250f2623c2dccd7ef25 Patch: codec-clear-update-clear_glyph_entry-count-after-alloc.patch +# CVE-2026-25952 +# https://github.com/FreeRDP/FreeRDP/commit/1994e9844212a6dfe0ff12309fef520e888986b5 +# https://github.com/FreeRDP/FreeRDP/commit/78fd7f580d5f9e6d9d582d82e5ea96003844fbdf +# https://github.com/FreeRDP/FreeRDP/commit/4ff57b68c2960fa414d03c78ff0e0660be1cc5bd +# https://github.com/FreeRDP/FreeRDP/commit/a278ff74117444c635c50ffa5084ecf517171f5a +Patch: client-x11-lock-appwindow.patch +Patch: client-x11-improve-rails-window-locking.patch +Patch: client-x11-refactor-locking.patch +Patch: client-x11-fix-deadlock-on-output-expose.patch + BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: alsa-lib-devel @@ -434,7 +451,11 @@ find %{buildroot} -name "*.a" -delete %{_libdir}/pkgconfig/winpr-tools2.pc %changelog -* Tue Apr 28 2026 Ondrej Holy - 2:2.11.7-1.7 +* Tue May 05 2026 Ondrej Holy - 2:2.11.7-7.3 +- Lock appWindow to fix use-after-free in RAIL mode (CVE-2026-25952) + Resolves: RHEL-159860 + +* Tue Apr 28 2026 Ondrej Holy - 2:2.11.7-7.2 - Fix double free in xf_rail_window_common cleanup (CVE-2026-26986) - Fix growth of preallocated buffers (CVE-2026-27951) - Fix heap-buffer-overflow in bitmap_cache_put (CVE-2026-29775) @@ -442,36 +463,40 @@ find %{buildroot} -name "*.a" -delete - Fix DSP array bounds checks (CVE-2026-31883) - Fix DSP array bounds checks (CVE-2026-31885) - Update CLEAR_GLYPH_ENTRY::count after alloc (CVE-2026-33985) - Resolves: RHEL-159815, RHEL-155477, RHEL-161046, RHEL-161481 - Resolves: RHEL-161517, RHEL-161084, RHEL-167803 + Resolves: RHEL-159816, RHEL-155478, RHEL-161047, RHEL-161482 + Resolves: RHEL-161519, RHEL-161085, RHEL-168463 -* Fri Apr 10 2026 Ondrej Holy - 2:2.11.7-1.6 +* Tue Apr 14 2026 Ondrej Holy - 2:2.11.7-7.1 - Update CLEAR_VBAR_ENTRY size after alloc (CVE-2026-33984) - Fail progressive_rfx_quant_sub on invalid values (CVE-2026-33983) - Resolves: RHEL-162958, RHEL-162978 + Resolves: RHEL-163097, RHEL-163113 -* Tue Mar 31 2026 Ondrej Holy - 2:2.11.7-1.5 +* Tue Mar 31 2026 Ondrej Holy - 2:2.11.7-7 - Fix use of nsc_process_message - Resolves: RHEL-155993 + Resolves: RHEL-155994 -* Fri Mar 27 2026 Ondrej Holy - 2:2.11.7-1.4 +* Fri Mar 27 2026 Ondrej Holy - 2:2.11.7-6 - Backport several CVE fixes - Resolves: RHEL-148046, RHEL-148049, RHEL-148054, RHEL-148061, RHEL-148079 - Resolves: RHEL-148094, RHEL-148096, RHEL-148104, RHEL-148939, RHEL-149029 - Resolves: RHEL-149042, RHEL-149065, RHEL-155993 + Resolves: RHEL-148052, RHEL-148053, RHEL-148056, RHEL-148075, RHEL-148081 + Resolves: RHEL-148098, RHEL-148105, RHEL-148106, RHEL-148941, RHEL-149032 + Resolves: RHEL-149043, RHEL-149066, RHEL-155994 -* Wed Mar 25 2026 Ondrej Holy - 2:2.11.7-1.3 +* Wed Mar 25 2026 Ondrej Holy - 2:2.11.7-5 - Backport several CVE fixes - Resolves: RHEL-151988, RHEL-152215 + Resolves: RHEL-151989, RHEL-152216 -* Tue Feb 17 2026 Ondrej Holy - 2:2.11.7-1.2 +* Tue Feb 17 2026 Ondrej Holy - 2:2.11.7-4 - Backport several CVE fixes - Resolves: RHEL-148847, RHEL-148887, RHEL-149020 + Resolves: RHEL-148849, RHEL-148891, RHEL-149030 -* Tue Jan 27 2026 Ondrej Holy - 2:2.11.7-1.1 +* Tue Jan 27 2026 Ondrej Holy - 2:2.11.7-3 - Backport several CVE fixes - Resolves: RHEL-142426, RHEL-142410, RHEL-142394, RHEL-142378, RHEL-142362, - Resolves: RHEL-142346, RHEL-142330 + Resolves: RHEL-142427, RHEL-142411, RHEL-142395, RHEL-142379, RHEL-142363 + Resolves: RHEL-142348, RHEL-142332 + +* Fri Jan 16 2026 Ondrej Holy - 2:2.11.7-2 +- Try next DNS entry on connect failure + Resolves: RHEL-113722 * Thu May 09 2024 Ondrej Holy - 2:2.11.7-1 - Update to 2.11.7 (CVE-2024-32039, CVE-2024-32040, CVE-2024-32041,