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);
 	}
openSUSE Build Service is sponsored by