File freerdp-CVE-2024-32658.patch of Package freerdp.34025

From aabe57e643ec6e297d8f5b36d0eec1e8beaa33bd Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Fri, 2 Jul 2021 07:42:43 +0200
Subject: [PATCH 1/7] Added bounds checks to ExtractRunLength

---
 libfreerdp/codec/include/bitmap.c | 12 ++++++------
 libfreerdp/codec/interleaved.c    | 20 +++++++++++++++++++-
 2 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/libfreerdp/codec/include/bitmap.c b/libfreerdp/codec/include/bitmap.c
index 355c697e0..18e94ee8d 100644
--- a/libfreerdp/codec/include/bitmap.c
+++ b/libfreerdp/codec/include/bitmap.c
@@ -131,7 +131,7 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 		/* Handle Background Run Orders. */
 		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;
@@ -190,7 +190,7 @@ 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;
@@ -222,7 +222,7 @@ 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;
@@ -245,7 +245,7 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 			/* 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;
@@ -264,7 +264,7 @@ 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;
@@ -330,7 +330,7 @@ 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;
diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c
index a5456f725..1c2e4d67b 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -127,13 +127,17 @@ 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 INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const BYTE* pbEnd,
+                                      UINT32* advance)
 {
 	UINT32 runLength;
 	UINT32 ladvance;
 	ladvance = 1;
 	runLength = 0;
 
+	if (pbOrderHdr >= pbEnd)
+		return 0;
+
 	switch (code)
 	{
 		case REGULAR_FGBG_IMAGE:
@@ -141,6 +145,8 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3
 
 			if (runLength == 0)
 			{
+				if (pbOrderHdr + 1 >= pbEnd)
+					return 0;
 				runLength = (*(pbOrderHdr + 1)) + 1;
 				ladvance += 1;
 			}
@@ -156,6 +162,9 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3
 
 			if (runLength == 0)
 			{
+				if (pbOrderHdr + 1 >= pbEnd)
+					return 0;
+
 				runLength = (*(pbOrderHdr + 1)) + 1;
 				ladvance += 1;
 			}
@@ -175,6 +184,9 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3
 			if (runLength == 0)
 			{
 				/* An extended (MEGA) run. */
+				if (pbOrderHdr + 1 >= pbEnd)
+					return 0;
+
 				runLength = (*(pbOrderHdr + 1)) + 32;
 				ladvance += 1;
 			}
@@ -188,6 +200,9 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3
 			if (runLength == 0)
 			{
 				/* An extended (MEGA) run. */
+				if (pbOrderHdr + 1 >= pbEnd)
+					return 0;
+
 				runLength = (*(pbOrderHdr + 1)) + 16;
 				ladvance += 1;
 			}
@@ -202,6 +217,9 @@ 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:
+			if (pbOrderHdr + 2 >= pbEnd)
+				return 0;
+
 			runLength = ((UINT16)pbOrderHdr[1]) | ((UINT16)(pbOrderHdr[2] << 8));
 			ladvance += 2;
 			break;
-- 
2.45.0


From 616bfab5e227ecdb989fb874f49013117dc1a359 Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Mon, 12 Dec 2022 13:28:36 +0100
Subject: [PATCH 2/7] [codec,interleaved] add proper debug logging

log reason for decoder to fail
---
 libfreerdp/codec/include/bitmap.c | 27 ++++++++---
 libfreerdp/codec/interleaved.c    | 78 ++++++++++++++++++++++++++-----
 2 files changed, 87 insertions(+), 18 deletions(-)

diff --git a/libfreerdp/codec/include/bitmap.c b/libfreerdp/codec/include/bitmap.c
index 18e94ee8d..c41c5cb0a 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, "[%s] cBits %d > 8", __FUNCTION__, cBits);
 		return NULL;
+	}
 
 	if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
 		return NULL;
@@ -61,7 +64,10 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd,
 	BYTE mask = 0x01;
 
 	if (cBits > 8)
+	{
+		WLog_ERR(TAG, "[%s] cBits %d > 8", __FUNCTION__, cBits);
 		return NULL;
+	}
 
 	if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
 		return NULL;
@@ -102,10 +108,18 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 	RLEEXTRA
 
 	if ((rowDelta == 0) || (rowDelta < width))
+	{
+		WLog_ERR(TAG, "[%s] Invalid arguments: rowDelta=%" PRIu32 " == 0 || < width=%" PRIu32,
+		         __FUNCTION__, rowDelta, width);
 		return FALSE;
+	}
 
 	if (!pbSrcBuffer || !pbDestBuffer)
+	{
+		WLog_ERR(TAG, "[%s] Invalid arguments: pbSrcBuffer=%p, pbDestBuffer=%p", __FUNCTION__,
+		         pbSrcBuffer, pbDestBuffer);
 		return FALSE;
+	}
 
 	pbEnd = pbSrcBuffer + cbSrcBuffer;
 	pbDestEnd = pbDestBuffer + rowDelta * height;
@@ -197,7 +211,7 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 
 				if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
 				{
-					if (pbSrc + sizeof(fgPel) >= pbEnd)
+					if (!buffer_within_range(pbSrc, pbEnd))
 						return FALSE;
 					SRCREADPIXEL(fgPel, pbSrc);
 				}
@@ -226,10 +240,10 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 				if (advance == 0)
 					return FALSE;
 				pbSrc = pbSrc + advance;
-				if (pbSrc + sizeof(pixelA) >= pbEnd)
+				if (!buffer_within_range(pbSrc, pbEnd))
 					return FALSE;
 				SRCREADPIXEL(pixelA, pbSrc);
-				if (pbSrc + sizeof(pixelB) >= pbEnd)
+				if (!buffer_within_range(pbSrc, pbEnd))
 					return FALSE;
 				SRCREADPIXEL(pixelB, pbSrc);
 
@@ -249,7 +263,7 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 				if (advance == 0)
 					return FALSE;
 				pbSrc = pbSrc + advance;
-				if (pbSrc + sizeof(pixelA) >= pbEnd)
+				if (!buffer_within_range(pbSrc, pbEnd))
 					return FALSE;
 				SRCREADPIXEL(pixelA, pbSrc);
 
@@ -269,7 +283,7 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 					return FALSE;
 				pbSrc = pbSrc + advance;
 
-				if (pbSrc + sizeof(fgPel) >= pbEnd)
+				if (!buffer_within_range(pbSrc, pbEnd))
 					return FALSE;
 				if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
 				{
@@ -338,7 +352,7 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 					return FALSE;
 
 				UNROLL(runLength, {
-					if (pbSrc >= pbEnd)
+					if (!buffer_within_range(pbSrc, pbEnd))
 						return FALSE;
 					SRCREADPIXEL(temp, pbSrc);
 					DESTWRITEPIXEL(pbDest, temp);
@@ -406,6 +420,7 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 				break;
 
 			default:
+				WLog_ERR(TAG, "[%s] invalid code 0x%08" PRIx32, __FUNCTION__, code);
 				return FALSE;
 		}
 	}
diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c
index 1c2e4d67b..5d9782338 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -24,6 +24,7 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
+#include <winpr/assert.h>
 
 #include <freerdp/codec/interleaved.h>
 #include <freerdp/log.h>
@@ -97,6 +98,20 @@ static const BYTE g_MaskSpecialFgBg2 = 0x05;
 static const BYTE g_MaskRegularRunLength = 0x1F;
 static const BYTE g_MaskLiteRunLength = 0x0F;
 
+#define buffer_within_range(pbSrc, pbEnd) \
+	buffer_within_range_((pbSrc), (pbEnd), __FUNCTION__, __FILE__, __LINE__)
+static INLINE BOOL buffer_within_range_(const void* pbSrc, const void* pbEnd, const char* fkt,
+                                        const char* file, size_t line)
+{
+	WINPR_UNUSED(file);
+	if (pbSrc >= pbEnd)
+	{
+		WLog_ERR(TAG, "[%s:%" PRIuz "] pbSrc=%p >= pbEnd=%p", fkt, line, pbSrc, pbEnd);
+		return FALSE;
+	}
+	return TRUE;
+}
+
 /**
  * Reads the supplied order header and extracts the compression
  * order code ID.
@@ -135,7 +150,11 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
 	ladvance = 1;
 	runLength = 0;
 
-	if (pbOrderHdr >= pbEnd)
+	WINPR_ASSERT(pbOrderHdr);
+	WINPR_ASSERT(pbEnd);
+	WINPR_ASSERT(advance);
+
+	if (!buffer_within_range(pbOrderHdr, pbEnd))
 		return 0;
 
 	switch (code)
@@ -145,7 +164,7 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
 
 			if (runLength == 0)
 			{
-				if (pbOrderHdr + 1 >= pbEnd)
+				if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
 					return 0;
 				runLength = (*(pbOrderHdr + 1)) + 1;
 				ladvance += 1;
@@ -162,7 +181,7 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
 
 			if (runLength == 0)
 			{
-				if (pbOrderHdr + 1 >= pbEnd)
+				if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
 					return 0;
 
 				runLength = (*(pbOrderHdr + 1)) + 1;
@@ -184,7 +203,7 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
 			if (runLength == 0)
 			{
 				/* An extended (MEGA) run. */
-				if (pbOrderHdr + 1 >= pbEnd)
+				if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
 					return 0;
 
 				runLength = (*(pbOrderHdr + 1)) + 32;
@@ -200,7 +219,7 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
 			if (runLength == 0)
 			{
 				/* An extended (MEGA) run. */
-				if (pbOrderHdr + 1 >= pbEnd)
+				if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
 					return 0;
 
 				runLength = (*(pbOrderHdr + 1)) + 16;
@@ -217,7 +236,7 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
 		case MEGA_MEGA_FGBG_IMAGE:
 		case MEGA_MEGA_SET_FGBG_IMAGE:
 		case MEGA_MEGA_COLOR_IMAGE:
-			if (pbOrderHdr + 2 >= pbEnd)
+			if (!buffer_within_range(pbOrderHdr + 2, pbEnd))
 				return 0;
 
 			runLength = ((UINT16)pbOrderHdr[1]) | ((UINT16)(pbOrderHdr[2] << 8));
@@ -229,20 +248,32 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
 	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), __FUNCTION__, __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)
 {
+	WINPR_ASSERT(_buf);
 	*_buf = _pix;
 }
 
 static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix)
 {
+	WINPR_ASSERT(_buf);
 	(_buf)[0] = (BYTE)(_pix);
 	(_buf)[1] = (BYTE)((_pix) >> 8);
 	(_buf)[2] = (BYTE)((_pix) >> 16);
@@ -250,6 +281,7 @@ static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix)
 
 static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
 {
+	WINPR_ASSERT(_buf);
 	_buf[0] = _pix & 0xFF;
 	_buf[1] = (_pix >> 8) & 0xFF;
 }
@@ -357,7 +389,11 @@ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE*
 	UINT32 BufferSize;
 
 	if (!interleaved || !pSrcData || !pDstData)
+	{
+		WLog_ERR(TAG, "[%s] invalid arguments: interleaved=%p, pSrcData=%p, pDstData=%p",
+		         __FUNCTION__, interleaved, pSrcData, pDstData);
 		return FALSE;
+	}
 
 	switch (bpp)
 	{
@@ -382,7 +418,7 @@ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE*
 			break;
 
 		default:
-			WLog_ERR(TAG, "Invalid color depth %" PRIu32 "", bpp);
+			WLog_ERR(TAG, "[%s] Invalid color depth %" PRIu32 "", __FUNCTION__, bpp);
 			return FALSE;
 	}
 
@@ -395,14 +431,20 @@ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE*
 	}
 
 	if (!interleaved->TempBuffer)
+	{
+		WLog_ERR(TAG, "[%s] interleaved->TempBuffer=%p", __FUNCTION__, interleaved->TempBuffer);
 		return FALSE;
+	}
 
 	switch (bpp)
 	{
 		case 24:
 			if (!RleDecompress24to24(pSrcData, SrcSize, interleaved->TempBuffer, scanline,
 			                         nSrcWidth, nSrcHeight))
+			{
+				WLog_ERR(TAG, "[%s] RleDecompress24to24 failed", __FUNCTION__);
 				return FALSE;
+			}
 
 			break;
 
@@ -410,24 +452,36 @@ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE*
 		case 15:
 			if (!RleDecompress16to16(pSrcData, SrcSize, interleaved->TempBuffer, scanline,
 			                         nSrcWidth, nSrcHeight))
+			{
+				WLog_ERR(TAG, "[%s] RleDecompress16to16 failed", __FUNCTION__);
 				return FALSE;
+			}
 
 			break;
 
 		case 8:
 			if (!RleDecompress8to8(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth,
 			                       nSrcHeight))
+			{
+				WLog_ERR(TAG, "[%s] RleDecompress8to8 failed", __FUNCTION__);
 				return FALSE;
+			}
 
 			break;
 
 		default:
+			WLog_ERR(TAG, "[%s] Invalid color depth %" PRIu32 "", __FUNCTION__, 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, "[%s] freerdp_image_copy failed", __FUNCTION__);
+		return FALSE;
+	}
+	return TRUE;
 }
 
 BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstData, UINT32* pDstSize,
-- 
2.45.0


From 3e5e4a231fe7f886e0aaad810a648e7e1960ef37 Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Mon, 12 Dec 2022 16:01:59 +0100
Subject: [PATCH 3/7] [codec,interleaved] refactored run length reading

---
 libfreerdp/codec/interleaved.c | 166 ++++++++++++++++++++++-----------
 1 file changed, 109 insertions(+), 57 deletions(-)

diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c
index 5d9782338..c573408a0 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -142,6 +142,106 @@ static INLINE UINT32 ExtractCodeId(BYTE bOrderHdr)
 /**
  * Extract the run length of a compression order.
  */
+static UINT ExtractRunLengthRegularFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
+{
+	UINT runLength;
+
+	WINPR_ASSERT(pbOrderHdr);
+	WINPR_ASSERT(pbEnd);
+	WINPR_ASSERT(advance);
+
+	runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
+	if (runLength == 0)
+	{
+		if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
+			return 0;
+		runLength = *(pbOrderHdr + 1) + 1;
+		(*advance)++;
+	}
+	else
+		runLength = runLength * 8;
+
+	return runLength;
+}
+
+static UINT ExtractRunLengthLiteFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
+{
+	UINT runLength;
+
+	WINPR_ASSERT(pbOrderHdr);
+	WINPR_ASSERT(pbEnd);
+	WINPR_ASSERT(advance);
+
+	runLength = *pbOrderHdr & g_MaskLiteRunLength;
+	if (runLength == 0)
+	{
+		if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
+			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;
+
+	WINPR_ASSERT(pbOrderHdr);
+	WINPR_ASSERT(pbEnd);
+	WINPR_ASSERT(advance);
+
+	runLength = *pbOrderHdr & g_MaskRegularRunLength;
+	if (runLength == 0)
+	{
+		if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
+			return 0;
+		runLength = *(pbOrderHdr + 1) + 32;
+		(*advance)++;
+	}
+
+	return runLength;
+}
+
+static UINT ExtractRunLengthMegaMega(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
+{
+	UINT runLength;
+
+	WINPR_ASSERT(pbOrderHdr);
+	WINPR_ASSERT(pbEnd);
+	WINPR_ASSERT(advance);
+
+	if (!buffer_within_range(pbOrderHdr + 2, pbEnd))
+		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;
+
+	WINPR_ASSERT(pbOrderHdr);
+	WINPR_ASSERT(pbEnd);
+	WINPR_ASSERT(advance);
+
+	runLength = *pbOrderHdr & g_MaskLiteRunLength;
+	if (runLength == 0)
+	{
+		if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
+			return 0;
+		runLength = *(pbOrderHdr + 1) + 16;
+		(*advance)++;
+	}
+	return runLength;
+}
+
 static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const BYTE* pbEnd,
                                       UINT32* advance)
 {
@@ -160,72 +260,23 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
 	switch (code)
 	{
 		case REGULAR_FGBG_IMAGE:
-			runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
-
-			if (runLength == 0)
-			{
-				if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
-					return 0;
-				runLength = (*(pbOrderHdr + 1)) + 1;
-				ladvance += 1;
-			}
-			else
-			{
-				runLength = runLength * 8;
-			}
-
+			runLength = ExtractRunLengthRegularFgBg(pbOrderHdr, pbEnd, &ladvance);
 			break;
 
 		case LITE_SET_FG_FGBG_IMAGE:
-			runLength = (*pbOrderHdr) & g_MaskLiteRunLength;
-
-			if (runLength == 0)
-			{
-				if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
-					return 0;
-
-				runLength = (*(pbOrderHdr + 1)) + 1;
-				ladvance += 1;
-			}
-			else
-			{
-				runLength = runLength * 8;
-			}
-
+			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. */
-				if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
-					return 0;
-
-				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. */
-				if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
-					return 0;
-
-				runLength = (*(pbOrderHdr + 1)) + 16;
-				ladvance += 1;
-			}
-
+			runLength = ExtractRunLengthLite(pbOrderHdr, pbEnd, &ladvance);
 			break;
 
 		case MEGA_MEGA_BG_RUN:
@@ -236,11 +287,12 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
 		case MEGA_MEGA_FGBG_IMAGE:
 		case MEGA_MEGA_SET_FGBG_IMAGE:
 		case MEGA_MEGA_COLOR_IMAGE:
-			if (!buffer_within_range(pbOrderHdr + 2, pbEnd))
-				return 0;
+			runLength = ExtractRunLengthMegaMega(pbOrderHdr, pbEnd, &ladvance);
+			break;
 
-			runLength = ((UINT16)pbOrderHdr[1]) | ((UINT16)(pbOrderHdr[2] << 8));
-			ladvance += 2;
+		default:
+			runLength = 0;
+			ladvance = 0;
 			break;
 	}
 
-- 
2.45.0


From b08e85ef07c22b9142a6f41f30b33f1eab585361 Mon Sep 17 00:00:00 2001
From: Armin Novak <anovak@thincast.com>
Date: Thu, 7 Sep 2023 19:49:15 +0200
Subject: [PATCH 4/7] [codec,interleaved] fix type definition

---
 libfreerdp/codec/include/bitmap.c | 31 ++++++++++++++-------
 libfreerdp/codec/interleaved.c    | 46 +++++++++++++++++++++----------
 2 files changed, 53 insertions(+), 24 deletions(-)

diff --git a/libfreerdp/codec/include/bitmap.c b/libfreerdp/codec/include/bitmap.c
index c41c5cb0a..9eed1c439 100644
--- a/libfreerdp/codec/include/bitmap.c
+++ b/libfreerdp/codec/include/bitmap.c
@@ -211,7 +211,7 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 
 				if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
 				{
-					if (!buffer_within_range(pbSrc, pbEnd))
+					if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
 						return FALSE;
 					SRCREADPIXEL(fgPel, pbSrc);
 				}
@@ -240,10 +240,10 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 				if (advance == 0)
 					return FALSE;
 				pbSrc = pbSrc + advance;
-				if (!buffer_within_range(pbSrc, pbEnd))
+				if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
 					return FALSE;
 				SRCREADPIXEL(pixelA, pbSrc);
-				if (!buffer_within_range(pbSrc, pbEnd))
+				if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
 					return FALSE;
 				SRCREADPIXEL(pixelB, pbSrc);
 
@@ -263,7 +263,7 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 				if (advance == 0)
 					return FALSE;
 				pbSrc = pbSrc + advance;
-				if (!buffer_within_range(pbSrc, pbEnd))
+				if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
 					return FALSE;
 				SRCREADPIXEL(pixelA, pbSrc);
 
@@ -283,13 +283,15 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 					return FALSE;
 				pbSrc = pbSrc + advance;
 
-				if (!buffer_within_range(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);
 				}
 
+				if (!buffer_within_range(pbSrc, runLength / 8, pbEnd))
+					return FALSE;
 				if (fFirstLine)
 				{
 					while (runLength > 8)
@@ -308,8 +310,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)
@@ -321,8 +323,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)
 					{
@@ -361,6 +364,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 
 			/* Handle Special Order 1. */
 			case SPECIAL_FGBG_1:
+				if (!buffer_within_range(pbSrc, 1, pbEnd))
+					return FALSE;
 				pbSrc = pbSrc + 1;
 
 				if (fFirstLine)
@@ -381,6 +386,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)
@@ -401,6 +408,8 @@ 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))
@@ -411,6 +420,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 
 			/* Handle Black Order. */
 			case SPECIAL_BLACK:
+				if (!buffer_within_range(pbSrc, 1, pbEnd))
+					return FALSE;
 				pbSrc = pbSrc + 1;
 
 				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c
index c573408a0..90f3b3c2b 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -38,7 +38,9 @@
 		for (x = 0; x < (_count); x++) \
 		{                              \
 			do                         \
-				_exp while (FALSE);    \
+			{                          \
+				_exp                   \
+			} while (FALSE);           \
 		}                              \
 	} while (FALSE)
 
@@ -98,15 +100,19 @@ static const BYTE g_MaskSpecialFgBg2 = 0x05;
 static const BYTE g_MaskRegularRunLength = 0x1F;
 static const BYTE g_MaskLiteRunLength = 0x0F;
 
-#define buffer_within_range(pbSrc, pbEnd) \
-	buffer_within_range_((pbSrc), (pbEnd), __FUNCTION__, __FILE__, __LINE__)
-static INLINE BOOL buffer_within_range_(const void* pbSrc, const void* pbEnd, const char* fkt,
-                                        const char* file, size_t line)
+#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);
-	if (pbSrc >= pbEnd)
+	WINPR_ASSERT(pbSrc);
+	WINPR_ASSERT(pbEnd);
+
+	if ((char*)pbSrc + size > pbEnd)
 	{
-		WLog_ERR(TAG, "[%s:%" PRIuz "] pbSrc=%p >= pbEnd=%p", fkt, line, pbSrc, pbEnd);
+		WLog_ERR(TAG, "[%s:%" PRIuz "] pbSrc=%p + %" PRIuz " > pbEnd=%p", fkt, line, pbSrc, size,
+		         pbEnd);
 		return FALSE;
 	}
 	return TRUE;
@@ -153,7 +159,7 @@ static UINT ExtractRunLengthRegularFgBg(const BYTE* pbOrderHdr, const BYTE* pbEn
 	runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
 	if (runLength == 0)
 	{
-		if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
+		if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
 			return 0;
 		runLength = *(pbOrderHdr + 1) + 1;
 		(*advance)++;
@@ -175,7 +181,7 @@ static UINT ExtractRunLengthLiteFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd,
 	runLength = *pbOrderHdr & g_MaskLiteRunLength;
 	if (runLength == 0)
 	{
-		if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
+		if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
 			return 0;
 		runLength = *(pbOrderHdr + 1) + 1;
 		(*advance)++;
@@ -197,7 +203,7 @@ static UINT ExtractRunLengthRegular(const BYTE* pbOrderHdr, const BYTE* pbEnd, U
 	runLength = *pbOrderHdr & g_MaskRegularRunLength;
 	if (runLength == 0)
 	{
-		if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
+		if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
 			return 0;
 		runLength = *(pbOrderHdr + 1) + 32;
 		(*advance)++;
@@ -214,7 +220,7 @@ static UINT ExtractRunLengthMegaMega(const BYTE* pbOrderHdr, const BYTE* pbEnd,
 	WINPR_ASSERT(pbEnd);
 	WINPR_ASSERT(advance);
 
-	if (!buffer_within_range(pbOrderHdr + 2, pbEnd))
+	if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
 		return 0;
 
 	runLength = ((UINT16)pbOrderHdr[1]) | (((UINT16)pbOrderHdr[2]) << 8);
@@ -234,7 +240,7 @@ static UINT ExtractRunLengthLite(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT
 	runLength = *pbOrderHdr & g_MaskLiteRunLength;
 	if (runLength == 0)
 	{
-		if (!buffer_within_range(pbOrderHdr + 1, pbEnd))
+		if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
 			return 0;
 		runLength = *(pbOrderHdr + 1) + 16;
 		(*advance)++;
@@ -254,7 +260,7 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
 	WINPR_ASSERT(pbEnd);
 	WINPR_ASSERT(advance);
 
-	if (!buffer_within_range(pbOrderHdr, pbEnd))
+	if (!buffer_within_range(pbOrderHdr, 0, pbEnd))
 		return 0;
 
 	switch (code)
@@ -346,6 +352,10 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
 #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) \
 	do                             \
@@ -377,6 +387,10 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
 #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)  \
 	do                              \
@@ -407,7 +421,11 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
 #undef RLEDECOMPRESS
 #undef RLEEXTRA
 #undef WHITE_PIXEL
-#define WHITE_PIXEL 0xFFFFFF
+#undef PIXEL_SIZE
+#undef PIXEL
+#define PIXEL_SIZE 3
+#define PIXEL UINT32
+#define WHITE_PIXEL 0xffffff
 #define DESTWRITEPIXEL(_buf, _pix)  \
 	do                              \
 	{                               \
-- 
2.45.0


From d60e836d0f489efec8e8b5829fd92c8ebcbcaa2e Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Tue, 13 Dec 2022 11:02:55 +0100
Subject: [PATCH 5/7] [codec,interleaved] move length check out of loop

---
 libfreerdp/codec/include/bitmap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libfreerdp/codec/include/bitmap.c b/libfreerdp/codec/include/bitmap.c
index 9eed1c439..9e4ed6f4e 100644
--- a/libfreerdp/codec/include/bitmap.c
+++ b/libfreerdp/codec/include/bitmap.c
@@ -353,10 +353,10 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
 				pbSrc = pbSrc + advance;
 				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
 					return FALSE;
+				if (!ENSURE_CAPACITY(pbSrc, pbEnd, runLength))
+					return FALSE;
 
 				UNROLL(runLength, {
-					if (!buffer_within_range(pbSrc, pbEnd))
-						return FALSE;
 					SRCREADPIXEL(temp, pbSrc);
 					DESTWRITEPIXEL(pbDest, temp);
 				});
-- 
2.45.0


From 4a8691a24037d1aa4b1eee4bf1c9df1d406b1071 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Sat, 20 Apr 2024 17:59:49 +0200
Subject: [PATCH 6/7] [codec,interleaved] fix offset error

---
 libfreerdp/codec/interleaved.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c
index 90f3b3c2b..f41cf26dd 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -159,7 +159,7 @@ static UINT ExtractRunLengthRegularFgBg(const BYTE* pbOrderHdr, const BYTE* pbEn
 	runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
 	if (runLength == 0)
 	{
-		if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
+		if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
 			return 0;
 		runLength = *(pbOrderHdr + 1) + 1;
 		(*advance)++;
@@ -220,7 +220,7 @@ static UINT ExtractRunLengthMegaMega(const BYTE* pbOrderHdr, const BYTE* pbEnd,
 	WINPR_ASSERT(pbEnd);
 	WINPR_ASSERT(advance);
 
-	if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
+	if (!buffer_within_range(pbOrderHdr, 3, pbEnd))
 		return 0;
 
 	runLength = ((UINT16)pbOrderHdr[1]) | (((UINT16)pbOrderHdr[2]) << 8);
-- 
2.45.0


From b509f23ca74de4f1d14cb6530ffc9951d324c8a3 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Tue, 16 Apr 2024 08:47:31 +0200
Subject: [PATCH 7/7] [codec,interleaved] fix off by one length check

---
 libfreerdp/codec/interleaved.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c
index f41cf26dd..35a1fa7af 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -181,7 +181,7 @@ static UINT ExtractRunLengthLiteFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd,
 	runLength = *pbOrderHdr & g_MaskLiteRunLength;
 	if (runLength == 0)
 	{
-		if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
+		if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
 			return 0;
 		runLength = *(pbOrderHdr + 1) + 1;
 		(*advance)++;
-- 
2.45.0

openSUSE Build Service is sponsored by