import Oracle_OSS freerdp-3.10.3-12.el10_2.6

This commit is contained in:
AlmaLinux RelEng Bot 2026-07-21 06:46:43 -04:00
parent 6b0a8dd639
commit 5335061a79
17 changed files with 2220 additions and 19 deletions

View File

@ -0,0 +1,143 @@
From abf9e9c31e64630aa7459ac22e1aff3a277fd830 Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Thu, 30 Apr 2026 10:42:42 +0200
Subject: [PATCH] [channels,cliprdr] abort on duplicate caps
---
channels/cliprdr/server/cliprdr_main.c | 70 +++++++++++++++-----------
1 file changed, 42 insertions(+), 28 deletions(-)
diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c
index 1aef5b373..345236d27 100644
--- a/channels/cliprdr/server/cliprdr_main.c
+++ b/channels/cliprdr/server/cliprdr_main.c
@@ -472,6 +472,15 @@ static UINT cliprdr_server_receive_general_capability(CliprdrServerContext* cont
WINPR_ASSERT(context);
WINPR_ASSERT(cap_set);
+ if (cap_set->capabilitySetLength != sizeof(CLIPRDR_GENERAL_CAPABILITY_SET))
+ {
+ WLog_ERR(TAG,
+ "invalid capabilitySetLength %" PRIu16 " != %" PRIuz
+ " (capabilitySetType=CB_CAPSTYPE_GENERAL)",
+ cap_set->capabilitySetLength, sizeof(CLIPRDR_GENERAL_CAPABILITY_SET));
+ return ERROR_INVALID_DATA;
+ }
+
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return ERROR_INVALID_DATA;
@@ -500,6 +509,26 @@ static UINT cliprdr_server_receive_general_capability(CliprdrServerContext* cont
return CHANNEL_RC_OK;
}
+static BOOL cliprdr_capabilities_contain_capset(const CLIPRDR_CAPABILITIES* capabilities,
+ const CLIPRDR_CAPABILITY_SET* capset)
+{
+ WINPR_ASSERT(capabilities);
+
+ const BYTE* offset = (const BYTE*)capabilities->capabilitySets;
+ for (UINT32 x = 0; x < capabilities->cCapabilitiesSets; x++)
+ {
+ const CLIPRDR_CAPABILITY_SET* cur = (const CLIPRDR_CAPABILITY_SET*)offset;
+ offset += cur->capabilitySetLength;
+
+ if (cur->capabilitySetType == capset->capabilitySetType)
+ {
+ WLog_ERR(TAG, "duplicate CLIPRDR_CAPABILITY_SET %" PRIu16, cur->capabilitySetType);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
/**
* Function description
*
@@ -508,12 +537,9 @@ static UINT cliprdr_server_receive_general_capability(CliprdrServerContext* cont
static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, wStream* s,
const CLIPRDR_HEADER* header)
{
- UINT16 capabilitySetType = 0;
- UINT16 capabilitySetLength = 0;
UINT error = ERROR_INVALID_DATA;
size_t cap_sets_size = 0;
CLIPRDR_CAPABILITIES capabilities = { 0 };
- CLIPRDR_CAPABILITY_SET* capSet = NULL;
WINPR_ASSERT(context);
WINPR_UNUSED(header);
@@ -522,17 +548,16 @@ static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, w
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_INVALID_DATA;
- Stream_Read_UINT16(s, capabilities.cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
+ const UINT16 cCapabilitiesSets = Stream_Get_UINT16(s); /* cCapabilitiesSets (2 bytes) */
Stream_Seek_UINT16(s); /* pad1 (2 bytes) */
- for (size_t index = 0; index < capabilities.cCapabilitiesSets; index++)
+ for (size_t index = 0; index < cCapabilitiesSets; index++)
{
- void* tmp = NULL;
const size_t cap_set_offset = cap_sets_size;
if (!Stream_CheckAndLogRequiredLength(TAG, s, sizeof(CLIPRDR_CAPABILITY_SET)))
goto out;
- Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */
- Stream_Read_UINT16(s, capabilitySetLength); /* capabilitySetLength (2 bytes) */
+ const UINT16 capabilitySetType = Stream_Get_UINT16(s); /* capabilitySetType (2 bytes) */
+ const UINT16 capabilitySetLength = Stream_Get_UINT16(s); /* capabilitySetLength (2 bytes) */
if (capabilitySetLength < sizeof(CLIPRDR_CAPABILITY_SET))
{
@@ -547,26 +572,9 @@ static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, w
TAG, s, (size_t)capabilitySetLength - sizeof(CLIPRDR_CAPABILITY_SET)))
goto out;
- switch (capabilitySetType)
- {
- case CB_CAPSTYPE_GENERAL:
- if (capabilitySetLength != sizeof(CLIPRDR_GENERAL_CAPABILITY_SET))
- {
- WLog_ERR(TAG,
- "invalid capabilitySetLength %" PRIu16 " != %" PRIuz
- " (capabilitySetType=CB_CAPSTYPE_GENERAL)",
- capabilitySetLength, sizeof(CLIPRDR_GENERAL_CAPABILITY_SET));
- goto out;
- }
- break;
- default:
- WLog_ERR(TAG, "unknown cliprdr capability set: %" PRIu16 "", capabilitySetType);
- goto out;
- }
-
cap_sets_size += capabilitySetLength;
- tmp = realloc(capabilities.capabilitySets, cap_sets_size);
+ CLIPRDR_CAPABILITY_SET* tmp = realloc(capabilities.capabilitySets, cap_sets_size);
if (tmp == NULL)
{
WLog_ERR(TAG, "capabilities.capabilitySets realloc failed!");
@@ -574,13 +582,19 @@ static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, w
return CHANNEL_RC_NO_MEMORY;
}
- capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)tmp;
+ capabilities.capabilitySets = tmp;
- capSet = (CLIPRDR_CAPABILITY_SET*)(((BYTE*)capabilities.capabilitySets) + cap_set_offset);
+ CLIPRDR_CAPABILITY_SET* capSet =
+ (CLIPRDR_CAPABILITY_SET*)(((BYTE*)capabilities.capabilitySets) + cap_set_offset);
capSet->capabilitySetType = capabilitySetType;
capSet->capabilitySetLength = capabilitySetLength;
+ if (cliprdr_capabilities_contain_capset(&capabilities, capSet))
+ goto out;
+
+ capabilities.cCapabilitiesSets++;
+
switch (capSet->capabilitySetType)
{
case CB_CAPSTYPE_GENERAL:
--
2.52.0

View File

@ -0,0 +1,73 @@
From ff87e97d62f699826f6b8fc8f754e979d2c87ecb Mon Sep 17 00:00:00 2001
From: Kevin Valerio <kvalerio@protonmail.com>
Date: Wed, 29 Apr 2026 22:39:54 +0200
Subject: [PATCH] fix(cliprdr): validate capabilitySetLength in server caps
---
channels/cliprdr/server/cliprdr_main.c | 38 +++++++++++++++++++++++---
1 file changed, 34 insertions(+), 4 deletions(-)
diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c
index 3cfa057e3..1aef5b373 100644
--- a/channels/cliprdr/server/cliprdr_main.c
+++ b/channels/cliprdr/server/cliprdr_main.c
@@ -528,15 +528,45 @@ static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, w
for (size_t index = 0; index < capabilities.cCapabilitiesSets; index++)
{
void* tmp = NULL;
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
+ const size_t cap_set_offset = cap_sets_size;
+ if (!Stream_CheckAndLogRequiredLength(TAG, s, sizeof(CLIPRDR_CAPABILITY_SET)))
goto out;
Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */
Stream_Read_UINT16(s, capabilitySetLength); /* capabilitySetLength (2 bytes) */
+ if (capabilitySetLength < sizeof(CLIPRDR_CAPABILITY_SET))
+ {
+ WLog_ERR(TAG,
+ "invalid capabilitySetLength %" PRIu16 " < %" PRIuz
+ " (capabilitySetType=%" PRIu16 ")",
+ capabilitySetLength, sizeof(CLIPRDR_CAPABILITY_SET), capabilitySetType);
+ goto out;
+ }
+
+ if (!Stream_CheckAndLogRequiredLength(
+ TAG, s, (size_t)capabilitySetLength - sizeof(CLIPRDR_CAPABILITY_SET)))
+ goto out;
+
+ switch (capabilitySetType)
+ {
+ case CB_CAPSTYPE_GENERAL:
+ if (capabilitySetLength != sizeof(CLIPRDR_GENERAL_CAPABILITY_SET))
+ {
+ WLog_ERR(TAG,
+ "invalid capabilitySetLength %" PRIu16 " != %" PRIuz
+ " (capabilitySetType=CB_CAPSTYPE_GENERAL)",
+ capabilitySetLength, sizeof(CLIPRDR_GENERAL_CAPABILITY_SET));
+ goto out;
+ }
+ break;
+ default:
+ WLog_ERR(TAG, "unknown cliprdr capability set: %" PRIu16 "", capabilitySetType);
+ goto out;
+ }
+
cap_sets_size += capabilitySetLength;
- if (cap_sets_size > 0)
- tmp = realloc(capabilities.capabilitySets, cap_sets_size);
+ tmp = realloc(capabilities.capabilitySets, cap_sets_size);
if (tmp == NULL)
{
WLog_ERR(TAG, "capabilities.capabilitySets realloc failed!");
@@ -546,7 +576,7 @@ static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, w
capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)tmp;
- capSet = &(capabilities.capabilitySets[index]);
+ capSet = (CLIPRDR_CAPABILITY_SET*)(((BYTE*)capabilities.capabilitySets) + cap_set_offset);
capSet->capabilitySetType = capabilitySetType;
capSet->capabilitySetLength = capabilitySetLength;
--
2.52.0

View File

@ -0,0 +1,31 @@
From ae03a9ff981ce7be1ab09dba2cd319d54984f910 Mon Sep 17 00:00:00 2001
From: David Fort <contact@hardening-consulting.com>
Date: Wed, 6 May 2026 09:52:33 +0200
Subject: [PATCH] Fix for GHSA-j9q5-7g8m-jc9v, disable NDR pointer aliasing
The usage of aliased pointers can be used to trigger a double free, or a type confusion
(using the same memory location twice and pretend it's 2 different types of objects).
As pointer aliasing is never seen in practice with RDPEAR, let's just return an error
when we see an aliased pointer.
---
channels/rdpear/common/ndr.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/channels/rdpear/common/ndr.c b/channels/rdpear/common/ndr.c
index 6e4b10aa8..20cc31c6e 100644
--- a/channels/rdpear/common/ndr.c
+++ b/channels/rdpear/common/ndr.c
@@ -931,6 +931,11 @@ BOOL ndr_read_pointedMessageEx(NdrContext* context, wStream* s, ndr_refid ptrId,
return FALSE;
}
}
+ else
+ {
+ WLog_ERR(TAG, "aliased pointer aren't supported for now");
+ return FALSE;
+ }
*target = ret;
return TRUE;
--
2.54.0

View File

@ -0,0 +1,36 @@
From 668fcb49d4856fad28f685db54a572af2a284b50 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Sat, 10 Jan 2026 09:33:54 +0100
Subject: [PATCH] [channels,rdpear] fix ndr_read checks
---
channels/rdpear/common/ndr.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/channels/rdpear/common/ndr.c b/channels/rdpear/common/ndr.c
index d318ed63c..d0bd6d959 100644
--- a/channels/rdpear/common/ndr.c
+++ b/channels/rdpear/common/ndr.c
@@ -574,8 +574,10 @@ BOOL ndr_read_uconformant_array(NdrContext* context, wStream* s, const NdrArrayH
WINPR_ASSERT(itemType);
WINPR_ASSERT(vtarget);
- UINT32 count = 0;
+ if (itemType->itemSize == 0)
+ return FALSE;
+ UINT32 count = 0;
if (!ndr_read_uint32(context, s, &count))
return FALSE;
@@ -910,6 +912,8 @@ BOOL ndr_read_pointedMessageEx(NdrContext* context, wStream* s, ndr_refid ptrId,
if (!ret)
{
size_t itemCount = ndr_hintsCount(descr, hints);
+ if (itemCount == 0)
+ return FALSE;
ret = calloc(itemCount, descr->itemSize);
if (!ret)
return FALSE;
--
2.54.0

View File

@ -0,0 +1,170 @@
From 4c5a54419f0d6b62454acf2069ca5bf97f6952e7 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 5 May 2026 11:04:31 +0000
Subject: [PATCH] [client,x11] fix deadlock on output expose
Backport of commit a278ff74117444c635c50ffa5084ecf517171f5a.
Adapted for 3.10.3: `WINPR_ATTR_NODISCARD` attribute removed
(not available in 3.10.3), C99 `bool` replaced with `BOOL`,
adjusted hunk offsets.
Made-with: Cursor
---
client/X11/xf_client.c | 3 ++
client/X11/xf_event.c | 78 +++++++++++++++++++++++++-----------------
client/X11/xf_event.h | 3 ++
client/X11/xfreerdp.h | 3 ++
4 files changed, 56 insertions(+), 31 deletions(-)
diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c
index 7ad30d6..08dc2ca 100644
--- a/client/X11/xf_client.c
+++ b/client/X11/xf_client.c
@@ -514,6 +514,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 a1fbb84..172fb68 100644
--- a/client/X11/xf_event.c
+++ b/client/X11/xf_event.c
@@ -370,50 +370,30 @@ 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 = 0;
- int y = 0;
- int w = 0;
- int h = 0;
- rdpSettings* settings = NULL;
-
WINPR_ASSERT(xfc);
WINPR_ASSERT(event);
- settings = xfc->common.context.settings;
+ rdpSettings* settings = xfc->common.context.settings;
WINPR_ASSERT(settings);
if (!app && (freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) ||
freerdp_settings_get_bool(settings, FreeRDP_MultiTouchGestures)))
{
- x = 0;
- y = 0;
- w = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
- h = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
+ xfc->exposedArea.x = 0;
+ xfc->exposedArea.y = 0;
+ xfc->exposedArea.w = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
+ xfc->exposedArea.h = freerdp_settings_get_uint32(settings, FreeRDP_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->common.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;
}
@@ -1372,3 +1352,39 @@ BOOL xf_generic_RawButtonEvent(xfContext* xfc, int button, BOOL app, BOOL down)
return TRUE;
}
+
+BOOL xf_event_update_screen(freerdp* instance)
+{
+ WINPR_ASSERT(instance);
+
+ xfContext* xfc = (xfContext*)instance->context;
+ WINPR_ASSERT(xfc);
+
+ rdpSettings* settings = xfc->common.context.settings;
+ WINPR_ASSERT(settings);
+
+ if (!xfc->exposeRequested)
+ return TRUE;
+ xfc->exposeRequested = false;
+
+ if (!xfc->remote_app)
+ {
+ if (xfc->common.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 2f4ab07..299d2d3 100644
--- a/client/X11/xf_event.h
+++ b/client/X11/xf_event.h
@@ -31,6 +31,9 @@ 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 ba41553..677e3bc 100644
--- a/client/X11/xfreerdp.h
+++ b/client/X11/xfreerdp.h
@@ -319,6 +319,9 @@ struct xf_context
BOOL xi_event;
HANDLE pipethread;
wLog* log;
+ bool exposeRequested;
+ GDI_RGN exposedArea;
+ Window exposedWindow;
};
BOOL xf_create_window(xfContext* xfc);
--
2.54.0

View File

@ -0,0 +1,413 @@
From 24ef57b3085bfc353ab375ebba6a1c29d13929f1 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 5 May 2026 11:04:17 +0000
Subject: [PATCH] [client,x11] improve rails window locking
Backport of commit 78fd7f580d5f9e6d9d582d82e5ea96003844fbdf.
Adapted for 3.10.3: `nullptr` replaced with `NULL`,
`WINPR_ATTR_MALLOC` updated for renamed function,
`WINPR_ATTR_UNUSED` removed from `xfAppWindowsLockFrom`/
`UnlockFrom` signatures, `LogDynAndXSetTransientForHint`
replaced with inline `XSetTransientForHint` + `WLog_WARN`,
`xf_rail_add_window` parameter types `INT32` to `UINT32`,
`WLog_PrintTextMessage` replaced with `WLog_PrintMessage`
(not available in 3.10.3).
Made-with: Cursor
---
client/X11/xf_event.c | 3 +-
client/X11/xf_graphics.c | 5 +--
client/X11/xf_rail.c | 52 +++++++++++++----------------
client/X11/xf_rail.h | 11 +++++--
client/X11/xf_window.c | 70 ++++++++++++++++++++++++++++++++++++----
client/X11/xf_window.h | 12 +++++--
client/X11/xfreerdp.h | 4 +++
7 files changed, 112 insertions(+), 45 deletions(-)
diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c
index b26ece0..f82ab94 100644
--- a/client/X11/xf_event.c
+++ b/client/X11/xf_event.c
@@ -411,9 +411,8 @@ 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);
}
return TRUE;
diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c
index 5e68354..310f2a4 100644
--- a/client/X11/xf_graphics.c
+++ b/client/X11/xf_graphics.c
@@ -39,6 +39,7 @@
#include "xf_graphics.h"
#include "xf_event.h"
+#include "xf_window.h"
#include <freerdp/log.h>
#define TAG CLIENT_TAG("x11")
@@ -252,12 +253,12 @@ static Window xf_Pointer_get_window(xfContext* xfc)
if (xfc->remote_app)
{
Window w = 0;
- HashTable_Lock(xfc->railWindows);
+ xf_AppWindowsLock(xfc);
if (!xfc->appWindow)
WLog_WARN(TAG, "xf_Pointer: Invalid appWindow");
else
w = xfc->appWindow->handle;
- HashTable_Unlock(xfc->railWindows);
+ xf_AppWindowsUnlock(xfc);
return w;
}
else
diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c
index 2d79867..3353a8d 100644
--- a/client/X11/xf_rail.c
+++ b/client/X11/xf_rail.c
@@ -109,9 +109,9 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled)
WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
activate.windowId = (UINT32)appWindow->windowId;
+ xf_rail_return_window(appWindow);
activate.enabled = enabled;
xfc->rail->ClientActivate(xfc->rail, &activate);
- xf_rail_return_window(appWindow);
}
BOOL xf_rail_send_client_system_command(xfContext* xfc, UINT64 windowId, UINT16 command)
@@ -309,10 +309,12 @@ static void window_state_log_style_int(wLog* log, const WINDOW_STATE_ORDER* wind
static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
const WINDOW_STATE_ORDER* windowState)
{
+ BOOL rc = FALSE;
+ xfAppWindow* appWindow = NULL;
xfContext* xfc = (xfContext*)context;
UINT32 fieldFlags = orderInfo->fieldFlags;
BOOL position_or_size_updated = FALSE;
- xfAppWindow* appWindow = xf_rail_get_window(xfc, orderInfo->windowId);
+ appWindow = xf_rail_get_window(xfc, orderInfo->windowId);
if (fieldFlags & WINDOW_ORDER_STATE_NEW)
{
@@ -322,7 +324,7 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO*
windowState->windowHeight, 0xFFFFFFFF);
if (!appWindow)
- return FALSE;
+ goto fail;
appWindow->dwStyle = windowState->style;
appWindow->dwExStyle = windowState->extendedStyle;
@@ -363,13 +365,13 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO*
}
if (!appWindow->title)
- return FALSE;
+ goto fail;
xf_AppWindowInit(xfc, appWindow);
}
if (!appWindow)
- return FALSE;
+ goto fail;
/* Keep track of any position/size update so that we can force a refresh of the window */
if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
@@ -441,14 +443,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 (!(title = ConvertWCharNToUtf8Alloc(
cnv.wc, windowState->titleInfo.length / sizeof(WCHAR), NULL)))
{
WLog_ERR(TAG, "failed to convert window title");
- return FALSE;
+ goto fail;
}
free(appWindow->title);
@@ -489,7 +491,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));
@@ -518,7 +520,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));
@@ -594,7 +596,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)
@@ -1012,14 +1017,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;
default:
break;
}
@@ -1196,13 +1201,16 @@ xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, UINT32 x, UINT32 y, U
appWindow->width = width;
appWindow->height = height;
+ xf_AppWindowsLock(xfc);
if (!xf_AppWindowCreate(xfc, appWindow))
goto fail;
+
if (!HashTable_Insert(xfc->railWindows, &appWindow->windowId, (void*)appWindow))
goto fail;
return appWindow;
fail:
rail_window_free(appWindow);
+ xf_AppWindowsUnlock(xfc);
return NULL;
}
@@ -1217,26 +1225,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;
-
- HashTable_Lock(xfc->railWindows);
- xfAppWindow* window = HashTable_GetItemValue(xfc->railWindows, &id);
- if (!window)
- HashTable_Unlock(xfc->railWindows);
-
- 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;
- HashTable_Unlock(window->xfc->railWindows);
+ xfAppWindowsUnlockFrom(window->xfc, file, fkt, line);
}
diff --git a/client/X11/xf_rail.h b/client/X11/xf_rail.h
index 8e8ed33..2b365b5 100644
--- a/client/X11/xf_rail.h
+++ b/client/X11/xf_rail.h
@@ -38,9 +38,14 @@ 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);
+#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_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 801efbc..8d7bcd6 100644
--- a/client/X11/xf_window.c
+++ b/client/X11/xf_window.c
@@ -37,6 +37,7 @@
#include <winpr/assert.h>
#include <winpr/thread.h>
+#include <winpr/synch.h>
#include <winpr/crt.h>
#include <winpr/string.h>
@@ -1404,7 +1405,31 @@ 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)
{
ULONG_PTR* pKeys = NULL;
@@ -1412,29 +1437,28 @@ xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd)
if (!xfc->railWindows)
return NULL;
- HashTable_Lock(xfc->railWindows);
+ xfAppWindowsLockFrom(xfc, file, fkt, line);
size_t count = HashTable_GetKeys(xfc->railWindows, &pKeys);
for (size_t index = 0; index < count; index++)
{
- xfAppWindow* appWindow = HashTable_GetItemValue(xfc->railWindows, (void*)pKeys[index]);
+ xfAppWindow* appWindow = get_windowUnlocked(xfc, *(UINT64*)pKeys[index]);
if (!appWindow)
{
- HashTable_Unlock(xfc->railWindows);
+ xfAppWindowsUnlockFrom(xfc, file, fkt, line);
free(pKeys);
return NULL;
}
if (appWindow->handle == wnd)
{
- HashTable_Unlock(xfc->railWindows);
free(pKeys);
return appWindow;
}
}
- HashTable_Unlock(xfc->railWindows);
+ xfAppWindowsUnlockFrom(xfc, file, fkt, line);
free(pKeys);
return NULL;
}
@@ -1556,3 +1580,37 @@ void xf_XSetTransientForHint(xfContext* xfc, xfAppWindow* window)
}
xf_rail_return_window(parent);
}
+
+void xfAppWindowsLockFrom(xfContext* xfc, const char* file, const char* fkt, size_t line)
+{
+ WINPR_ASSERT(xfc);
+
+#if defined(WITH_VERBOSE_WINPR_ASSERT)
+ const DWORD level = WLOG_TRACE;
+ if (WLog_IsLevelActive(xfc->log, level))
+ WLog_PrintMessage(xfc->log, WLOG_MESSAGE_TEXT, level, line, file, fkt, "[rails] locking [%s]", fkt);
+#endif
+
+ HashTable_Lock(xfc->railWindows);
+
+#if defined(WITH_VERBOSE_WINPR_ASSERT)
+ WINPR_ASSERT(!xfc->isRailWindowsLocked);
+ xfc->isRailWindowsLocked = TRUE;
+#endif
+}
+
+void xfAppWindowsUnlockFrom(xfContext* xfc, const char* file, const char* fkt, size_t line)
+{
+ WINPR_ASSERT(xfc);
+
+#if defined(WITH_VERBOSE_WINPR_ASSERT)
+ const DWORD level = WLOG_TRACE;
+ if (WLog_IsLevelActive(xfc->log, level))
+ WLog_PrintMessage(xfc->log, WLOG_MESSAGE_TEXT, level, line, file, fkt, "[rails] unocking [%s]", fkt);
+
+ WINPR_ASSERT(xfc->isRailWindowsLocked);
+ xfc->isRailWindowsLocked = FALSE;
+#endif
+
+ HashTable_Unlock(xfc->railWindows);
+}
diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h
index 2384d61..25eedb3 100644
--- a/client/X11/xf_window.h
+++ b/client/X11/xf_window.h
@@ -202,8 +202,16 @@ 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);
-xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd);
-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);
+
+#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);
const char* window_styles_to_string(UINT32 style, char* buffer, size_t length);
const char* window_styles_ex_to_string(UINT32 styleEx, char* buffer, size_t length);
diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h
index 000ba56..ba41553 100644
--- a/client/X11/xfreerdp.h
+++ b/client/X11/xfreerdp.h
@@ -290,6 +290,10 @@ struct xf_context
wHashTable* railWindows;
xfRailIconCache* railIconCache;
+#if defined(WITH_VERBOSE_WINPR_ASSERT)
+ BOOL isRailWindowsLocked;
+#endif
+
BOOL xkbAvailable;
BOOL xrenderAvailable;
--
2.54.0

View File

@ -0,0 +1,439 @@
From 87ef0851132df9b00380f3cfe9d63272a85d7c49 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 5 May 2026 11:03:44 +0000
Subject: [PATCH] [client,x11] lock appWindow
Backport of commit 1994e9844212a6dfe0ff12309fef520e888986b5.
Adapted for 3.10.3: `xf_generic_MotionNotify_` renamed to
`xf_generic_MotionNotify`, `xf_generic_ButtonEvent_` to
`xf_generic_ButtonEvent`, `WINPR_ATTR_MALLOC` attribute removed
(not available in 3.10.3), adjusted hunk offsets.
Made-with: Cursor
---
client/X11/xf_event.c | 47 ++++++++++++++++++----------
client/X11/xf_graphics.c | 10 +++---
client/X11/xf_rail.c | 67 ++++++++++++++++++++++++++--------------
client/X11/xf_rail.h | 3 ++
client/X11/xf_window.c | 8 ++++-
client/X11/xf_window.h | 1 +
6 files changed, 92 insertions(+), 44 deletions(-)
diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c
index 0fce625..b26ece0 100644
--- a/client/X11/xf_event.c
+++ b/client/X11/xf_event.c
@@ -442,7 +442,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 */
@@ -536,7 +538,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 */
@@ -694,6 +698,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_keyboard_focus_in(xfc);
@@ -734,12 +739,13 @@ static BOOL xf_event_ClientMessage(xfContext* xfc, const XClientMessageEvent* ev
{
if (app)
{
+ BOOL rc = TRUE;
xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, event->window);
if (appWindow)
- return xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_CLOSE);
-
- return TRUE;
+ rc = xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_CLOSE);
+ xf_rail_return_window(appWindow);
+ return rc;
}
else
{
@@ -772,6 +778,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;
@@ -793,6 +800,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;
}
@@ -893,6 +901,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);
}
@@ -916,6 +925,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;
@@ -930,13 +940,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->common.context.gdi, TRUE);
- else
+ return gdi_send_suppress_output(xfc->common.context.gdi, TRUE);
+
{
xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, event->window);
if (appWindow)
appWindow->is_mapped = FALSE;
+ xf_rail_return_window(appWindow);
}
return TRUE;
@@ -944,6 +955,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);
@@ -968,7 +980,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event,
appWindow = xf_AppWindowFromX11Window(xfc, event->window);
if (!appWindow)
- return TRUE;
+ goto fail;
}
if (event->atom == xfc->_NET_WM_STATE)
@@ -1040,8 +1052,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event,
if (appWindow->rail_state != WINDOW_SHOW_MAXIMIZED)
{
appWindow->rail_state = WINDOW_SHOW_MAXIMIZED;
- return xf_rail_send_client_system_command(xfc, appWindow->windowId,
- SC_MAXIMIZE);
+ rc = xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MAXIMIZE);
}
}
else if (appWindow->minimized)
@@ -1049,8 +1060,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event,
if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED)
{
appWindow->rail_state = WINDOW_SHOW_MINIMIZED;
- return xf_rail_send_client_system_command(xfc, appWindow->windowId,
- SC_MINIMIZE);
+ rc = xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MINIMIZE);
}
}
else
@@ -1058,15 +1068,18 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event,
if (appWindow->rail_state != WINDOW_SHOW && appWindow->rail_state != WINDOW_HIDE)
{
appWindow->rail_state = WINDOW_SHOW;
- return xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE);
+ rc = xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE);
}
}
}
else if (minimizedChanged)
- gdi_send_suppress_output(xfc->common.context.gdi, minimized);
+ rc = gdi_send_suppress_output(xfc->common.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)
@@ -1182,7 +1195,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))
+ const BOOL rc = xf_event_suppress_events(xfc, appWindow, event);
+ xf_rail_return_window(appWindow);
+ if (rc)
return TRUE;
}
}
diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c
index a6950ad..5e68354 100644
--- a/client/X11/xf_graphics.c
+++ b/client/X11/xf_graphics.c
@@ -251,12 +251,14 @@ static Window xf_Pointer_get_window(xfContext* xfc)
}
if (xfc->remote_app)
{
+ Window w = 0;
+ HashTable_Lock(xfc->railWindows);
if (!xfc->appWindow)
- {
WLog_WARN(TAG, "xf_Pointer: Invalid appWindow");
- return 0;
- }
- return xfc->appWindow->handle;
+ else
+ w = xfc->appWindow->handle;
+ HashTable_Unlock(xfc->railWindows);
+ return w;
}
else
{
diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c
index f931b50..2d79867 100644
--- a/client/X11/xf_rail.c
+++ b/client/X11/xf_rail.c
@@ -111,6 +111,7 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled)
activate.windowId = (UINT32)appWindow->windowId;
activate.enabled = enabled;
xfc->rail->ClientActivate(xfc->rail, &activate);
+ xf_rail_return_window(appWindow);
}
BOOL xf_rail_send_client_system_command(xfContext* xfc, UINT64 windowId, UINT16 command)
@@ -255,6 +256,7 @@ BOOL xf_rail_paint_surface(xfContext* xfc, UINT64 windowId, const RECTANGLE_16*
updateRect.right - updateRect.left, updateRect.bottom - updateRect.top);
}
region16_uninit(&windowInvalidRegion);
+ xf_rail_return_window(appWindow);
return TRUE;
}
@@ -729,61 +731,65 @@ 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 = NULL;
- xfRailIcon* icon = NULL;
BOOL replaceIcon = 0;
- railWindow = xf_rail_get_window(xfc, orderInfo->windowId);
+ 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 = NULL;
- xfRailIcon* icon = NULL;
+ WINPR_ASSERT(orderInfo);
+
BOOL replaceIcon = 0;
- railWindow = xf_rail_get_window(xfc, orderInfo->windowId);
+ 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,
@@ -1023,6 +1029,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;
}
@@ -1044,6 +1051,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;
}
@@ -1215,7 +1223,20 @@ xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64 id)
return NULL;
if (!xfc->railWindows)
- return FALSE;
+ return NULL;
+
+ HashTable_Lock(xfc->railWindows);
+ xfAppWindow* window = HashTable_GetItemValue(xfc->railWindows, &id);
+ if (!window)
+ HashTable_Unlock(xfc->railWindows);
+
+ return window;
+}
+
+void xf_rail_return_window(xfAppWindow* window)
+{
+ if (!window)
+ return;
- return HashTable_GetItemValue(xfc->railWindows, &id);
+ HashTable_Unlock(window->xfc->railWindows);
}
diff --git a/client/X11/xf_rail.h b/client/X11/xf_rail.h
index 9cd54f0..8e8ed33 100644
--- a/client/X11/xf_rail.h
+++ b/client/X11/xf_rail.h
@@ -37,6 +37,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 cf3d8bc..801efbc 100644
--- a/client/X11/xf_window.c
+++ b/client/X11/xf_window.c
@@ -1412,25 +1412,29 @@ xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd)
if (!xfc->railWindows)
return NULL;
+ HashTable_Lock(xfc->railWindows);
size_t count = HashTable_GetKeys(xfc->railWindows, &pKeys);
for (size_t index = 0; index < count; index++)
{
- xfAppWindow* appWindow = xf_rail_get_window(xfc, *(UINT64*)pKeys[index]);
+ xfAppWindow* appWindow = HashTable_GetItemValue(xfc->railWindows, (void*)pKeys[index]);
if (!appWindow)
{
+ HashTable_Unlock(xfc->railWindows);
free(pKeys);
return NULL;
}
if (appWindow->handle == wnd)
{
+ HashTable_Unlock(xfc->railWindows);
free(pKeys);
return appWindow;
}
}
+ HashTable_Unlock(xfc->railWindows);
free(pKeys);
return NULL;
}
@@ -1509,6 +1513,7 @@ UINT xf_AppUpdateWindowFromSurface(xfContext* xfc, gdiGfxSurface* surface)
rc = CHANNEL_RC_OK;
fail:
+ xf_rail_return_window(appWindow);
XFlush(xfc->display);
xf_unlock_x11(xfc);
return rc;
@@ -1549,4 +1554,5 @@ void xf_XSetTransientForHint(xfContext* xfc, xfAppWindow* window)
WLog_WARN(TAG, "XSetTransientForHint [%d]{%s}", rc,
x11_error_to_string(xfc, rc, buffer, sizeof(buffer)));
}
+ xf_rail_return_window(parent);
}
diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h
index efbc67d..2384d61 100644
--- a/client/X11/xf_window.h
+++ b/client/X11/xf_window.h
@@ -203,6 +203,7 @@ void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, int maxWidth
void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, int direction, int x, int y);
void xf_EndLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow);
xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd);
+void xf_rail_return_window(xfAppWindow* window);
const char* window_styles_to_string(UINT32 style, char* buffer, size_t length);
const char* window_styles_ex_to_string(UINT32 styleEx, char* buffer, size_t length);
--
2.54.0

View File

@ -0,0 +1,446 @@
From aaa9a2609069494e89b166417ad47570d205c3bc Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 5 May 2026 11:04:31 +0000
Subject: [PATCH] [client,x11] refactor locking
Backport of commit 4ff57b68c2960fa414d03c78ff0e0660be1cc5bd.
Adapted for 3.10.3: `LogDynAndXSetClipMask`/`LogDynAndXSync`
replaced with direct `XSetClipMask`/`XSync` calls,
`LogDynAndXPutImage`/`LogDynAndXFlush` replaced with direct
`XPutImage`/`XFlush` calls, adjusted hunk offsets.
Made-with: Cursor
---
client/X11/xf_event.c | 24 ++++++++++++------------
client/X11/xf_gfx.c | 4 ++--
client/X11/xf_rail.c | 37 ++++++++++++++++++++++---------------
client/X11/xf_rail.h | 17 +++++++++--------
client/X11/xf_window.c | 27 ++++++++++++++-------------
5 files changed, 59 insertions(+), 50 deletions(-)
diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c
index f82ab94..a1fbb84 100644
--- a/client/X11/xf_event.c
+++ b/client/X11/xf_event.c
@@ -412,7 +412,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;
@@ -442,7 +442,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;
@@ -538,7 +538,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;
@@ -697,7 +697,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);
@@ -743,7 +743,7 @@ static BOOL xf_event_ClientMessage(xfContext* xfc, const XClientMessageEvent* ev
if (appWindow)
rc = 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
@@ -777,7 +777,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;
@@ -799,7 +799,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;
}
@@ -900,7 +900,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);
}
@@ -924,7 +924,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;
@@ -946,7 +946,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;
@@ -1075,7 +1075,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event,
rc = gdi_send_suppress_output(xfc->common.context.gdi, minimized);
fail:
- xf_rail_return_window(appWindow);
+ xf_rail_return_window(appWindow, FALSE);
}
return rc;
@@ -1195,7 +1195,7 @@ BOOL xf_event_process(freerdp* instance, const XEvent* event)
xfc->appWindow = appWindow;
const BOOL rc = xf_event_suppress_events(xfc, appWindow, event);
- xf_rail_return_window(appWindow);
+ xf_rail_return_window(appWindow, FALSE);
if (rc)
return TRUE;
}
diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c
index 48a2755..b748cf4 100644
--- a/client/X11/xf_gfx.c
+++ b/client/X11/xf_gfx.c
@@ -66,6 +66,7 @@ static UINT xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface)
if (!(rects = region16_rects(&surface->gdi.invalidRegion, &nbRects)))
return CHANNEL_RC_OK;
+ xf_lock_x11(xfc);
for (UINT32 x = 0; x < nbRects; x++)
{
const RECTANGLE_16* rect = &rects[x];
@@ -90,9 +91,7 @@ static UINT xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface)
{
XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image, nXSrc, nYSrc, nXDst,
nYDst, dwidth, dheight);
- xf_lock_x11(xfc);
xf_rail_paint_surface(xfc, surface->gdi.windowId, rect);
- xf_unlock_x11(xfc);
}
else
#ifdef WITH_XRENDER
@@ -116,6 +115,7 @@ fail:
region16_clear(&surface->gdi.invalidRegion);
XSetClipMask(xfc->display, xfc->gc, None);
XSync(xfc->display, False);
+ xf_unlock_x11(xfc);
return rc;
}
diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c
index 3353a8d..5322859 100644
--- a/client/X11/xf_rail.c
+++ b/client/X11/xf_rail.c
@@ -109,7 +109,7 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled)
WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
activate.windowId = (UINT32)appWindow->windowId;
- xf_rail_return_window(appWindow);
+ xf_rail_return_window(appWindow, FALSE);
activate.enabled = enabled;
xfc->rail->ClientActivate(xfc->rail, &activate);
}
@@ -227,7 +227,7 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
BOOL xf_rail_paint_surface(xfContext* xfc, UINT64 windowId, const RECTANGLE_16* rect)
{
- xfAppWindow* appWindow = xf_rail_get_window(xfc, windowId);
+ xfAppWindow* appWindow = xf_rail_get_window(xfc, windowId, FALSE);
WINPR_ASSERT(rect);
@@ -256,7 +256,7 @@ BOOL xf_rail_paint_surface(xfContext* xfc, UINT64 windowId, const RECTANGLE_16*
updateRect.right - updateRect.left, updateRect.bottom - updateRect.top);
}
region16_uninit(&windowInvalidRegion);
- xf_rail_return_window(appWindow);
+ xf_rail_return_window(appWindow, FALSE);
return TRUE;
}
@@ -314,7 +314,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;
- appWindow = xf_rail_get_window(xfc, orderInfo->windowId);
+ appWindow = xf_rail_get_window(xfc, orderInfo->windowId, FALSE);
if (fieldFlags & WINDOW_ORDER_STATE_NEW)
{
@@ -598,7 +598,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;
}
@@ -739,7 +739,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;
@@ -762,7 +762,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;
}
@@ -774,7 +774,7 @@ static BOOL xf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_I
WINPR_ASSERT(orderInfo);
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;
@@ -793,7 +793,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;
}
@@ -951,7 +951,7 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context,
int direction = 0;
Window child_window = 0;
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;
@@ -1034,7 +1034,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;
}
@@ -1047,7 +1047,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)
{
@@ -1056,7 +1056,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;
}
@@ -1222,13 +1222,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 2b365b5..dafbd51 100644
--- a/client/X11/xf_rail.h
+++ b/client/X11/xf_rail.h
@@ -38,14 +38,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);
-#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_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);
+#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, alreadyLocked) \
+ xf_rail_get_windowFrom((xfc), (id), (alreadyLocked), __FILE__, __func__, __LINE__)
+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 8d7bcd6..3a67e0e 100644
--- a/client/X11/xf_window.c
+++ b/client/X11/xf_window.c
@@ -1343,8 +1343,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 (freerdp_settings_get_bool(settings, FreeRDP_SoftwareGdi))
{
XPutImage(xfc->display, appWindow->pixmap, appWindow->gc, xfc->image, ax, ay, x, y, width,
@@ -1354,7 +1352,6 @@ void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, i
XCopyArea(xfc->display, appWindow->pixmap, appWindow->handle, appWindow->gc, x, y, width,
height, x, y);
XFlush(xfc->display);
- xf_unlock_x11(xfc);
}
static void xf_AppWindowDestroyImage(xfAppWindow* appWindow)
@@ -1411,8 +1408,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;
@@ -1420,9 +1417,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;
@@ -1471,7 +1471,7 @@ UINT xf_AppUpdateWindowFromSurface(xfContext* xfc, gdiGfxSurface* surface)
WINPR_ASSERT(xfc);
WINPR_ASSERT(surface);
- xfAppWindow* appWindow = xf_rail_get_window(xfc, surface->windowId);
+ xfAppWindow* appWindow = xf_rail_get_window(xfc, surface->windowId, FALSE);
if (!appWindow)
{
WLog_VRB(TAG, "Failed to find a window for id=0x%08" PRIx64, surface->windowId);
@@ -1482,7 +1482,6 @@ UINT xf_AppUpdateWindowFromSurface(xfContext* xfc, gdiGfxSurface* surface)
UINT32 nrects = 0;
const RECTANGLE_16* rects = region16_rects(&surface->invalidRegion, &nrects);
- xf_lock_x11(xfc);
if (swGdi)
{
if (appWindow->surfaceId != surface->surfaceId)
@@ -1537,9 +1536,9 @@ UINT xf_AppUpdateWindowFromSurface(xfContext* xfc, gdiGfxSurface* surface)
rc = CHANNEL_RC_OK;
fail:
- xf_rail_return_window(appWindow);
+ xf_rail_return_window(appWindow, FALSE);
XFlush(xfc->display);
- xf_unlock_x11(xfc);
+
return rc;
}
@@ -1567,7 +1566,7 @@ void xf_XSetTransientForHint(xfContext* xfc, xfAppWindow* window)
if (window->ownerWindowId == 0)
return;
- xfAppWindow* parent = xf_rail_get_window(xfc, window->ownerWindowId);
+ xfAppWindow* parent = xf_rail_get_window(xfc, window->ownerWindowId, TRUE);
if (!parent)
return;
@@ -1578,7 +1577,7 @@ void xf_XSetTransientForHint(xfContext* xfc, xfAppWindow* window)
WLog_WARN(TAG, "XSetTransientForHint [%d]{%s}", rc,
x11_error_to_string(xfc, rc, buffer, sizeof(buffer)));
}
- xf_rail_return_window(parent);
+ xf_rail_return_window(parent, TRUE);
}
void xfAppWindowsLockFrom(xfContext* xfc, const char* file, const char* fkt, size_t line)
@@ -1591,6 +1590,7 @@ void xfAppWindowsLockFrom(xfContext* xfc, const char* file, const char* fkt, siz
WLog_PrintMessage(xfc->log, WLOG_MESSAGE_TEXT, level, line, file, fkt, "[rails] locking [%s]", fkt);
#endif
+ xf_lock_x11(xfc);
HashTable_Lock(xfc->railWindows);
#if defined(WITH_VERBOSE_WINPR_ASSERT)
@@ -1613,4 +1613,5 @@ void xfAppWindowsUnlockFrom(xfContext* xfc, const char* file, const char* fkt, s
#endif
HashTable_Unlock(xfc->railWindows);
+ xf_unlock_x11(xfc);
}
--
2.54.0

View File

@ -0,0 +1,30 @@
From d9bf1e5fca30a89603accff808b2452750333cb6 Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Thu, 30 Apr 2026 15:03:21 +0200
Subject: [PATCH] [codec,planar] fix bounds checks
---
libfreerdp/codec/planar.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c
index 58efbc627..0c4129fb1 100644
--- a/libfreerdp/codec/planar.c
+++ b/libfreerdp/codec/planar.c
@@ -958,12 +958,12 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
return FALSE;
}
- if ((nXDst + nSrcWidth) * bpp > nDstStep)
+ if ((nXDst + nSrcWidth) * bpp > nTempStep)
{
WLog_ERR(TAG,
"planar plane destination (X %" PRIu32 " + width %" PRIu32
") * bpp %" PRIu32 " exceeds stride %" PRIu32,
- nXDst, nSrcWidth, bpp, nDstStep);
+ nXDst, nSrcWidth, bpp, nTempStep);
return FALSE;
}
--
2.52.0

View File

@ -0,0 +1,37 @@
From 60ed73552ffdb499dddf06c119be9437da7f9261 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Sun, 29 Dec 2024 10:22:56 +0100
Subject: [PATCH] [core,connection] print SSL warnings after init
---
libfreerdp/core/connection.c | 1 +
libfreerdp/core/freerdp.c | 1 -
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c
index 979ccdf60..001b56944 100644
--- a/libfreerdp/core/connection.c
+++ b/libfreerdp/core/connection.c
@@ -319,6 +319,7 @@ BOOL rdp_client_connect(rdpRdp* rdp)
flags |= WINPR_SSL_INIT_ENABLE_FIPS;
winpr_InitializeSSL(flags);
+ rdp_log_build_warnings(rdp);
/* FIPS Mode forces the following and overrides the following(by happening later */
/* in the command line processing): */
diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c
index 94dad20a0..715da31d9 100644
--- a/libfreerdp/core/freerdp.c
+++ b/libfreerdp/core/freerdp.c
@@ -802,7 +802,6 @@ BOOL freerdp_context_new_ex(freerdp* instance, rdpSettings* settings)
if (!rdp)
goto fail;
- rdp_log_build_warnings(rdp);
context->rdp = rdp;
context->pubSub = rdp->pubSub;
--
2.51.1

View File

@ -0,0 +1,43 @@
From 5a856bef31bdbecbaf69bd671d23add9779debd9 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 11:37:16 +0100
Subject: [PATCH] [core,tcp] Don't ignore connect errors
Backport of commit 0bdd8da0993231216a7bb4d5e6e33e47d817a944.
Co-Authored-By: Claude <noreply@anthropic.com>
---
libfreerdp/core/tcp.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c
index 8e7ee20bd..6edfb6d71 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -857,12 +857,19 @@ static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct
if (WAIT_OBJECT_0 != status)
goto fail;
- const SSIZE_T res = recv(sockfd, NULL, 0, 0);
-
- if (res == 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

View File

@ -0,0 +1,102 @@
From 4864954a384e4028298e95a19795505f688b21ae Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 11:38:11 +0100
Subject: [PATCH] [core,tcp] Fix PreferIPv6OverIPv4 fallback to IPv4 addresses
Backport of commit 0bdd8da0993231216a7bb4d5e6e33e47d817a944.
Co-Authored-By: Claude <noreply@anthropic.com>
---
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 6edfb6d71..83cc9af1e 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -1081,6 +1081,53 @@ int freerdp_tcp_connect(rdpContext* context, const char* hostname, int port, DWO
return transport_tcp_connect(context->rdp->transport, hostname, port, timeout);
}
+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)
{
@@ -1091,14 +1138,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;
- }
-
/* We want to force IPvX, abort if not detected */
const UINT32 IPvX = freerdp_settings_get_uint32(context->settings, FreeRDP_ForceIPvX);
switch (IPvX)
@@ -1237,9 +1276,11 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
/* By default we take the first returned entry.
*
- * 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

View File

@ -0,0 +1,76 @@
From e4adf227177fd807f47f8621a5e2568748619a23 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 11:34:53 +0100
Subject: [PATCH] [core,tcp] Try next DNS entry on connect failure
Backport of commit bd67348eb3380a66b544835346191bd2138a5ba4.
Co-Authored-By: Claude <noreply@anthropic.com>
---
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 53e3a412f..8e7ee20bd 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -1241,34 +1241,37 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
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 lrc = get_next_addrinfo(context, addr->ai_next, &addr,
FREERDP_ERROR_CONNECT_FAILED);
if (lrc < 0)
+ {
+ freeaddrinfo(result);
+ freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
+ WLog_ERR(TAG, "failed to connect to %s", hostname);
return lrc;
+ }
}
} 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

View File

@ -0,0 +1,39 @@
From 0a660bf3b3cf2660a4fa15bd37d8b8b3d03fbfef Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 14 Jan 2026 12:55:42 +0100
Subject: [PATCH] [core,tcp] fix double free in get_next_addrinfo
Backport of commit 48197426444b7b3587874b5eae175af1113beab8.
Co-Authored-By: Claude <noreply@anthropic.com>
---
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 83cc9af1e..a3e12d14b 100644
--- a/libfreerdp/core/tcp.c
+++ b/libfreerdp/core/tcp.c
@@ -1164,7 +1164,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;
}
@@ -1284,7 +1284,10 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
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

View File

@ -30,7 +30,7 @@
Name: freerdp
Epoch: 2
Version: 3.10.3
Release: 5%{?dist}.8
Release: 12%{?dist}.6
Summary: Free implementation of the Remote Desktop Protocol (RDP)
# The effective license is Apache-2.0 but:
@ -56,6 +56,15 @@ Patch2: Use-default-threadpool.patch
Patch3: Default-minimum-thread-count.patch
Patch4: Limit-minimum-threadpool-size.patch
# https://issues.redhat.com/browse/RHEL-73724
Patch: core-connection-print-SSL-warnings-after-init.patch
# https://issues.redhat.com/browse/RHEL-140099
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
@ -227,6 +236,40 @@ Patch: codec-clear-update-clear_glyph_entry-count-after-alloc.patch
# https://github.com/FreeRDP/FreeRDP/commit/a48dbde2c8a5b8b70a9d1c045d969a71afd6284c
Patch: cache-persist-use-winpr_aligned_calloc.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
# CVE-2026-40033
# https://github.com/FreeRDP/FreeRDP/commit/f951d8677ce6d34d9778b951f73b3072b01853cb
Patch: gdi-gfx-fix-bounds-checks.patch
# CVE-2026-44421
# https://github.com/FreeRDP/FreeRDP/commit/b877c8c0fef1b5ccda29ccd5a1a58696486545ed
Patch: gdi-gfx-ensure-the-cache-element-can-hold-the-data.patch
# CVE-2026-45700
# https://github.com/FreeRDP/FreeRDP/commit/4a065a941ae134a0433d1497c03b3c3eb91b9f85
Patch: codec-planar-fix-bounds-checks.patch
# CVE-2026-44420
# https://github.com/FreeRDP/FreeRDP/commit/0fba1f4dbff7585c9c99873d7c07d7dac46510c3
# https://github.com/FreeRDP/FreeRDP/commit/d00dc5d3be369fb400344eb12e6882db2ee184f0
Patch: channels-cliprdr-validate-capabilitySetLength-in-server-caps.patch
Patch: channels-cliprdr-abort-on-duplicate-caps.patch
# CVE-2026-44422
# https://github.com/FreeRDP/FreeRDP/commit/668fcb49d4856fad28f685db54a572af2a284b50
# https://github.com/FreeRDP/FreeRDP/commit/ae03a9ff981ce7be1ab09dba2cd319d54984f910
Patch: channels-rdpear-fix-ndr_read-checks.patch
Patch: channels-rdpear-disable-ndr-pointer-aliasing.patch
BuildRequires: gcc
BuildRequires: gcc-c++
BuildRequires: alsa-lib-devel
@ -398,6 +441,7 @@ find . -name "*.c" -exec chmod 664 {} \;
-DWITH_TIMEZONE_COMPILED=OFF \
-DWITH_TIMEZONE_FROM_FILE=ON \
-DWITH_URIPARSER=%{?_with_uriparser:ON}%{?!_with_uriparser:OFF} \
-DWITH_VERBOSE_WINPR_ASSERT=OFF \
-DWITH_VIDEO_FFMPEG=%{?_with_ffmpeg:ON}%{?!_with_ffmpeg:OFF} \
-DWITH_WAYLAND=ON \
-DWITH_WEBVIEW=%{?_with_webview:ON}%{?!_with_webview:OFF} \
@ -549,7 +593,16 @@ find %{buildroot} -name "*.a" -delete
%{_libdir}/pkgconfig/winpr-tools3.pc
%changelog
* Wed Apr 29 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-5.8
* Mon Jun 29 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-12.6
- Backport several CVE fixes (CVE-2026-40033, CVE-2026-44420, CVE-2026-44421,
CVE-2026-44422, CVE-2026-45700)
Resolves: RHEL-186978, RHEL-186967, RHEL-186958, RHEL-186950, RHEL-186093
* Tue May 05 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-12.5
- Lock appWindow to fix use-after-free in RAIL mode (CVE-2026-25952)
Resolves: RHEL-159848
* Wed Apr 29 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-12.4
- Fix double free in xf_rail_window_common cleanup (CVE-2026-26986)
- Fix clipboard use-after-free during auto-reconnect (CVE-2026-25997)
- Fix heap-buffer-overflow in bitmap_cache_put (CVE-2026-29775)
@ -559,37 +612,48 @@ find %{buildroot} -name "*.a" -delete
- Update PERSISTENT_CACHE_ENTRY::size after realloc (CVE-2026-33987)
- Update CLEAR_GLYPH_ENTRY::count after alloc (CVE-2026-33985)
- Use winpr_aligned_calloc in persistent cache (CVE-2026-33982)
Resolves: RHEL-159803, RHEL-159659, RHEL-161033, RHEL-161468
Resolves: RHEL-161504, RHEL-161071, RHEL-163653, RHEL-167791, RHEL-162930
Resolves: RHEL-159804, RHEL-159660, RHEL-161034, RHEL-161469
Resolves: RHEL-161505, RHEL-161072, RHEL-163654, RHEL-168462, RHEL-162931
* Fri Apr 10 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-5.6
* Fri Apr 10 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-12.2
- Update CLEAR_VBAR_ENTRY size after alloc (CVE-2026-33984)
- Fail progressive_rfx_quant_sub on invalid values (CVE-2026-33983)
Resolves: RHEL-162946, RHEL-162962
Resolves: RHEL-162947, RHEL-162963
* Tue Mar 31 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-5.5
* Thu Apr 09 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-12.1
- Rebuilt for errata
Resolves: RHEL-155980
* Tue Mar 31 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-12
- Fix use of nsc_process_message
- Increase timeout for TestSynchCritical
Resolves: RHEL-155979
Resolves: RHEL-155980
* Fri Mar 27 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-5.4
* Fri Mar 27 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-11
- Backport several CVE fixes
Resolves: RHEL-147948, RHEL-147949, RHEL-147956, RHEL-147963, RHEL-147964
Resolves: RHEL-147972, RHEL-147979, RHEL-147984, RHEL-147985, RHEL-148898
Resolves: RHEL-148978, RHEL-148984, RHEL-149051, RHEL-155979
Resolves: RHEL-147950, RHEL-147951, RHEL-147966, RHEL-147967, RHEL-147971
Resolves: RHEL-147997, RHEL-147998, RHEL-148006, RHEL-148007, RHEL-148900
Resolves: RHEL-148986, RHEL-148989, RHEL-149053, RHEL-155980
* Wed Mar 25 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-5.3
* Wed Mar 25 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-10
- Backport several CVE fixes
Resolves: RHEL-151975, RHEL-152202
Resolves: RHEL-151976, RHEL-152203
* Tue Feb 17 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-5.2
* Tue Feb 17 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-9
- Backport several CVE fixes
Resolves: RHEL-147912, RHEL-148815, RHEL-148859, RHEL-148892, RHEL-148973
Resolves: RHEL-147913, RHEL-148817, RHEL-148861, RHEL-148977, RHEL-148894
* Tue Jan 27 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-5.1
* Tue Jan 27 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-8
- Backport several CVE fixes
Resolves: RHEL-142413, RHEL-142397, RHEL-142381, RHEL-142365, RHEL-142349
Resolves: RHEL-142333, RHEL-142317
Resolves: RHEL-142414, RHEL-142398, RHEL-142382, RHEL-142366, RHEL-142350
Resolves: RHEL-142334, RHEL-142318
* Fri Jan 16 2026 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-7
- Try next DNS entry on connect failure
Resolves: RHEL-140099
* Tue Dec 16 2025 Ondrej Holy <oholy@redhat.com> - 2:3.10.3-6
- Fix broken SSL checks and disable runtime checks (RHEL-73724)
* Tue Sep 30 2025 Marek Kasik <mkasik@redhat.com> - 2:3.10.3-5
- Silence abidiff

View File

@ -0,0 +1,28 @@
From 45898fbb38d755d2c3211ed6064e13ee9815f24c Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Thu, 30 Apr 2026 10:49:01 +0200
Subject: [PATCH] [gdi,gfx] ensure the cache element can hold the data
For future color format compatibility ensure that the bytes per
pixel are MAX(4, FreeRDPGetBytesPerPixel(format))
---
libfreerdp/gdi/gfx.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c
index d22405445..7ac597d92 100644
--- a/libfreerdp/gdi/gfx.c
+++ b/libfreerdp/gdi/gfx.c
@@ -1414,7 +1414,9 @@ static gdiGfxCacheEntry* gdi_GfxCacheEntryNew(UINT64 cacheKey, UINT32 width, UIN
cacheEntry->width = width;
cacheEntry->height = height;
cacheEntry->format = format;
- cacheEntry->scanline = gfx_align_scanline(cacheEntry->width * 4, 16);
+
+ const UINT32 bpp = MAX(4, FreeRDPGetBytesPerPixel(format));
+ cacheEntry->scanline = gfx_align_scanline(cacheEntry->width * bpp, 16);
if ((cacheEntry->width > 0) && (cacheEntry->height > 0))
{
--
2.52.0

View File

@ -0,0 +1,31 @@
From f2b44427946bf42128609b66b4f6623c9b58a482 Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Thu, 30 Apr 2026 10:04:24 +0200
Subject: [PATCH] [gdi,gfx] fix bounds checks
---
libfreerdp/gdi/gfx.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c
index 3cbea681d..d22405445 100644
--- a/libfreerdp/gdi/gfx.c
+++ b/libfreerdp/gdi/gfx.c
@@ -1519,10 +1519,12 @@ static UINT gdi_CacheToSurface(RdpgfxClientContext* context,
if (!is_rect_valid(&rect, surface->width, surface->height))
goto fail;
+ const UINT32 w = rect.right - rect.left;
+ const UINT32 h = rect.bottom - rect.top;
if (!freerdp_image_copy_no_overlap(surface->data, surface->format, surface->scanline,
- destPt->x, destPt->y, cacheEntry->width,
- cacheEntry->height, cacheEntry->data, cacheEntry->format,
- cacheEntry->scanline, 0, 0, NULL, FREERDP_FLIP_NONE))
+ destPt->x, destPt->y, w, h, cacheEntry->data,
+ cacheEntry->format, cacheEntry->scanline, 0, 0, NULL,
+ FREERDP_FLIP_NONE))
goto fail;
invalidRect = rect;
--
2.52.0