File freerdp-CVE-2026-24684-2.patch of Package freerdp.42840

From afa6851dc80835d3101e40fcef51b6c5c0f43ea5 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Wed, 28 Jan 2026 09:31:06 +0100
Subject: [PATCH] [channel,rdpsnd] only clean up thread before free

rdpsnd channel usually has multiple instances (static, dynamic, ...) so
ensure only to terminate the handler thread when the channel is actually
closed for good.
---
 channels/rdpsnd/client/rdpsnd_main.c | 43 ++++++++++++++++------------
 1 file changed, 25 insertions(+), 18 deletions(-)

diff -urp FreeRDP-2.4.0.orig/channels/rdpsnd/client/rdpsnd_main.c FreeRDP-2.4.0/channels/rdpsnd/client/rdpsnd_main.c
--- FreeRDP-2.4.0.orig/channels/rdpsnd/client/rdpsnd_main.c	2026-02-18 19:52:52.163351599 -0600
+++ FreeRDP-2.4.0/channels/rdpsnd/client/rdpsnd_main.c	2026-02-18 21:52:42.599918112 -0600
@@ -37,6 +37,7 @@
 #include <errno.h>
 
 #include <winpr/crt.h>
+#include <winpr/assert.h>
 #include <winpr/wlog.h>
 #include <winpr/stream.h>
 #include <winpr/cmdline.h>
@@ -126,8 +127,11 @@ struct rdpsnd_plugin
 	HANDLE thread;
 	wMessageQueue* queue;
 	BOOL initialized;
+	size_t references;
 };
 
+static DWORD WINAPI play_thread(LPVOID arg);
+
 static const char* rdpsnd_is_dyn_str(BOOL dynamic)
 {
 	if (dynamic)
@@ -1231,6 +1235,25 @@ static void rdpsnd_terminate_thread(rdps
 	rdpsnd->queue = NULL;
 }
 
+static void cleanup_internals(rdpsndPlugin* rdpsnd)
+{
+	if (!rdpsnd)
+		return;
+
+	if (rdpsnd->pool)
+		StreamPool_Return(rdpsnd->pool, rdpsnd->data_in);
+
+	audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
+	audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
+
+	rdpsnd->NumberOfClientFormats = 0;
+	rdpsnd->ClientFormats = NULL;
+	rdpsnd->NumberOfServerFormats = 0;
+	rdpsnd->ServerFormats = NULL;
+
+	rdpsnd->data_in = NULL;
+}
+
 /**
  * Function description
  *
@@ -1256,17 +1279,7 @@ static UINT rdpsnd_virtual_channel_event
 		return error;
 	}
 
-	rdpsnd->OpenHandle = 0;
-	freerdp_dsp_context_free(rdpsnd->dsp_context);
-	StreamPool_Return(rdpsnd->pool, rdpsnd->data_in);
-	StreamPool_Free(rdpsnd->pool);
-
-	audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
-	rdpsnd->NumberOfClientFormats = 0;
-	rdpsnd->ClientFormats = NULL;
-	audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
-	rdpsnd->NumberOfServerFormats = 0;
-	rdpsnd->ServerFormats = NULL;
+	cleanup_internals(rdpsnd);
 
 	if (rdpsnd->device)
 	{
@@ -1283,6 +1296,64 @@ static void _queue_free(void* obj)
 	Stream_Release(s);
 }
 
+static void free_internals(rdpsndPlugin* rdpsnd)
+{
+	if (!rdpsnd)
+		return;
+
+	if (rdpsnd->references > 0)
+		rdpsnd->references--;
+
+	if (rdpsnd->references > 0)
+		return;
+
+	rdpsnd_terminate_thread(rdpsnd);
+	freerdp_dsp_context_free(rdpsnd->dsp_context);
+	StreamPool_Free(rdpsnd->pool);
+	rdpsnd->pool = NULL;
+	rdpsnd->dsp_context = NULL;
+}
+
+static BOOL allocate_internals(rdpsndPlugin* rdpsnd)
+{
+	WINPR_ASSERT(rdpsnd);
+
+	if (!rdpsnd->pool)
+	{
+		rdpsnd->pool = StreamPool_New(TRUE, 4096);
+		if (!rdpsnd->pool)
+			return FALSE;
+	}
+
+	if (!rdpsnd->dsp_context)
+	{
+		rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE);
+		if (!rdpsnd->dsp_context)
+			return FALSE;
+	}
+
+	if (!rdpsnd->queue)
+	{
+		wObject obj = { 0 };
+
+		obj.fnObjectFree = _queue_free;
+		rdpsnd->queue = MessageQueue_New(&obj);
+		if (!rdpsnd->queue)
+			return CHANNEL_RC_NO_MEMORY;
+	}
+
+	if (!rdpsnd->thread)
+	{
+		rdpsnd->thread = CreateThread(NULL, 0, play_thread, rdpsnd, 0, NULL);
+		if (!rdpsnd->thread)
+			return CHANNEL_RC_INITIALIZATION_ERROR;
+	}
+
+	rdpsnd->references++;
+
+	return TRUE;
+}
+
 static DWORD WINAPI play_thread(LPVOID arg)
 {
 	UINT error = CHANNEL_RC_OK;
@@ -1318,19 +1389,12 @@ static DWORD WINAPI play_thread(LPVOID a
 
 static UINT rdpsnd_virtual_channel_event_initialized(rdpsndPlugin* rdpsnd)
 {
-	wObject obj = { 0 };
-
 	if (!rdpsnd)
 		return ERROR_INVALID_PARAMETER;
 
-	obj.fnObjectFree = _queue_free;
-	rdpsnd->queue = MessageQueue_New(&obj);
-	if (!rdpsnd->queue)
+	if (!allocate_internals(rdpsnd))
 		return CHANNEL_RC_NO_MEMORY;
 
-	rdpsnd->thread = CreateThread(NULL, 0, play_thread, rdpsnd, 0, NULL);
-	if (!rdpsnd->thread)
-		return CHANNEL_RC_INITIALIZATION_ERROR;
 	return CHANNEL_RC_OK;
 }
 
@@ -1338,7 +1402,7 @@ static void rdpsnd_virtual_channel_event
 {
 	if (rdpsnd)
 	{
-		rdpsnd_terminate_thread(rdpsnd);
+		free_internals(rdpsnd);
 
 		audio_formats_free(rdpsnd->fixed_format, 1);
 		free(rdpsnd->subsystem);
@@ -1462,6 +1526,23 @@ BOOL VCAPITYPE rdpsnd_VirtualChannelEntr
 		return FALSE;
 	}
 
+	if (!rdpsnd->queue)
+	{
+		wObject obj = { 0 };
+
+		obj.fnObjectFree = _queue_free;
+		rdpsnd->queue = MessageQueue_New(&obj);
+		if (!rdpsnd->queue)
+			return CHANNEL_RC_NO_MEMORY;
+	}
+
+	if (!rdpsnd->thread)
+	{
+		rdpsnd->thread = CreateThread(NULL, 0, play_thread, rdpsnd, 0, NULL);
+		if (!rdpsnd->thread)
+			return CHANNEL_RC_INITIALIZATION_ERROR;
+	}
+
 	return TRUE;
 }
 
@@ -1519,16 +1600,11 @@ static UINT rdpsnd_on_close(IWTSVirtualC
 
 	if (rdpsnd->device)
 		IFCALL(rdpsnd->device->Close, rdpsnd->device);
-	freerdp_dsp_context_free(rdpsnd->dsp_context);
-	StreamPool_Return(rdpsnd->pool, rdpsnd->data_in);
-	StreamPool_Free(rdpsnd->pool);
 
-	audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
-	rdpsnd->NumberOfClientFormats = 0;
-	rdpsnd->ClientFormats = NULL;
-	audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
-	rdpsnd->NumberOfServerFormats = 0;
-	rdpsnd->ServerFormats = NULL;
+	cleanup_internals(rdpsnd);
+
+	free_internals(rdpsnd);
+
 	if (rdpsnd->device)
 	{
 		IFCALL(rdpsnd->device->Free, rdpsnd->device);
openSUSE Build Service is sponsored by