From 118afc0b954ba9d5632b7836ad24e454555ed113 Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Tue, 17 Feb 2026 12:05:42 +0100
Subject: [PATCH] [allocations] fix growth of preallocated buffers

* Replace * 2 with * sizeof(WCHAR) for string usages
* Grow streams and other buffers reasonably, e.g. add 128 elements per
  try and check for possible overflows
* Add constant postfix to force them to 64bit
---
 channels/drive/client/drive_file.c            |  2 +-
 channels/remdesk/common/remdesk_common.c      |  2 +-
 channels/remdesk/server/remdesk_main.c        |  4 +-
 channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c     |  4 +-
 channels/tsmf/client/tsmf_media.c             |  2 +-
 .../urbdrc/client/libusb/libusb_udevice.c     |  4 +-
 .../freeRDPCore/src/main/cpp/android_event.c  | 14 +++-
 client/Windows/wf_cliprdr.c                   | 11 ++-
 client/X11/xf_event.c                         |  6 +-
 libfreerdp/core/gcc.c                         |  3 +-
 libfreerdp/core/orders.c                      |  2 +-
 libfreerdp/core/proxy.c                       |  2 +-
 libfreerdp/crypto/base64.c                    |  2 +-
 winpr/libwinpr/clipboard/synthetic_file.c     |  2 +-
 winpr/libwinpr/crt/buffer.c                   |  2 +-
 winpr/libwinpr/environment/environment.c      | 77 ++++++++++---------
 winpr/libwinpr/file/file.c                    |  2 +-
 winpr/libwinpr/ncrypt/ncrypt.c                |  4 +-
 winpr/libwinpr/ncrypt/ncrypt_pkcs11.c         |  7 +-
 .../libwinpr/path/include/PathAllocCombine.h  |  6 +-
 winpr/libwinpr/sspi/NTLM/ntlm_message.c       |  4 +-
 winpr/libwinpr/utils/collections/BufferPool.c | 15 +++-
 .../libwinpr/utils/collections/MessageQueue.c | 19 +++--
 winpr/libwinpr/utils/collections/ObjectPool.c | 15 ++--
 winpr/libwinpr/utils/collections/PubSub.c     | 16 ++--
 winpr/libwinpr/utils/collections/Stack.c      | 10 ++-
 winpr/libwinpr/utils/stream.c                 | 15 ++--
 winpr/tools/makecert/makecert.c               |  5 +-
 28 files changed, 153 insertions(+), 104 deletions(-)

Index: freerdp-2.11.7/channels/drive/client/drive_file.c
===================================================================
--- freerdp-2.11.7.orig/channels/drive/client/drive_file.c
+++ freerdp-2.11.7/channels/drive/client/drive_file.c
@@ -808,7 +808,7 @@ BOOL drive_file_query_directory(DRIVE_FI
 	else if (!FindNextFileW(file->find_handle, &file->find_data))
 		goto out_fail;
 
-	length = _wcslen(file->find_data.cFileName) * 2;
+	length = _wcslen(file->find_data.cFileName) * sizeof(WCHAR);
 
 	switch (FsInformationClass)
 	{
Index: freerdp-2.11.7/channels/remdesk/server/remdesk_main.c
===================================================================
--- freerdp-2.11.7.orig/channels/remdesk/server/remdesk_main.c
+++ freerdp-2.11.7/channels/remdesk/server/remdesk_main.c
@@ -294,7 +294,7 @@ static UINT remdesk_recv_ctl_remote_cont
 		return ERROR_INVALID_DATA;
 
 	cchStringW++;
-	cbRaConnectionStringW = cchStringW * 2;
+	cbRaConnectionStringW = cchStringW * sizeof(WCHAR);
 	pdu.raConnectionString = NULL;
 	status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, cbRaConnectionStringW / 2,
 	                            &pdu.raConnectionString, 0, NULL, NULL);
@@ -346,7 +346,7 @@ static UINT remdesk_recv_ctl_authenticat
 		return ERROR_INVALID_DATA;
 
 	cchStringW++;
-	cbRaConnectionStringW = cchStringW * 2;
+	cbRaConnectionStringW = cchStringW * sizeof(WCHAR);
 	pStringW += cchStringW;
 	expertBlobW = pStringW;
 	cchStringW = 0;
@@ -361,7 +361,7 @@ static UINT remdesk_recv_ctl_authenticat
 		return ERROR_INVALID_DATA;
 
 	cchStringW++;
-	cbExpertBlobW = cchStringW * 2;
+	cbExpertBlobW = cchStringW * sizeof(WCHAR);
 	pdu.raConnectionString = NULL;
 	status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, cbRaConnectionStringW / 2,
 	                            &pdu.raConnectionString, 0, NULL, NULL);
Index: freerdp-2.11.7/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c
===================================================================
--- freerdp-2.11.7.orig/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c
+++ freerdp-2.11.7/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c
@@ -461,12 +461,12 @@ static BOOL tsmf_ffmpeg_decode_audio(ITS
 		if (mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE)
 		{
 			BYTE* tmp_data;
-			tmp_data = realloc(mdecoder->decoded_data, mdecoder->decoded_size_max * 2 + 16);
+			tmp_data = realloc(mdecoder->decoded_data, mdecoder->decoded_size_max * 2ull + 16ull);
 
 			if (!tmp_data)
 				return FALSE;
 
-			mdecoder->decoded_size_max = mdecoder->decoded_size_max * 2 + 16;
+			mdecoder->decoded_size_max = mdecoder->decoded_size_max * 2ull + 16ull;
 			mdecoder->decoded_data = tmp_data;
 			dst = (BYTE*)(((uintptr_t)mdecoder->decoded_data + 15) & ~0x0F);
 
Index: freerdp-2.11.7/channels/tsmf/client/tsmf_media.c
===================================================================
--- freerdp-2.11.7.orig/channels/tsmf/client/tsmf_media.c
+++ freerdp-2.11.7/channels/tsmf/client/tsmf_media.c
@@ -398,7 +398,7 @@ TSMF_PRESENTATION* tsmf_presentation_fin
 	UINT32 index;
 	UINT32 count;
 	BOOL found = FALSE;
-	char guid_str[GUID_SIZE * 2 + 1];
+	char guid_str[GUID_SIZE * 2ull + 1];
 	TSMF_PRESENTATION* presentation;
 	ArrayList_Lock(presentation_list);
 	count = ArrayList_Count(presentation_list);
Index: freerdp-2.11.7/channels/urbdrc/client/libusb/libusb_udevice.c
===================================================================
--- freerdp-2.11.7.orig/channels/urbdrc/client/libusb/libusb_udevice.c
+++ freerdp-2.11.7/channels/urbdrc/client/libusb/libusb_udevice.c
@@ -889,10 +889,10 @@ static UINT32 libusb_udev_control_query_
 				 * So also check the string length returned as server side does
 				 * not honor strings with multi '\0' characters well.
 				 */
-				const size_t rchar = _wcsnlen((WCHAR*)&data[2], sizeof(data) / 2);
+				const size_t rchar = _wcsnlen((WCHAR*)&data[2], sizeof(data) / sizeof(WCHAR));
 				len = MIN((BYTE)ret, slen);
 				len = MIN(len, inSize);
-				len = MIN(len, rchar * 2 + sizeof(WCHAR));
+				len = MIN(len, rchar * sizeof(WCHAR) + sizeof(WCHAR));
 				memcpy(Buffer, &data[2], len);
 
 				/* Just as above, the returned WCHAR string should be '\0'
Index: freerdp-2.11.7/client/Windows/wf_cliprdr.c
===================================================================
--- freerdp-2.11.7.orig/client/Windows/wf_cliprdr.c
+++ freerdp-2.11.7/client/Windows/wf_cliprdr.c
@@ -1140,10 +1140,13 @@ static void map_ensure_capacity(wfClipbo
 
 	if (clipboard->map_size >= clipboard->map_capacity)
 	{
-		size_t new_size;
-		formatMapping* new_map;
-		new_size = clipboard->map_capacity * 2;
-		new_map =
+		size_t new_size = clipboard->map_capacity;
+		do
+		{
+			WINPR_ASSERT(new_size <= SIZE_MAX - 128ull);
+			new_size += 128ull;
+		} while (new_size <= clipboard->map_size);
+		formatMapping* new_map =
 		    (formatMapping*)realloc(clipboard->format_mappings, sizeof(formatMapping) * new_size);
 
 		if (!new_map)
Index: freerdp-2.11.7/client/X11/xf_event.c
===================================================================
--- freerdp-2.11.7.orig/client/X11/xf_event.c
+++ freerdp-2.11.7/client/X11/xf_event.c
@@ -743,9 +743,8 @@ static BOOL xf_event_ConfigureNotify(xfC
 
 		if (settings->DynamicResolutionUpdate)
 		{
-			int alignedWidth, alignedHeight;
-			alignedWidth = (xfc->window->width / 2) * 2;
-			alignedHeight = (xfc->window->height / 2) * 2;
+			const int alignedWidth = (xfc->window->width / 2) * 2;
+			const int alignedHeight = (xfc->window->height / 2) * 2;
 			/* ask the server to resize using the display channel */
 			xf_disp_handle_configureNotify(xfc, alignedWidth, alignedHeight);
 		}
Index: freerdp-2.11.7/libfreerdp/core/gcc.c
===================================================================
--- freerdp-2.11.7.orig/libfreerdp/core/gcc.c
+++ freerdp-2.11.7/libfreerdp/core/gcc.c
@@ -1645,7 +1645,8 @@ BOOL gcc_read_server_network_data(wStrea
 BOOL gcc_write_server_network_data(wStream* s, rdpMcs* mcs)
 {
 	UINT32 i;
-	int payloadLen = 8 + mcs->channelCount * 2 + (mcs->channelCount % 2 == 1 ? 2 : 0);
+	const size_t payloadLen =
+	    8ull + mcs->channelCount * 2ull + (mcs->channelCount % 2 == 1 ? 2ull : 0ull);
 
 	if (!Stream_EnsureRemainingCapacity(s, payloadLen + 4))
 		return FALSE;
Index: freerdp-2.11.7/libfreerdp/core/orders.c
===================================================================
--- freerdp-2.11.7.orig/libfreerdp/core/orders.c
+++ freerdp-2.11.7/libfreerdp/core/orders.c
@@ -3003,7 +3003,7 @@ int update_approximate_create_offscreen_
     const CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
 {
 	const OFFSCREEN_DELETE_LIST* deleteList = &(create_offscreen_bitmap->deleteList);
-	return 32 + deleteList->cIndices * 2;
+	return 32ull + deleteList->cIndices * 2ull;
 }
 BOOL update_write_create_offscreen_bitmap_order(
     wStream* s, const CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
Index: freerdp-2.11.7/winpr/libwinpr/crt/buffer.c
===================================================================
--- freerdp-2.11.7.orig/winpr/libwinpr/crt/buffer.c
+++ freerdp-2.11.7/winpr/libwinpr/crt/buffer.c
@@ -41,7 +41,7 @@ errno_t memmove_s(void* dest, size_t num
 
 errno_t wmemmove_s(WCHAR* dest, size_t numberOfElements, const WCHAR* src, size_t count)
 {
-	if (count * 2 > numberOfElements)
+	if (count * sizeof(WCHAR) > numberOfElements)
 		return -1;
 
 	memmove(dest, src, count * 2);
Index: freerdp-2.11.7/winpr/libwinpr/environment/environment.c
===================================================================
--- freerdp-2.11.7.orig/winpr/libwinpr/environment/environment.c
+++ freerdp-2.11.7/winpr/libwinpr/environment/environment.c
@@ -29,6 +29,11 @@
 
 #include <winpr/environment.h>
 
+#include "../log.h"
+
+#define TAG WINPR_TAG("environment")
+
+
 #ifndef _WIN32
 
 #define stricmp strcasecmp
@@ -223,32 +228,36 @@ extern char** environ;
 LPCH GetEnvironmentStringsA(VOID)
 {
 #if !defined(_UWP)
-	char* p;
 	size_t offset;
-	size_t length;
-	char** envp;
-	DWORD cchEnvironmentBlock;
-	LPCH lpszEnvironmentBlock;
 
-	offset = 0;
-	envp = environ;
+	char** envp = environ;
+	const size_t blocksize = 128;
+	size_t cchEnvironmentBlock = blocksize;
+	LPCH lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
 
-	cchEnvironmentBlock = 128;
-	lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
 	if (!lpszEnvironmentBlock)
 		return NULL;
 
 	while (*envp)
 	{
-		length = strlen(*envp);
+		const size_t length = strlen(*envp);
+		const size_t required = offset + length + 8ull;
+		if (required > UINT32_MAX)
+		{
+			WLog_ERR(TAG, "Environment block too large: %" PRIuz, required);
+			free(lpszEnvironmentBlock);
+			return NULL;
+		}
 
-		while ((offset + length + 8) > cchEnvironmentBlock)
+		if (required > cchEnvironmentBlock)
 		{
-			DWORD new_size;
-			LPCH new_blk;
+			size_t new_size = cchEnvironmentBlock;
+			do
+			{
+				new_size += blocksize;
+			} while (new_size <= required);
+			LPCH new_blk = (LPCH)realloc(lpszEnvironmentBlock, new_size * sizeof(CHAR));
 
-			new_size = cchEnvironmentBlock * 2;
-			new_blk = (LPCH)realloc(lpszEnvironmentBlock, new_size * sizeof(CHAR));
 			if (!new_blk)
 			{
 				free(lpszEnvironmentBlock);
@@ -259,12 +268,12 @@ LPCH GetEnvironmentStringsA(VOID)
 			cchEnvironmentBlock = new_size;
 		}
 
-		p = &(lpszEnvironmentBlock[offset]);
+		char* p = &(lpszEnvironmentBlock[offset]);
 
 		CopyMemory(p, *envp, length * sizeof(CHAR));
 		p[length] = '\0';
 
-		offset += (length + 1);
+		offset += (length + 1ull);
 		envp++;
 	}
 
Index: freerdp-2.11.7/winpr/libwinpr/file/file.c
===================================================================
--- freerdp-2.11.7.orig/winpr/libwinpr/file/file.c
+++ freerdp-2.11.7/winpr/libwinpr/file/file.c
@@ -1246,7 +1246,7 @@ DWORD GetFullPathNameA(LPCSTR lpFileName
 	free(lpFileNameW);
 	free(lpBufferW);
 
-	return dwStatus * 2;
+	return WINPR_ASSERTING_INT_CAST(DWORD, dwStatus * sizeof(WCHAR));
 }
 
 BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
Index: freerdp-2.11.7/winpr/libwinpr/sspi/NTLM/ntlm_message.c
===================================================================
--- freerdp-2.11.7.orig/winpr/libwinpr/sspi/NTLM/ntlm_message.c
+++ freerdp-2.11.7/winpr/libwinpr/sspi/NTLM/ntlm_message.c
@@ -1230,11 +1230,11 @@ SECURITY_STATUS ntlm_write_AuthenticateM
 	if (credentials->identity.DomainLength > 0)
 	{
 		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
-		message->DomainName.Len = (UINT16)credentials->identity.DomainLength * 2;
+		message->DomainName.Len = (UINT16)credentials->identity.DomainLength * sizeof(WCHAR);
 		message->DomainName.Buffer = (BYTE*)credentials->identity.Domain;
 	}
 
-	message->UserName.Len = (UINT16)credentials->identity.UserLength * 2;
+	message->UserName.Len = (UINT16)credentials->identity.UserLength * sizeof(WCHAR);
 	message->UserName.Buffer = (BYTE*)credentials->identity.User;
 	message->LmChallengeResponse.Len = (UINT16)context->LmChallengeResponse.cbBuffer;
 	message->LmChallengeResponse.Buffer = (BYTE*)context->LmChallengeResponse.pvBuffer;
Index: freerdp-2.11.7/winpr/libwinpr/utils/collections/BufferPool.c
===================================================================
--- freerdp-2.11.7.orig/winpr/libwinpr/utils/collections/BufferPool.c
+++ freerdp-2.11.7/winpr/libwinpr/utils/collections/BufferPool.c
@@ -68,9 +68,20 @@ static BOOL BufferPool_ShiftUsed(wBuffer
 {
 	if (count > 0)
 	{
-		if (pool->uSize + count > pool->uCapacity)
+		const SSIZE_T required = pool->uSize + count;
+		// check for overflow
+		if ((required < count) || (required < pool->uSize))
+			return FALSE;
+
+		if (required > pool->uCapacity)
 		{
-			int newUCapacity = pool->uCapacity * 2;
+			SSIZE_T newUCapacity = pool->uCapacity;
+			do
+			{
+				if (newUCapacity > SIZE_MAX - 128ull)
+					return FALSE;
+				newUCapacity += 128ull;
+			} while (newUCapacity <= required);
 			wBufferPoolItem* newUArray =
 			    (wBufferPoolItem*)realloc(pool->uArray, sizeof(wBufferPoolItem) * newUCapacity);
 			if (!newUArray)
Index: freerdp-2.11.7/winpr/libwinpr/utils/collections/ObjectPool.c
===================================================================
--- freerdp-2.11.7.orig/winpr/libwinpr/utils/collections/ObjectPool.c
+++ freerdp-2.11.7/winpr/libwinpr/utils/collections/ObjectPool.c
@@ -72,13 +72,18 @@ void ObjectPool_Return(wObjectPool* pool
 	if (pool->synchronized)
 		EnterCriticalSection(&pool->lock);
 
-	if ((pool->size + 1) >= pool->capacity)
+	WINPR_ASSERT(pool->size < SIZE_MAX);
+	const size_t required = pool->size + 1ull;
+	if (required >= pool->capacity)
 	{
-		size_t new_cap;
-		void** new_arr;
+		size_t new_cap = pool->capacity;
+		do
+		{
+			WINPR_ASSERT(new_cap <= SIZE_MAX - 128ull);
+			new_cap += 128ull;
+		} while (new_cap <= required);
 
-		new_cap = pool->capacity * 2;
-		new_arr = (void**)realloc(pool->array, sizeof(void*) * new_cap);
+        void** new_arr = (void**)realloc((void*)pool->array, sizeof(void*) * new_cap);
 		if (!new_arr)
 			goto out;
 
Index: freerdp-2.11.7/winpr/libwinpr/utils/collections/PubSub.c
===================================================================
--- freerdp-2.11.7.orig/winpr/libwinpr/utils/collections/PubSub.c
+++ freerdp-2.11.7/winpr/libwinpr/utils/collections/PubSub.c
@@ -78,13 +78,19 @@ void PubSub_AddEventTypes(wPubSub* pubSu
 	if (pubSub->synchronized)
 		PubSub_Lock(pubSub);
 
-	while (pubSub->count + count >= pubSub->size)
+	const size_t required = pubSub->count + count;
+	WINPR_ASSERT((required >= pubSub->count) && (required >= count));
+
+	if (required >= pubSub->size)
 	{
-		int new_size;
-		wEventType* new_event;
+		size_t new_size = pubSub->size;
+		do
+		{
+			WINPR_ASSERT(new_size <= SIZE_MAX - 128ull);
+			new_size += 128ull;
+		} while (new_size <= required);
 
-		new_size = pubSub->size * 2;
-		new_event = (wEventType*)realloc(pubSub->events, new_size * sizeof(wEventType));
+		wEventType* new_event = (wEventType*)realloc(pubSub->events, new_size * sizeof(wEventType));
 		if (!new_event)
 			return;
 		pubSub->size = new_size;
Index: freerdp-2.11.7/winpr/libwinpr/utils/collections/Stack.c
===================================================================
--- freerdp-2.11.7.orig/winpr/libwinpr/utils/collections/Stack.c
+++ freerdp-2.11.7/winpr/libwinpr/utils/collections/Stack.c
@@ -125,11 +125,16 @@ void Stack_Push(wStack* stack, void* obj
 	if (stack->synchronized)
 		EnterCriticalSection(&stack->lock);
 
-	if ((stack->size + 1) >= stack->capacity)
+	WINPR_ASSERT(stack->size < SIZE_MAX);
+	if ((stack->size + 1ull) >= stack->capacity)
 	{
-		int new_cap;
 		void** new_arr;
-		new_cap = stack->capacity * 2;
+		size_t new_cap = stack->capacity;
+		do
+		{
+			WINPR_ASSERT(new_cap <= SIZE_MAX - 128ull);
+			new_cap += 128ull;
+		} while (new_cap <= stack->size + 1ull);
 		new_arr = (void**)realloc(stack->array, sizeof(void*) * new_cap);
 
 		if (!new_arr)
Index: freerdp-2.11.7/winpr/libwinpr/utils/stream.c
===================================================================
--- freerdp-2.11.7.orig/winpr/libwinpr/utils/stream.c
+++ freerdp-2.11.7/winpr/libwinpr/utils/stream.c
@@ -30,20 +30,19 @@ BOOL Stream_EnsureCapacity(wStream* s, s
 {
 	if (s->capacity < size)
 	{
-		size_t position;
-		size_t old_capacity;
-		size_t new_capacity;
 		BYTE* new_buf;
 
-		old_capacity = s->capacity;
-		new_capacity = old_capacity;
+		size_t old_capacity = s->capacity;
+		size_t new_capacity = old_capacity;
 
 		do
 		{
-			new_capacity *= 2;
-		} while (new_capacity < size);
+			if (new_capacity > SIZE_MAX - 128ull)
+				return FALSE;
+			new_capacity += 128ull;
+		} while (new_capacity <= size);
 
-		position = Stream_GetPosition(s);
+		const size_t position = Stream_GetPosition(s);
 
 		if (!s->isOwner)
 		{
Index: freerdp-2.11.7/winpr/tools/makecert/makecert.c
===================================================================
--- freerdp-2.11.7.orig/winpr/tools/makecert/makecert.c
+++ freerdp-2.11.7/winpr/tools/makecert/makecert.c
@@ -77,11 +77,8 @@ static char* makecert_read_str(BIO* bio,
 
 	while (offset >= length)
 	{
-		size_t new_len;
 		char* new_str;
-		new_len = length * 2;
-		if (new_len == 0)
-			new_len = 2048;
+		size_t new_len = length + 2048ull;
 		new_str = (char*)realloc(x509_str, new_len);
 
 		if (!new_str || (new_len > INT_MAX))
