File freerdp-CVE-2024-32658.patch of Package freerdp.34024
From fd13cf3986d5e33e40f59952ade48d39b42b294f 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 | 19 ++++++++++++++++++-
2 files changed, 24 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 223cb71fc..d565523bb 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -129,7 +129,8 @@ 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;
@@ -138,6 +139,8 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3
WINPR_ASSERT(pbOrderHdr);
WINPR_ASSERT(advance);
+ if (pbOrderHdr >= pbEnd)
+ return 0;
switch (code)
{
@@ -146,6 +149,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;
}
@@ -161,6 +166,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;
}
@@ -180,6 +188,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;
}
@@ -193,6 +204,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;
}
@@ -207,6 +221,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 9967c37269e0b198b342ce7baa0ebca5c0cfc085 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 | 75 ++++++++++++++++++++++++++-----
2 files changed, 84 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 d565523bb..88484a2e9 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -99,6 +99,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.
@@ -138,8 +152,10 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const
runLength = 0;
WINPR_ASSERT(pbOrderHdr);
+ WINPR_ASSERT(pbEnd);
WINPR_ASSERT(advance);
- if (pbOrderHdr >= pbEnd)
+
+ if (!buffer_within_range(pbOrderHdr, pbEnd))
return 0;
switch (code)
@@ -149,7 +165,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;
@@ -166,7 +182,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;
@@ -188,7 +204,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;
@@ -204,7 +220,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;
@@ -221,7 +237,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));
@@ -233,20 +249,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);
@@ -254,6 +282,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;
}
@@ -361,7 +390,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)
{
@@ -386,7 +419,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;
}
@@ -399,14 +432,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;
@@ -414,24 +453,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 906804f62ba54aad64361a337a0d4534b4d8ca29 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 88484a2e9..5b1c55733 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -143,6 +143,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)
{
@@ -161,72 +261,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:
@@ -237,11 +288,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 3b7abc95f53e42ba065d26b69f465ed90b7201f3 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 5b1c55733..e6555ccdc 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -39,7 +39,9 @@
for (x = 0; x < (_count); x++) \
{ \
do \
- _exp while (FALSE); \
+ { \
+ _exp \
+ } while (FALSE); \
} \
} while (FALSE)
@@ -99,15 +101,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;
@@ -154,7 +160,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)++;
@@ -176,7 +182,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)++;
@@ -198,7 +204,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)++;
@@ -215,7 +221,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);
@@ -235,7 +241,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)++;
@@ -255,7 +261,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)
@@ -347,6 +353,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 \
@@ -378,6 +388,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 \
@@ -408,7 +422,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 f33ffc8e5a350c6bf1f41b5d5973b26a34c34950 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 085aaae49ec3cc6c044d53dd746d412975a277fd 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 e6555ccdc..a35e0ba4a 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -160,7 +160,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)++;
@@ -221,7 +221,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 3c4b34cb61685aa05cd58974c992cb05330797b5 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 a35e0ba4a..aa29959ef 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -182,7 +182,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