diff mbox series

[meta-oe,kirkstone,4/5] freerdp: patch CVE-2024-32460

Message ID 20260123064332.4001588-4-skandigraun@gmail.com
State New
Headers show
Series [meta-oe,kirkstone,1/5] freerdp: mark CVE-2024-32041 patched | expand

Commit Message

Gyorgy Sarvari Jan. 23, 2026, 6:43 a.m. UTC
Details: https://nvd.nist.gov/vuln/detail/CVE-2024-32460

Backport the patch that is marked to resolve this vulnerability
by the relevant Github advisory[1].

[1]: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4rr8-gr65-vqrr

Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
---
 .../freerdp/freerdp/CVE-2024-32460.patch      | 1030 +++++++++++++++++
 .../recipes-support/freerdp/freerdp_2.6.1.bb  |    1 +
 2 files changed, 1031 insertions(+)
 create mode 100644 meta-oe/recipes-support/freerdp/freerdp/CVE-2024-32460.patch
diff mbox series

Patch

diff --git a/meta-oe/recipes-support/freerdp/freerdp/CVE-2024-32460.patch b/meta-oe/recipes-support/freerdp/freerdp/CVE-2024-32460.patch
new file mode 100644
index 0000000000..356e1a99ef
--- /dev/null
+++ b/meta-oe/recipes-support/freerdp/freerdp/CVE-2024-32460.patch
@@ -0,0 +1,1030 @@ 
+From 86391660a70ac263c21a818c51528c42d01e64c5 Mon Sep 17 00:00:00 2001
+From: Armin Novak <armin.novak@thincast.com>
+Date: Wed, 17 Apr 2024 11:23:52 +0200
+Subject: [PATCH] backport from 3.5.0
+
+CVE: CVE-2024-32460
+Upstream-Status: Backport [https://github.com/FreeRDP/FreeRDP/commit/18cef378eae2b63a1a750da242f00da12b5b3881]
+Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
+---
+ libfreerdp/codec/include/bitmap.c | 119 ++++----
+ libfreerdp/codec/interleaved.c    | 448 +++++++++++++++++++++++-------
+ 2 files changed, 413 insertions(+), 154 deletions(-)
+
+diff --git a/libfreerdp/codec/include/bitmap.c b/libfreerdp/codec/include/bitmap.c
+index 38bcaa859..af8338711 100644
+--- a/libfreerdp/codec/include/bitmap.c
++++ b/libfreerdp/codec/include/bitmap.c
+@@ -31,7 +31,10 @@ static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 r
+ 	BYTE mask = 0x01;
+ 
+ 	if (cBits > 8)
++	{
++		WLog_ERR(TAG, "cBits %d > 8", cBits);
+ 		return NULL;
++	}
+ 
+ 	if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
+ 		return NULL;
+@@ -46,7 +49,6 @@ static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 r
+ 			data = xorPixel;
+ 
+ 		DESTWRITEPIXEL(pbDest, data);
+-		DESTNEXTPIXEL(pbDest);
+ 		mask = mask << 1;
+ 	});
+ 	return pbDest;
+@@ -62,7 +64,10 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd,
+ 	BYTE mask = 0x01;
+ 
+ 	if (cBits > 8)
++	{
++		WLog_ERR(TAG, "cBits %d > 8", cBits);
+ 		return NULL;
++	}
+ 
+ 	if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
+ 		return NULL;
+@@ -76,7 +81,6 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd,
+ 			data = BLACK_PIXEL;
+ 
+ 		DESTWRITEPIXEL(pbDest, data);
+-		DESTNEXTPIXEL(pbDest);
+ 		mask = mask << 1;
+ 	});
+ 	return pbDest;
+@@ -88,6 +92,9 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd,
+ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BYTE* pbDestBuffer,
+                                  UINT32 rowDelta, UINT32 width, UINT32 height)
+ {
++#if defined(WITH_DEBUG_CODECS)
++	char sbuffer[128] = { 0 };
++#endif
+ 	const BYTE* pbSrc = pbSrcBuffer;
+ 	const BYTE* pbEnd;
+ 	const BYTE* pbDestEnd;
+@@ -100,14 +107,22 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 	PIXEL pixelA, pixelB;
+ 	UINT32 runLength;
+ 	UINT32 code;
+-	UINT32 advance;
++	UINT32 advance = 0;
+ 	RLEEXTRA
+ 
+ 	if ((rowDelta == 0) || (rowDelta < width))
++	{
++		WLog_ERR(TAG, "Invalid arguments: rowDelta=%" PRIu32 " == 0 || < width=%" PRIu32, rowDelta,
++		         width);
+ 		return FALSE;
++	}
+ 
+ 	if (!pbSrcBuffer || !pbDestBuffer)
++	{
++		WLog_ERR(TAG, "Invalid arguments: pbSrcBuffer=%p, pbDestBuffer=%p", pbSrcBuffer,
++		         pbDestBuffer);
+ 		return FALSE;
++	}
+ 
+ 	pbEnd = pbSrcBuffer + cbSrcBuffer;
+ 	pbDestEnd = pbDestBuffer + rowDelta * height;
+@@ -130,10 +145,17 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 		*/
+ 		code = ExtractCodeId(*pbSrc);
+ 
++#if defined(WITH_DEBUG_CODECS)
++		WLog_VRB(TAG, "pbSrc=%p code=%s, rem=%" PRIuz, pbSrc,
++		         rle_code_str_buffer(code, sbuffer, sizeof(sbuffer)), pbEnd - pbSrc);
++#endif
++
+ 		/* Handle Background Run Orders. */
+-		if (code == REGULAR_BG_RUN || code == MEGA_MEGA_BG_RUN)
++		if ((code == REGULAR_BG_RUN) || (code == MEGA_MEGA_BG_RUN))
+ 		{
+-			runLength = ExtractRunLength(code, pbSrc, &advance);
++			runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
++			if (advance == 0)
++				return FALSE;
+ 			pbSrc = pbSrc + advance;
+ 
+ 			if (fFirstLine)
+@@ -144,17 +166,13 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 						return FALSE;
+ 
+ 					DESTWRITEPIXEL(pbDest, fgPel);
+-					DESTNEXTPIXEL(pbDest);
+ 					runLength = runLength - 1;
+ 				}
+ 
+ 				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
+ 					return FALSE;
+ 
+-				UNROLL(runLength, {
+-					DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
+-					DESTNEXTPIXEL(pbDest);
+-				});
++				UNROLL(runLength, { DESTWRITEPIXEL(pbDest, BLACK_PIXEL); });
+ 			}
+ 			else
+ 			{
+@@ -166,7 +184,6 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 						return FALSE;
+ 
+ 					DESTWRITEPIXEL(pbDest, temp ^ fgPel);
+-					DESTNEXTPIXEL(pbDest);
+ 					runLength--;
+ 				}
+ 
+@@ -176,7 +193,6 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 				UNROLL(runLength, {
+ 					DESTREADPIXEL(temp, pbDest - rowDelta);
+ 					DESTWRITEPIXEL(pbDest, temp);
+-					DESTNEXTPIXEL(pbDest);
+ 				});
+ 			}
+ 
+@@ -196,15 +212,16 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 			case MEGA_MEGA_FG_RUN:
+ 			case LITE_SET_FG_FG_RUN:
+ 			case MEGA_MEGA_SET_FG_RUN:
+-				runLength = ExtractRunLength(code, pbSrc, &advance);
++				runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
++				if (advance == 0)
++					return FALSE;
+ 				pbSrc = pbSrc + advance;
+ 
+ 				if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
+ 				{
+-					if (pbSrc >= pbEnd)
++					if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
+ 						return FALSE;
+ 					SRCREADPIXEL(fgPel, pbSrc);
+-					SRCNEXTPIXEL(pbSrc);
+ 				}
+ 
+ 				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
+@@ -212,17 +229,13 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 
+ 				if (fFirstLine)
+ 				{
+-					UNROLL(runLength, {
+-						DESTWRITEPIXEL(pbDest, fgPel);
+-						DESTNEXTPIXEL(pbDest);
+-					});
++					UNROLL(runLength, { DESTWRITEPIXEL(pbDest, fgPel); });
+ 				}
+ 				else
+ 				{
+ 					UNROLL(runLength, {
+ 						DESTREADPIXEL(temp, pbDest - rowDelta);
+ 						DESTWRITEPIXEL(pbDest, temp ^ fgPel);
+-						DESTNEXTPIXEL(pbDest);
+ 					});
+ 				}
+ 
+@@ -231,45 +244,41 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 			/* Handle Dithered Run Orders. */
+ 			case LITE_DITHERED_RUN:
+ 			case MEGA_MEGA_DITHERED_RUN:
+-				runLength = ExtractRunLength(code, pbSrc, &advance);
++				runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
++				if (advance == 0)
++					return FALSE;
+ 				pbSrc = pbSrc + advance;
+-				if (pbSrc >= pbEnd)
++				if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
+ 					return FALSE;
+ 				SRCREADPIXEL(pixelA, pbSrc);
+-				SRCNEXTPIXEL(pbSrc);
+-				if (pbSrc >= pbEnd)
++				if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
+ 					return FALSE;
+ 				SRCREADPIXEL(pixelB, pbSrc);
+-				SRCNEXTPIXEL(pbSrc);
+ 
+ 				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2))
+ 					return FALSE;
+ 
+ 				UNROLL(runLength, {
+ 					DESTWRITEPIXEL(pbDest, pixelA);
+-					DESTNEXTPIXEL(pbDest);
+ 					DESTWRITEPIXEL(pbDest, pixelB);
+-					DESTNEXTPIXEL(pbDest);
+ 				});
+ 				break;
+ 
+ 			/* Handle Color Run Orders. */
+ 			case REGULAR_COLOR_RUN:
+ 			case MEGA_MEGA_COLOR_RUN:
+-				runLength = ExtractRunLength(code, pbSrc, &advance);
++				runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
++				if (advance == 0)
++					return FALSE;
+ 				pbSrc = pbSrc + advance;
+-				if (pbSrc >= pbEnd)
++				if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
+ 					return FALSE;
+ 				SRCREADPIXEL(pixelA, pbSrc);
+-				SRCNEXTPIXEL(pbSrc);
+ 
+ 				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
+ 					return FALSE;
+ 
+-				UNROLL(runLength, {
+-					DESTWRITEPIXEL(pbDest, pixelA);
+-					DESTNEXTPIXEL(pbDest);
+-				});
++				UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); });
+ 				break;
+ 
+ 			/* Handle Foreground/Background Image Orders. */
+@@ -277,17 +286,20 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 			case MEGA_MEGA_FGBG_IMAGE:
+ 			case LITE_SET_FG_FGBG_IMAGE:
+ 			case MEGA_MEGA_SET_FGBG_IMAGE:
+-				runLength = ExtractRunLength(code, pbSrc, &advance);
++				runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
++				if (advance == 0)
++					return FALSE;
+ 				pbSrc = pbSrc + advance;
+ 
+-				if (pbSrc >= pbEnd)
+-					return FALSE;
+ 				if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
+ 				{
++					if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
++						return FALSE;
+ 					SRCREADPIXEL(fgPel, pbSrc);
+-					SRCNEXTPIXEL(pbSrc);
+ 				}
+ 
++				if (!buffer_within_range(pbSrc, runLength / 8, pbEnd))
++					return FALSE;
+ 				if (fFirstLine)
+ 				{
+ 					while (runLength > 8)
+@@ -306,8 +318,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 				{
+ 					while (runLength > 8)
+ 					{
+-						bitmask = *pbSrc;
+-						pbSrc = pbSrc + 1;
++						bitmask = *pbSrc++;
++
+ 						pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8);
+ 
+ 						if (!pbDest)
+@@ -319,8 +331,9 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 
+ 				if (runLength > 0)
+ 				{
+-					bitmask = *pbSrc;
+-					pbSrc = pbSrc + 1;
++					if (!buffer_within_range(pbSrc, 1, pbEnd))
++						return FALSE;
++					bitmask = *pbSrc++;
+ 
+ 					if (fFirstLine)
+ 					{
+@@ -342,23 +355,25 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 			/* Handle Color Image Orders. */
+ 			case REGULAR_COLOR_IMAGE:
+ 			case MEGA_MEGA_COLOR_IMAGE:
+-				runLength = ExtractRunLength(code, pbSrc, &advance);
++				runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
++				if (advance == 0)
++					return FALSE;
+ 				pbSrc = pbSrc + advance;
+ 				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
+ 					return FALSE;
++				if (!ENSURE_CAPACITY(pbSrc, pbEnd, runLength))
++					return FALSE;
+ 
+ 				UNROLL(runLength, {
+-					if (pbSrc >= pbEnd)
+-						return FALSE;
+ 					SRCREADPIXEL(temp, pbSrc);
+-					SRCNEXTPIXEL(pbSrc);
+ 					DESTWRITEPIXEL(pbDest, temp);
+-					DESTNEXTPIXEL(pbDest);
+ 				});
+ 				break;
+ 
+ 			/* Handle Special Order 1. */
+ 			case SPECIAL_FGBG_1:
++				if (!buffer_within_range(pbSrc, 1, pbEnd))
++					return FALSE;
+ 				pbSrc = pbSrc + 1;
+ 
+ 				if (fFirstLine)
+@@ -379,6 +394,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 
+ 			/* Handle Special Order 2. */
+ 			case SPECIAL_FGBG_2:
++				if (!buffer_within_range(pbSrc, 1, pbEnd))
++					return FALSE;
+ 				pbSrc = pbSrc + 1;
+ 
+ 				if (fFirstLine)
+@@ -399,27 +416,31 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
+ 
+ 			/* Handle White Order. */
+ 			case SPECIAL_WHITE:
++				if (!buffer_within_range(pbSrc, 1, pbEnd))
++					return FALSE;
+ 				pbSrc = pbSrc + 1;
+ 
+ 				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
+ 					return FALSE;
+ 
+ 				DESTWRITEPIXEL(pbDest, WHITE_PIXEL);
+-				DESTNEXTPIXEL(pbDest);
+ 				break;
+ 
+ 			/* Handle Black Order. */
+ 			case SPECIAL_BLACK:
++				if (!buffer_within_range(pbSrc, 1, pbEnd))
++					return FALSE;
+ 				pbSrc = pbSrc + 1;
+ 
+ 				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
+ 					return FALSE;
+ 
+ 				DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
+-				DESTNEXTPIXEL(pbDest);
+ 				break;
+ 
+ 			default:
++				WLog_ERR(TAG, "invalid code 0x%08" PRIx32 ", pbSrcBuffer=%p, pbSrc=%p, pbEnd=%p",
++				         code, pbSrcBuffer, pbSrc, pbEnd);
+ 				return FALSE;
+ 		}
+ 	}
+diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c
+index b76fe1ca3..abfdc51f9 100644
+--- a/libfreerdp/codec/interleaved.c
++++ b/libfreerdp/codec/interleaved.c
+@@ -21,6 +21,7 @@
+  * limitations under the License.
+  */
+ 
++#include <assert.h>
+ #ifdef HAVE_CONFIG_H
+ #include "config.h"
+ #endif
+@@ -30,15 +31,16 @@
+ 
+ #define TAG FREERDP_TAG("codec")
+ 
+-#define UNROLL_BODY(_exp, _count)      \
+-	do                                 \
+-	{                                  \
+-		size_t x;                      \
+-		for (x = 0; x < (_count); x++) \
+-		{                              \
+-			do                         \
+-				_exp while (FALSE);    \
+-		}                              \
++#define UNROLL_BODY(_exp, _count)             \
++	do                                        \
++	{                                         \
++		for (size_t x = 0; x < (_count); x++) \
++		{                                     \
++			do                                \
++			{                                 \
++				_exp                          \
++			} while (FALSE);                  \
++		}                                     \
+ 	} while (FALSE)
+ 
+ #define UNROLL_MULTIPLE(_condition, _exp, _count) \
+@@ -97,6 +99,80 @@ static const BYTE g_MaskSpecialFgBg2 = 0x05;
+ static const BYTE g_MaskRegularRunLength = 0x1F;
+ static const BYTE g_MaskLiteRunLength = 0x0F;
+ 
++static const char* rle_code_str(UINT32 code)
++{
++	switch (code)
++	{
++		case REGULAR_BG_RUN:
++			return "REGULAR_BG_RUN";
++		case MEGA_MEGA_BG_RUN:
++			return "MEGA_MEGA_BG_RUN";
++		case REGULAR_FG_RUN:
++			return "REGULAR_FG_RUN";
++		case MEGA_MEGA_FG_RUN:
++			return "MEGA_MEGA_FG_RUN";
++		case LITE_SET_FG_FG_RUN:
++			return "LITE_SET_FG_FG_RUN";
++		case MEGA_MEGA_SET_FG_RUN:
++			return "MEGA_MEGA_SET_FG_RUN";
++		case LITE_DITHERED_RUN:
++			return "LITE_DITHERED_RUN";
++		case MEGA_MEGA_DITHERED_RUN:
++			return "MEGA_MEGA_DITHERED_RUN";
++		case REGULAR_COLOR_RUN:
++			return "REGULAR_COLOR_RUN";
++		case MEGA_MEGA_COLOR_RUN:
++			return "MEGA_MEGA_COLOR_RUN";
++		case REGULAR_FGBG_IMAGE:
++			return "REGULAR_FGBG_IMAGE";
++		case MEGA_MEGA_FGBG_IMAGE:
++			return "MEGA_MEGA_FGBG_IMAGE";
++		case LITE_SET_FG_FGBG_IMAGE:
++			return "LITE_SET_FG_FGBG_IMAGE";
++		case MEGA_MEGA_SET_FGBG_IMAGE:
++			return "MEGA_MEGA_SET_FGBG_IMAGE";
++		case REGULAR_COLOR_IMAGE:
++			return "REGULAR_COLOR_IMAGE";
++		case MEGA_MEGA_COLOR_IMAGE:
++			return "MEGA_MEGA_COLOR_IMAGE";
++		case SPECIAL_FGBG_1:
++			return "SPECIAL_FGBG_1";
++		case SPECIAL_FGBG_2:
++			return "SPECIAL_FGBG_2";
++		case SPECIAL_WHITE:
++			return "SPECIAL_WHITE";
++		case SPECIAL_BLACK:
++			return "SPECIAL_BLACK";
++		default:
++			return "UNKNOWN";
++	}
++}
++
++static const char* rle_code_str_buffer(UINT32 code, char* buffer, size_t size)
++{
++	const char* str = rle_code_str(code);
++	_snprintf(buffer, size, "%s [0x%08" PRIx32 "]", str, code);
++	return buffer;
++}
++
++#define buffer_within_range(pbSrc, size, pbEnd) \
++	buffer_within_range_((pbSrc), (size), (pbEnd), __func__, __FILE__, __LINE__)
++static INLINE BOOL buffer_within_range_(const void* pbSrc, size_t size, const void* pbEnd,
++                                        const char* fkt, const char* file, size_t line)
++{
++	WINPR_UNUSED(file);
++	assert((pbSrc) && "Assert failed: pbSrc");
++	assert((pbEnd) && "Assert failed: pbEnd");
++
++	if ((const char*)pbSrc + size > (const char*)pbEnd)
++	{
++		WLog_ERR(TAG, "[%s:%" PRIuz "] pbSrc=%p + %" PRIuz " > pbEnd=%p", fkt, line, pbSrc, size,
++		         pbEnd);
++		return FALSE;
++	}
++	return TRUE;
++}
++
+ /**
+  * Reads the supplied order header and extracts the compression
+  * order code ID.
+@@ -127,71 +203,155 @@ static INLINE UINT32 ExtractCodeId(BYTE bOrderHdr)
+ /**
+  * Extract the run length of a compression order.
+  */
+-static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT32* advance)
++static UINT ExtractRunLengthRegularFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
+ {
+-	UINT32 runLength;
+-	UINT32 ladvance;
+-	ladvance = 1;
+-	runLength = 0;
++	UINT runLength = 0;
+ 
+-	switch (code)
++	assert((pbOrderHdr) && "Assert failed: pbOrderHdr");
++	assert((pbEnd) && "Assert failed: pbEnd");
++	assert((advance) && "Assert failed: advance");
++
++	runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
++	if (runLength == 0)
+ 	{
+-		case REGULAR_FGBG_IMAGE:
+-			runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
++		if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
++		{
++			*advance = 0;
++			return 0;
++		}
++		runLength = *(pbOrderHdr + 1) + 1;
++		(*advance)++;
++	}
++	else
++		runLength = runLength * 8;
+ 
+-			if (runLength == 0)
+-			{
+-				runLength = (*(pbOrderHdr + 1)) + 1;
+-				ladvance += 1;
+-			}
+-			else
+-			{
+-				runLength = runLength * 8;
+-			}
++	return runLength;
++}
+ 
+-			break;
++static UINT ExtractRunLengthLiteFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
++{
++	UINT runLength = 0;
+ 
+-		case LITE_SET_FG_FGBG_IMAGE:
+-			runLength = (*pbOrderHdr) & g_MaskLiteRunLength;
++	assert((pbOrderHdr) && "Assert failed: pbOrderHdr");
++	assert((pbEnd) && "Assert failed: pbEnd");
++	assert((advance) && "Assert failed: advance");
+ 
+-			if (runLength == 0)
+-			{
+-				runLength = (*(pbOrderHdr + 1)) + 1;
+-				ladvance += 1;
+-			}
+-			else
+-			{
+-				runLength = runLength * 8;
+-			}
++	runLength = *pbOrderHdr & g_MaskLiteRunLength;
++	if (runLength == 0)
++	{
++		if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
++		{
++			*advance = 0;
++			return 0;
++		}
++		runLength = *(pbOrderHdr + 1) + 1;
++		(*advance)++;
++	}
++	else
++		runLength = runLength * 8;
++
++	return runLength;
++}
++
++static UINT ExtractRunLengthRegular(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
++{
++	UINT runLength = 0;
++
++	assert((pbOrderHeader) && "Assert failed: pbOrderHeader");
++	assert((pbEnd) && "Assert failed: pbEnd");
++	assert((advance) && "Assert failed: advance");
++
++	runLength = *pbOrderHdr & g_MaskRegularRunLength;
++	if (runLength == 0)
++	{
++		if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
++		{
++			*advance = 0;
++			return 0;
++		}
++		runLength = *(pbOrderHdr + 1) + 32;
++		(*advance)++;
++	}
++
++	return runLength;
++}
++
++static UINT ExtractRunLengthMegaMega(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
++{
++	UINT runLength = 0;
++
++	assert((pbOrderHdr) && "Assert failed: pbOrderHdr");
++	assert((pbEnd) && "Assert failed: pbEnd");
++	assert((advance) && "Assert failed: advance");
++
++	if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
++	{
++		*advance = 0;
++		return 0;
++	}
++
++	runLength = ((UINT16)pbOrderHdr[1]) | (((UINT16)pbOrderHdr[2]) << 8);
++	(*advance) += 2;
++
++	return runLength;
++}
++
++static UINT ExtractRunLengthLite(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
++{
++	UINT runLength = 0;
++
++	assert((pbOrderHdr) && "Assert failed: pbOrderHdr");
++	assert((pbEnd) && "Assert failed: pbEnd");
++	assert((advance) && "Assert failed: advance");
++
++	runLength = *pbOrderHdr & g_MaskLiteRunLength;
++	if (runLength == 0)
++	{
++		if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
++		{
++			*advance = 0;
++			return 0;
++		}
++		runLength = *(pbOrderHdr + 1) + 16;
++		(*advance)++;
++	}
++	return runLength;
++}
++
++static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const BYTE* pbEnd,
++                                      UINT32* advance)
++{
++	UINT32 runLength = 0;
++	UINT32 ladvance = 1;
++
++	assert((pbOrderHdr) && "Assert failed: pbOrderHdr");
++	assert((pbEnd) && "Assert failed: pbEnd");
++	assert((advance) && "Assert failed: advance");
++
++	*advance = 0;
++	if (!buffer_within_range(pbOrderHdr, 0, pbEnd))
++		return 0;
++
++	switch (code)
++	{
++		case REGULAR_FGBG_IMAGE:
++			runLength = ExtractRunLengthRegularFgBg(pbOrderHdr, pbEnd, &ladvance);
++			break;
+ 
++		case LITE_SET_FG_FGBG_IMAGE:
++			runLength = ExtractRunLengthLiteFgBg(pbOrderHdr, pbEnd, &ladvance);
+ 			break;
+ 
+ 		case REGULAR_BG_RUN:
+ 		case REGULAR_FG_RUN:
+ 		case REGULAR_COLOR_RUN:
+ 		case REGULAR_COLOR_IMAGE:
+-			runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
+-
+-			if (runLength == 0)
+-			{
+-				/* An extended (MEGA) run. */
+-				runLength = (*(pbOrderHdr + 1)) + 32;
+-				ladvance += 1;
+-			}
+-
++			runLength = ExtractRunLengthRegular(pbOrderHdr, pbEnd, &ladvance);
+ 			break;
+ 
+ 		case LITE_SET_FG_FG_RUN:
+ 		case LITE_DITHERED_RUN:
+-			runLength = (*pbOrderHdr) & g_MaskLiteRunLength;
+-
+-			if (runLength == 0)
+-			{
+-				/* An extended (MEGA) run. */
+-				runLength = (*(pbOrderHdr + 1)) + 16;
+-				ladvance += 1;
+-			}
+-
++			runLength = ExtractRunLengthLite(pbOrderHdr, pbEnd, &ladvance);
+ 			break;
+ 
+ 		case MEGA_MEGA_BG_RUN:
+@@ -202,8 +362,12 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3
+ 		case MEGA_MEGA_FGBG_IMAGE:
+ 		case MEGA_MEGA_SET_FGBG_IMAGE:
+ 		case MEGA_MEGA_COLOR_IMAGE:
+-			runLength = ((UINT16)pbOrderHdr[1]) | ((UINT16)(pbOrderHdr[2] << 8));
+-			ladvance += 2;
++			runLength = ExtractRunLengthMegaMega(pbOrderHdr, pbEnd, &ladvance);
++			break;
++
++		default:
++			runLength = 0;
++			ladvance = 0;
+ 			break;
+ 	}
+ 
+@@ -211,20 +375,32 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3
+ 	return runLength;
+ }
+ 
+-static INLINE BOOL ensure_capacity(const BYTE* start, const BYTE* end, size_t size, size_t base)
++#define ensure_capacity(start, end, size, base) \
++	ensure_capacity_((start), (end), (size), (base), __func__, __FILE__, __LINE__)
++static INLINE BOOL ensure_capacity_(const BYTE* start, const BYTE* end, size_t size, size_t base,
++                                    const char* fkt, const char* file, size_t line)
+ {
+ 	const size_t available = (uintptr_t)end - (uintptr_t)start;
+ 	const BOOL rc = available >= size * base;
+-	return rc && (start <= end);
++	const BOOL res = rc && (start <= end);
++
++	if (!res)
++		WLog_ERR(TAG,
++		         "[%s:%" PRIuz "] failed: start=%p <= end=%p, available=%" PRIuz " >= size=%" PRIuz
++		         " * base=%" PRIuz,
++		         fkt, line, start, end, available, size, base);
++	return res;
+ }
+ 
+ static INLINE void write_pixel_8(BYTE* _buf, BYTE _pix)
+ {
++	assert((_buf) && "Assert failed: _buf");
+ 	*_buf = _pix;
+ }
+ 
+ static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix)
+ {
++	assert((_buf) && "Assert failed: _buf");
+ 	(_buf)[0] = (BYTE)(_pix);
+ 	(_buf)[1] = (BYTE)((_pix) >> 8);
+ 	(_buf)[2] = (BYTE)((_pix) >> 16);
+@@ -232,6 +408,7 @@ static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix)
+ 
+ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
+ {
++	assert((_buf) && "Assert failed: _buf");
+ 	_buf[0] = _pix & 0xFF;
+ 	_buf[1] = (_pix >> 8) & 0xFF;
+ }
+@@ -239,19 +416,30 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
+ #undef DESTWRITEPIXEL
+ #undef DESTREADPIXEL
+ #undef SRCREADPIXEL
+-#undef DESTNEXTPIXEL
+-#undef SRCNEXTPIXEL
+ #undef WRITEFGBGIMAGE
+ #undef WRITEFIRSTLINEFGBGIMAGE
+ #undef RLEDECOMPRESS
+ #undef RLEEXTRA
+ #undef WHITE_PIXEL
++#undef PIXEL_SIZE
++#undef PIXEL
++#define PIXEL_SIZE 1
++#define PIXEL BYTE
+ #define WHITE_PIXEL 0xFF
+-#define DESTWRITEPIXEL(_buf, _pix) write_pixel_8(_buf, _pix)
++#define DESTWRITEPIXEL(_buf, _pix) \
++	do                             \
++	{                              \
++		write_pixel_8(_buf, _pix); \
++		_buf += 1;                 \
++	} while (0)
+ #define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0]
+-#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0]
+-#define DESTNEXTPIXEL(_buf) _buf += 1
+-#define SRCNEXTPIXEL(_buf) _buf += 1
++#define SRCREADPIXEL(_pix, _buf) \
++	do                           \
++	{                            \
++		_pix = (_buf)[0];        \
++		_buf += 1;               \
++	} while (0)
++
+ #define WRITEFGBGIMAGE WriteFgBgImage8to8
+ #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage8to8
+ #define RLEDECOMPRESS RleDecompress8to8
+@@ -263,19 +451,29 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
+ #undef DESTWRITEPIXEL
+ #undef DESTREADPIXEL
+ #undef SRCREADPIXEL
+-#undef DESTNEXTPIXEL
+-#undef SRCNEXTPIXEL
+ #undef WRITEFGBGIMAGE
+ #undef WRITEFIRSTLINEFGBGIMAGE
+ #undef RLEDECOMPRESS
+ #undef RLEEXTRA
+ #undef WHITE_PIXEL
++#undef PIXEL_SIZE
++#undef PIXEL
++#define PIXEL_SIZE 2
++#define PIXEL UINT16
+ #define WHITE_PIXEL 0xFFFF
+-#define DESTWRITEPIXEL(_buf, _pix) write_pixel_16(_buf, _pix)
++#define DESTWRITEPIXEL(_buf, _pix)  \
++	do                              \
++	{                               \
++		write_pixel_16(_buf, _pix); \
++		_buf += 2;                  \
++	} while (0)
+ #define DESTREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]
+-#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8)
+-#define DESTNEXTPIXEL(_buf) _buf += 2
+-#define SRCNEXTPIXEL(_buf) _buf += 2
++#define SRCREADPIXEL(_pix, _buf)             \
++	do                                       \
++	{                                        \
++		_pix = (_buf)[0] | ((_buf)[1] << 8); \
++		_buf += 2;                           \
++	} while (0)
+ #define WRITEFGBGIMAGE WriteFgBgImage16to16
+ #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage16to16
+ #define RLEDECOMPRESS RleDecompress16to16
+@@ -287,19 +485,30 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
+ #undef DESTWRITEPIXEL
+ #undef DESTREADPIXEL
+ #undef SRCREADPIXEL
+-#undef DESTNEXTPIXEL
+-#undef SRCNEXTPIXEL
+ #undef WRITEFGBGIMAGE
+ #undef WRITEFIRSTLINEFGBGIMAGE
+ #undef RLEDECOMPRESS
+ #undef RLEEXTRA
+ #undef WHITE_PIXEL
+-#define WHITE_PIXEL 0xFFFFFF
+-#define DESTWRITEPIXEL(_buf, _pix) write_pixel_24(_buf, _pix)
++#undef PIXEL_SIZE
++#undef PIXEL
++#define PIXEL_SIZE 3
++#define PIXEL UINT32
++#define WHITE_PIXEL 0xffffff
++#define DESTWRITEPIXEL(_buf, _pix)  \
++	do                              \
++	{                               \
++		write_pixel_24(_buf, _pix); \
++		_buf += 3;                  \
++	} while (0)
+ #define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16)
+-#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16)
+-#define DESTNEXTPIXEL(_buf) _buf += 3
+-#define SRCNEXTPIXEL(_buf) _buf += 3
++#define SRCREADPIXEL(_pix, _buf)                                 \
++	do                                                           \
++	{                                                            \
++		_pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16); \
++		_buf += 3;                                               \
++	} while (0)
++
+ #define WRITEFGBGIMAGE WriteFgBgImage24to24
+ #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage24to24
+ #define RLEDECOMPRESS RleDecompress24to24
+@@ -308,18 +517,32 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
+ #define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 3)
+ #include "include/bitmap.c"
+ 
++struct S_BITMAP_INTERLEAVED_CONTEXT
++{
++	BOOL Compressor;
++
++	UINT32 TempSize;
++	BYTE* TempBuffer;
++
++	wStream* bts;
++};
++
+ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE* pSrcData,
+                             UINT32 SrcSize, UINT32 nSrcWidth, UINT32 nSrcHeight, UINT32 bpp,
+                             BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst,
+                             UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,
+                             const gdiPalette* palette)
+ {
+-	UINT32 scanline;
+-	UINT32 SrcFormat;
+-	UINT32 BufferSize;
++	UINT32 scanline = 0;
++	UINT32 SrcFormat = 0;
++	UINT32 BufferSize = 0;
+ 
+ 	if (!interleaved || !pSrcData || !pDstData)
++	{
++		WLog_ERR(TAG, "invalid arguments: interleaved=%p, pSrcData=%p, pDstData=%p", interleaved,
++		         pSrcData, pDstData);
+ 		return FALSE;
++	}
+ 
+ 	switch (bpp)
+ 	{
+@@ -352,19 +575,26 @@ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE*
+ 
+ 	if (BufferSize > interleaved->TempSize)
+ 	{
+-		interleaved->TempBuffer = _aligned_realloc(interleaved->TempBuffer, BufferSize, 16);
++		interleaved->TempBuffer =
++		    _aligned_recalloc(interleaved->TempBuffer, BufferSize, sizeof(BYTE), 16);
+ 		interleaved->TempSize = BufferSize;
+ 	}
+ 
+ 	if (!interleaved->TempBuffer)
++	{
++		WLog_ERR(TAG, "interleaved->TempBuffer=%p", interleaved->TempBuffer);
+ 		return FALSE;
++	}
+ 
+ 	switch (bpp)
+ 	{
+ 		case 24:
+ 			if (!RleDecompress24to24(pSrcData, SrcSize, interleaved->TempBuffer, scanline,
+ 			                         nSrcWidth, nSrcHeight))
++			{
++				WLog_ERR(TAG, "RleDecompress24to24 failed");
+ 				return FALSE;
++			}
+ 
+ 			break;
+ 
+@@ -372,24 +602,36 @@ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE*
+ 		case 15:
+ 			if (!RleDecompress16to16(pSrcData, SrcSize, interleaved->TempBuffer, scanline,
+ 			                         nSrcWidth, nSrcHeight))
++			{
++				WLog_ERR(TAG, "RleDecompress16to16 failed");
+ 				return FALSE;
++			}
+ 
+ 			break;
+ 
+ 		case 8:
+ 			if (!RleDecompress8to8(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth,
+ 			                       nSrcHeight))
++			{
++				WLog_ERR(TAG, "RleDecompress8to8 failed");
+ 				return FALSE;
++			}
+ 
+ 			break;
+ 
+ 		default:
++			WLog_ERR(TAG, "Invalid color depth %" PRIu32 "", bpp);
+ 			return FALSE;
+ 	}
+ 
+-	return freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight,
+-	                          interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette,
+-	                          FREERDP_FLIP_VERTICAL);
++	if (!freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight,
++	                        interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette,
++	                        FREERDP_FLIP_VERTICAL))
++	{
++		WLog_ERR(TAG, "freerdp_image_copy failed");
++		return FALSE;
++	}
++	return TRUE;
+ }
+ 
+ BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstData, UINT32* pDstSize,
+@@ -397,10 +639,10 @@ BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstDat
+                           UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette,
+                           UINT32 bpp)
+ {
+-	BOOL status;
+-	wStream* s;
++	BOOL status = 0;
++	wStream* s = NULL;
+ 	UINT32 DstFormat = 0;
+-	const size_t maxSize = 64 * 64 * 4;
++	const UINT32 maxSize = 64 * 64 * 4;
+ 
+ 	if (!interleaved || !pDstData || !pSrcData)
+ 		return FALSE;
+@@ -442,7 +684,7 @@ BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstDat
+ 	}
+ 
+ 	if (!freerdp_image_copy(interleaved->TempBuffer, DstFormat, 0, 0, 0, nWidth, nHeight, pSrcData,
+-	                        SrcFormat, nSrcStep, nXSrc, nYSrc, palette, FREERDP_FLIP_NONE))
++	                        SrcFormat, nSrcStep, nXSrc, nYSrc, palette, 0))
+ 		return FALSE;
+ 
+ 	s = Stream_New(pDstData, *pDstSize);
+@@ -474,33 +716,29 @@ BOOL bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved)
+ 
+ BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor)
+ {
+-	BITMAP_INTERLEAVED_CONTEXT* interleaved;
+-	interleaved = (BITMAP_INTERLEAVED_CONTEXT*)calloc(1, sizeof(BITMAP_INTERLEAVED_CONTEXT));
++	BITMAP_INTERLEAVED_CONTEXT* interleaved = NULL;
++	interleaved = (BITMAP_INTERLEAVED_CONTEXT*)_aligned_recalloc(
++	    NULL, 1, sizeof(BITMAP_INTERLEAVED_CONTEXT), 32);
+ 
+ 	if (interleaved)
+ 	{
+ 		interleaved->TempSize = 64 * 64 * 4;
+-		interleaved->TempBuffer = _aligned_malloc(interleaved->TempSize, 16);
++		interleaved->TempBuffer = _aligned_malloc(interleaved->TempSize * sizeof(BYTE), 16);
+ 
+ 		if (!interleaved->TempBuffer)
+-		{
+-			free(interleaved);
+-			WLog_ERR(TAG, "_aligned_malloc failed!");
+-			return NULL;
+-		}
++			goto fail;
+ 
+ 		interleaved->bts = Stream_New(NULL, interleaved->TempSize);
+ 
+ 		if (!interleaved->bts)
+-		{
+-			_aligned_free(interleaved->TempBuffer);
+-			free(interleaved);
+-			WLog_ERR(TAG, "Stream_New failed!");
+-			return NULL;
+-		}
++			goto fail;
+ 	}
+ 
+ 	return interleaved;
++
++fail:
++	bitmap_interleaved_context_free(interleaved);
++	return NULL;
+ }
+ 
+ void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved)
+@@ -510,5 +748,5 @@ void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved)
+ 
+ 	_aligned_free(interleaved->TempBuffer);
+ 	Stream_Free(interleaved->bts, TRUE);
+-	free(interleaved);
++	_aligned_free(interleaved);
+ }
diff --git a/meta-oe/recipes-support/freerdp/freerdp_2.6.1.bb b/meta-oe/recipes-support/freerdp/freerdp_2.6.1.bb
index 6d98ad36f7..85d24428d4 100644
--- a/meta-oe/recipes-support/freerdp/freerdp_2.6.1.bb
+++ b/meta-oe/recipes-support/freerdp/freerdp_2.6.1.bb
@@ -36,6 +36,7 @@  SRC_URI = "git://github.com/FreeRDP/FreeRDP.git;branch=stable-2.0;protocol=https
            file://CVE-2024-32040.patch \
            file://CVE-2024-32458.patch \
            file://CVE-2024-32459.patch \
+           file://CVE-2024-32460.patch \
            "
 
 S = "${WORKDIR}/git"