File freerdp-CVE-2026-24683.patch of Package freerdp2
From d9ca272dce7a776ab475e9b1a8e8c3d2968c8486 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Mon, 26 Jan 2026 12:08:48 +0100
Subject: [PATCH] [channels,ainput] lock context when updating listener
---
channels/ainput/client/ainput_main.c | 36 ++++++++++++++++++++--------
1 file changed, 26 insertions(+), 10 deletions(-)
diff -urp freerdp-2.11.7.orig/channels/ainput/client/ainput_main.c freerdp-2.11.7/channels/ainput/client/ainput_main.c
--- freerdp-2.11.7.orig/channels/ainput/client/ainput_main.c 2024-04-22 04:26:59.000000000 -0500
+++ freerdp-2.11.7/channels/ainput/client/ainput_main.c 2026-02-18 16:06:17.371535339 -0600
@@ -69,6 +69,7 @@ struct AINPUT_PLUGIN_
UINT32 MajorVersion;
UINT32 MinorVersion;
BOOL initialized;
+ CRITICAL_SECTION lock;
};
/**
@@ -109,10 +110,7 @@ static UINT ainput_on_data_received(IWTS
static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, INT32 x, INT32 y)
{
- AINPUT_PLUGIN* ainput;
- AINPUT_CHANNEL_CALLBACK* callback;
BYTE buffer[32] = { 0 };
- UINT64 time;
wStream sbuffer = { 0 };
wStream* s = &sbuffer;
@@ -121,8 +119,8 @@ static UINT ainput_send_input_event(AInp
WINPR_ASSERT(s);
WINPR_ASSERT(context);
- time = GetTickCount64();
- ainput = (AINPUT_PLUGIN*)context->handle;
+ const UINT64 time = GetTickCount64();
+ AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)context->handle;
WINPR_ASSERT(ainput);
WINPR_ASSERT(ainput->listener_callback);
@@ -132,8 +130,6 @@ static UINT ainput_send_input_event(AInp
ainput->MajorVersion, ainput->MinorVersion);
return CHANNEL_RC_UNSUPPORTED_VERSION;
}
- callback = ainput->listener_callback->channel_callback;
- WINPR_ASSERT(callback);
{
char buffer[128] = { 0 };
@@ -152,10 +148,15 @@ static UINT ainput_send_input_event(AInp
Stream_SealLength(s);
/* ainput back what we have received. AINPUT does not have any message IDs. */
+ EnterCriticalSection(&ainput->lock);
+ AINPUT_CHANNEL_CALLBACK* callback;
+ WINPR_ASSERT(callback);
WINPR_ASSERT(callback->channel);
WINPR_ASSERT(callback->channel->Write);
- return callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s),
- NULL);
+ const UINT rc = callback->channel->Write(callback->channel, (ULONG)Stream_Length(s),
+ Stream_Buffer(s), NULL);
+ LeaveCriticalSection(&ainput->lock);
+ return rc;
}
/**
@@ -167,8 +168,16 @@ static UINT ainput_on_close(IWTSVirtualC
{
AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback;
- free(callback);
+ if (callback)
+ {
+ AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)callback->plugin;
+ WINPR_ASSERT(ainput);
+ /* Lock here to ensure that no ainput_send_input_event is in progress. */
+ EnterCriticalSection(&ainput->lock);
+ free(callback);
+ LeaveCriticalSection(&ainput->lock);
+ }
return CHANNEL_RC_OK;
}
@@ -255,6 +264,8 @@ static UINT ainput_plugin_initialize(IWT
static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin)
{
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
+ WINPR_ASSERT(ainput);
+
if (ainput && ainput->listener_callback)
{
IWTSVirtualChannelManager* mgr = ainput->listener_callback->channel_mgr;
@@ -266,6 +277,7 @@ static UINT ainput_plugin_terminated(IWT
free(ainput->listener_callback);
free(ainput->iface.pInterface);
}
+ DeleteCriticalSection(&ainput->lock);
free(ainput);
return CHANNEL_RC_OK;
@@ -306,7 +318,11 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINT
context->handle = (void*)ainput;
context->AInputSendInputEvent = ainput_send_input_event;
+ InitializeCriticalSection(&ainput->lock);
+
+ EnterCriticalSection(&ainput->lock);
ainput->iface.pInterface = (void*)context;
+ LeaveCriticalSection(&ainput->lock);
status = pEntryPoints->RegisterPlugin(pEntryPoints, AINPUT_CHANNEL_NAME, &ainput->iface);
}