File freerdp-CVE-2023-39350-to-2023-40589.patch of Package freerdp.33721
From a075d6fdf4a9ba19cda46240796e78bcf788e49b Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Fri, 4 Aug 2023 13:55:40 +0200
Subject: [PATCH 01/14] [codec,rfx] fix possible out of bound read
Allows malicious servers to crash FreeRDP based clients
reported by @pwn2carr
---
libfreerdp/codec/rfx.c | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c
index 8c65e7508..5dca1d84f 100644
--- a/libfreerdp/codec/rfx.c
+++ b/libfreerdp/codec/rfx.c
@@ -1019,10 +1019,8 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length,
UINT32 top, BYTE* dst, UINT32 dstFormat, UINT32 dstStride,
UINT32 dstHeight, REGION16* invalidRegion)
{
- REGION16 updateRegion;
- UINT32 blockLen;
- UINT32 blockType;
- wStream inStream, *s = &inStream;
+ REGION16 updateRegion = { 0 };
+ wStream inStream = { 0 }, *s = &inStream;
BOOL ok = TRUE;
RFX_MESSAGE* message;
@@ -1037,8 +1035,10 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length,
while (ok && Stream_GetRemainingLength(s) > 6)
{
- wStream subStream;
+ wStream subStream = { 0 };
size_t extraBlockLen = 0;
+ UINT32 blockLen = 0;
+ UINT32 blockType = 0;
/* RFX_BLOCKT */
Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
@@ -1067,8 +1067,8 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length,
if (blockType >= WBT_CONTEXT && blockType <= WBT_EXTENSION)
{
/* RFX_CODEC_CHANNELT */
- UINT8 codecId;
- UINT8 channelId;
+ UINT8 codecId = 0;
+ UINT8 channelId = 0;
if (Stream_GetRemainingLength(s) < 2)
return FALSE;
@@ -1106,8 +1106,18 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length,
}
}
- Stream_StaticInit(&subStream, Stream_Pointer(s), blockLen - (6 + extraBlockLen));
- Stream_Seek(s, blockLen - (6 + extraBlockLen));
+ const size_t blockLenNoHeader = blockLen - 6;
+ if (blockLenNoHeader < extraBlockLen)
+ {
+ WLog_Print(context->priv->log, WLOG_ERROR,
+ "blockLen too small(%" PRIu32 "), must be >= 6 + %" PRIu16, blockLen,
+ extraBlockLen);
+ return FALSE;
+ }
+
+ const size_t subStreamLen = blockLenNoHeader - extraBlockLen;
+ Stream_StaticInit(&subStream, Stream_Pointer(s), subStreamLen);
+ Stream_Seek(s, subStreamLen);
switch (blockType)
{
--
2.42.1
From 30138992df674058269bff30200ca18f68463572 Mon Sep 17 00:00:00 2001
From: Armin Novak <anovak@thincast.com>
Date: Sat, 5 Aug 2023 09:29:19 +0200
Subject: [PATCH 02/14] [codec,rfx] free content of currentMessage on fail
---
libfreerdp/codec/rfx.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c
index 5dca1d84f..b6f38b17c 100644
--- a/libfreerdp/codec/rfx.c
+++ b/libfreerdp/codec/rfx.c
@@ -1235,6 +1235,11 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length,
region16_uninit(&clippingRects);
return TRUE;
}
+ else
+ {
+ rfx_message_free(context, message);
+ context->currentMessage.freeArray = TRUE;
+ }
return FALSE;
}
--
2.42.1
From 9e5b4ae2df290f2958d86cf2477dd809a7455213 Mon Sep 17 00:00:00 2001
From: Armin Novak <anovak@thincast.com>
Date: Fri, 4 Aug 2023 16:42:05 +0200
Subject: [PATCH 03/14] [codec,color] fix freerdp_image_fill
in case width or height == 0 out of bounds write might happen.
reported by @pwn2carr
---
libfreerdp/codec/color.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c
index edbfcd4ed..0afe98283 100644
--- a/libfreerdp/codec/color.c
+++ b/libfreerdp/codec/color.c
@@ -728,18 +728,25 @@ BOOL freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32
BOOL freerdp_image_fill(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst,
UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 color)
{
- UINT32 x, y;
+ if ((nWidth == 0) || (nHeight == 0))
+ return TRUE;
const UINT32 bpp = GetBytesPerPixel(DstFormat);
- BYTE* pFirstDstLine = &pDstData[nYDst * nDstStep];
- BYTE* pFirstDstLineXOffset = &pFirstDstLine[nXDst * bpp];
+ BYTE* pFirstDstLine;
+ BYTE* pFirstDstLineXOffset;
+
+ if (nDstStep == 0)
+ nDstStep = (nXDst + nWidth) * GetBytesPerPixel(DstFormat);
+
+ pFirstDstLine = &pDstData[nYDst * nDstStep];
+ pFirstDstLineXOffset = &pFirstDstLine[nXDst * bpp];
- for (x = 0; x < nWidth; x++)
+ for (UINT32 x = 0; x < nWidth; x++)
{
BYTE* pDst = &pFirstDstLine[(x + nXDst) * bpp];
WriteColor(pDst, DstFormat, color);
}
- for (y = 1; y < nHeight; y++)
+ for (UINT32 y = 1; y < nHeight; y++)
{
BYTE* pDstLine = &pDstData[(y + nYDst) * nDstStep + nXDst * bpp];
memcpy(pDstLine, pFirstDstLineXOffset, nWidth * bpp * 1ULL);
--
2.42.1
From e5c95d739caea26ba0d5a98d3fa3d301f7b6a68c Mon Sep 17 00:00:00 2001
From: Armin Novak <anovak@thincast.com>
Date: Sat, 5 Aug 2023 08:57:28 +0200
Subject: [PATCH 04/14] [coded,rfx] check indices are within range
reported by @pwn2carr
---
libfreerdp/codec/rfx.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c
index b6f38b17c..cb544cac4 100644
--- a/libfreerdp/codec/rfx.c
+++ b/libfreerdp/codec/rfx.c
@@ -936,6 +936,29 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa
Stream_Read_UINT8(&sub, tile->quantIdxY); /* quantIdxY (1 byte) */
Stream_Read_UINT8(&sub, tile->quantIdxCb); /* quantIdxCb (1 byte) */
Stream_Read_UINT8(&sub, tile->quantIdxCr); /* quantIdxCr (1 byte) */
+
+ if (tile->quantIdxY >= context->numQuant)
+ {
+ WLog_Print(context->priv->log, WLOG_ERROR, "quantIdxY %" PRIu8 " >= numQuant %" PRIu8,
+ tile->quantIdxY, context->numQuant);
+ rc = FALSE;
+ break;
+ }
+ if (tile->quantIdxCb >= context->numQuant)
+ {
+ WLog_Print(context->priv->log, WLOG_ERROR, "quantIdxCb %" PRIu8 " >= numQuant %" PRIu8,
+ tile->quantIdxCb, context->numQuant);
+ rc = FALSE;
+ break;
+ }
+ if (tile->quantIdxCr >= context->numQuant)
+ {
+ WLog_Print(context->priv->log, WLOG_ERROR, "quantIdxCr %" PRIu8 " >= numQuant %" PRIu8,
+ tile->quantIdxCr, context->numQuant);
+ rc = FALSE;
+ break;
+ }
+
Stream_Read_UINT16(&sub, tile->xIdx); /* xIdx (2 bytes) */
Stream_Read_UINT16(&sub, tile->yIdx); /* yIdx (2 bytes) */
Stream_Read_UINT16(&sub, tile->YLen); /* YLen (2 bytes) */
--
2.42.1
From df1a0813ab8aeebb3256dff7645f1b8e7e383809 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Tue, 22 Aug 2023 10:48:57 +0200
Subject: [PATCH 05/14] [codec,nsc] fix input length validation
---
libfreerdp/codec/nsc.c | 39 +++++++++++++++++++++++++++++++-----
libfreerdp/codec/nsc_types.h | 1 +
2 files changed, 35 insertions(+), 5 deletions(-)
diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c
index dc3a978ed..b3a7aece6 100644
--- a/libfreerdp/codec/nsc.c
+++ b/libfreerdp/codec/nsc.c
@@ -29,6 +29,7 @@
#include <string.h>
#include <winpr/crt.h>
+#include <winpr/assert.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/codec/color.h>
@@ -111,12 +112,17 @@ static BOOL nsc_decode(NSC_CONTEXT* context)
return TRUE;
}
-static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalSize)
+static BOOL nsc_rle_decode(const BYTE* in, size_t inSize, BYTE* out, UINT32 outSize,
+ UINT32 originalSize)
{
UINT32 left = originalSize;
while (left > 4)
{
+ if (inSize < 1)
+ return FALSE;
+ inSize--;
+
const BYTE value = *in++;
UINT32 len = 0;
@@ -129,17 +135,26 @@ static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalS
*out++ = value;
left--;
}
+ else if (inSize < 1)
+ return FALSE;
else if (value == *in)
{
+ inSize--;
in++;
- if (*in < 0xFF)
+ if (inSize < 1)
+ return FALSE;
+ else if (*in < 0xFF)
{
+ inSize--;
len = (UINT32)*in++;
len += 2;
}
else
{
+ if (inSize < 5)
+ return FALSE;
+ inSize -= 5;
in++;
len = ((UINT32)(*in++));
len |= ((UINT32)(*in++)) << 8U;
@@ -169,6 +184,8 @@ static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalS
if ((outSize < 4) || (left < 4))
return FALSE;
+ if (inSize < 4)
+ return FALSE;
memcpy(out, in, 4);
return TRUE;
}
@@ -184,12 +201,17 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context)
return FALSE;
rle = context->Planes;
+ size_t rleSize = context->PlanesSize;
+ WINPR_ASSERT(rle);
for (i = 0; i < 4; i++)
{
originalSize = context->OrgByteCount[i];
planeSize = context->PlaneByteCount[i];
+ if (rleSize < planeSize)
+ return FALSE;
+
if (planeSize == 0)
{
if (context->priv->PlaneBuffersLength < originalSize)
@@ -199,7 +221,7 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context)
}
else if (planeSize < originalSize)
{
- if (!nsc_rle_decode(rle, context->priv->PlaneBuffers[i],
+ if (!nsc_rle_decode(rle, rleSize, context->priv->PlaneBuffers[i],
context->priv->PlaneBuffersLength, originalSize))
return FALSE;
}
@@ -208,6 +230,9 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context)
if (context->priv->PlaneBuffersLength < originalSize)
return FALSE;
+ if (rleSize < originalSize)
+ return FALSE;
+
CopyMemory(context->priv->PlaneBuffers[i], rle, originalSize);
}
@@ -224,14 +249,18 @@ static BOOL nsc_stream_initialize(NSC_CONTEXT* context, wStream* s)
if (Stream_GetRemainingLength(s) < 20)
return FALSE;
- for (i = 0; i < 4; i++)
+ size_t total = 0;
+ for (i = 0; i < 4; i++) {
Stream_Read_UINT32(s, context->PlaneByteCount[i]);
+ total += context->PlaneByteCount[i];
+ }
Stream_Read_UINT8(s, context->ColorLossLevel); /* ColorLossLevel (1 byte) */
Stream_Read_UINT8(s, context->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */
Stream_Seek(s, 2); /* Reserved (2 bytes) */
context->Planes = Stream_Pointer(s);
- return TRUE;
+ context->PlanesSize = total;
+ return Stream_GetRemainingLength(s) >= total;
}
static BOOL nsc_context_initialize(NSC_CONTEXT* context, wStream* s)
diff --git a/libfreerdp/codec/nsc_types.h b/libfreerdp/codec/nsc_types.h
index 14c1a946b..5a6506bae 100644
--- a/libfreerdp/codec/nsc_types.h
+++ b/libfreerdp/codec/nsc_types.h
@@ -61,6 +61,7 @@ struct _NSC_CONTEXT
UINT32 BitmapDataLength;
BYTE* Planes;
+ size_t PlanesSize;
UINT32 PlaneByteCount[4];
UINT32 ColorLossLevel;
UINT32 ChromaSubsamplingLevel;
--
2.42.1
From 29a79e156a5e7cc3fdb83d7842ed8e9c544944b1 Mon Sep 17 00:00:00 2001
From: Armin Novak <anovak@thincast.com>
Date: Sat, 5 Aug 2023 11:31:08 +0200
Subject: [PATCH 06/14] [core,orders] fix checks for multi opaque rect
---
libfreerdp/core/orders.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c
index a97683395..82acacd23 100644
--- a/libfreerdp/core/orders.c
+++ b/libfreerdp/core/orders.c
@@ -27,6 +27,7 @@
#include <winpr/wtypes.h>
#include <winpr/crt.h>
+#include <winpr/assert.h>
#include <freerdp/api.h>
#include <freerdp/log.h>
@@ -1390,7 +1391,7 @@ static BOOL update_read_multi_dstblt_order(wStream* s, const ORDER_INFO* orderIn
return update_read_delta_rects(s, multi_dstblt->rectangles, &multi_dstblt->numRectangles);
}
- return TRUE;
+ return multi_dstblt->numRectangles == 0;
}
static BOOL update_read_multi_patblt_order(wStream* s, const ORDER_INFO* orderInfo,
MULTI_PATBLT_ORDER* multi_patblt)
@@ -1420,12 +1421,18 @@ static BOOL update_read_multi_patblt_order(wStream* s, const ORDER_INFO* orderIn
if (!update_read_delta_rects(s, multi_patblt->rectangles, &multi_patblt->numRectangles))
return FALSE;
}
+ else if (multi_patblt->numRectangles != 0)
+ return FALSE;
return TRUE;
}
static BOOL update_read_multi_scrblt_order(wStream* s, const ORDER_INFO* orderInfo,
MULTI_SCRBLT_ORDER* multi_scrblt)
{
+ WINPR_ASSERT(orderInfo);
+ WINPR_ASSERT(multi_scrblt);
+
+ multi_scrblt->numRectangles = 0;
if (!read_order_field_coord(orderInfo, s, 1, &multi_scrblt->nLeftRect, FALSE) ||
!read_order_field_coord(orderInfo, s, 2, &multi_scrblt->nTopRect, FALSE) ||
!read_order_field_coord(orderInfo, s, 3, &multi_scrblt->nWidth, FALSE) ||
@@ -1445,7 +1452,7 @@ static BOOL update_read_multi_scrblt_order(wStream* s, const ORDER_INFO* orderIn
return update_read_delta_rects(s, multi_scrblt->rectangles, &multi_scrblt->numRectangles);
}
- return TRUE;
+ return multi_scrblt->numRectangles == 0;
}
static BOOL update_read_multi_opaque_rect_order(wStream* s, const ORDER_INFO* orderInfo,
MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
@@ -1497,7 +1504,7 @@ static BOOL update_read_multi_opaque_rect_order(wStream* s, const ORDER_INFO* or
&multi_opaque_rect->numRectangles);
}
- return TRUE;
+ return multi_opaque_rect->numRectangles == 0;
}
static BOOL update_read_multi_draw_nine_grid_order(wStream* s, const ORDER_INFO* orderInfo,
MULTI_DRAW_NINE_GRID_ORDER* multi_draw_nine_grid)
@@ -1520,7 +1527,7 @@ static BOOL update_read_multi_draw_nine_grid_order(wStream* s, const ORDER_INFO*
&multi_draw_nine_grid->nDeltaEntries);
}
- return TRUE;
+ return multi_draw_nine_grid->nDeltaEntries == 0;
}
static BOOL update_read_line_to_order(wStream* s, const ORDER_INFO* orderInfo,
LINE_TO_ORDER* line_to)
--
2.42.1
From b7c84b4e3e840393e33ed04b6199bc75d8ffe22f Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Mon, 21 Aug 2023 14:30:11 +0200
Subject: [PATCH 07/14] [codec,zgfx] fix cBitsRemaining calculation
fixed out of bound read reported by @pwn2carr
---
libfreerdp/codec/zgfx.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c
index 04ddeadb2..4489b3798 100644
--- a/libfreerdp/codec/zgfx.c
+++ b/libfreerdp/codec/zgfx.c
@@ -259,7 +259,11 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t
zgfx->pbInputCurrent = pbSegment;
zgfx->pbInputEnd = &pbSegment[cbSegment - 1];
/* NumberOfBitsToDecode = ((NumberOfBytesToDecode - 1) * 8) - ValueOfLastByte */
- zgfx->cBitsRemaining = 8 * (cbSegment - 1) - *zgfx->pbInputEnd;
+ const UINT32 bits = 8u * (cbSegment - 1u);
+ if (bits < *zgfx->pbInputEnd)
+ return FALSE;
+
+ zgfx->cBitsRemaining = bits - *zgfx->pbInputEnd;
zgfx->cBitsCurrent = 0;
zgfx->BitsCurrent = 0;
--
2.42.1
From 87ab44058280d44fa08a4459c71893ad8f5b243c Mon Sep 17 00:00:00 2001
From: Youkou Tenhouin <youkou@tenhou.in>
Date: Tue, 14 Nov 2023 14:00:46 +0800
Subject: [PATCH 08/14] SLE: fix CVE-2023-40186
---
libfreerdp/gdi/gfx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c
index a3b7505c5..4a639025e 100644
--- a/libfreerdp/gdi/gfx.c
+++ b/libfreerdp/gdi/gfx.c
@@ -1025,7 +1025,7 @@ static UINT gdi_CreateSurface(RdpgfxClientContext* context,
}
surface->scanline = gfx_align_scanline(surface->width * 4UL, 16);
- surface->data = (BYTE*)_aligned_malloc(surface->scanline * surface->height * 1ULL, 16);
+ surface->data = (BYTE*)_aligned_malloc(1ull * surface->scanline * surface->height, 16);
if (!surface->data)
{
--
2.42.1
From 318497da3ec4085b3568562a93044f2a638a296f Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Tue, 22 Aug 2023 10:48:57 +0200
Subject: [PATCH 09/14] [codec,nsc] fix input length validation
---
libfreerdp/codec/nsc.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c
index b3a7aece6..283e74688 100644
--- a/libfreerdp/codec/nsc.c
+++ b/libfreerdp/codec/nsc.c
@@ -209,6 +209,9 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context)
originalSize = context->OrgByteCount[i];
planeSize = context->PlaneByteCount[i];
+ if (rleSize < planeSize)
+ return FALSE;
+
if (rleSize < planeSize)
return FALSE;
--
2.42.1
From 2466fae284a93d2d06bc086f3d7f43ea135f6112 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Tue, 22 Aug 2023 14:44:57 +0200
Subject: [PATCH 10/14] [codec,clear] fix missing bounds checks
---
libfreerdp/codec/clear.c | 46 +++++++++++++++++++++-------------------
1 file changed, 24 insertions(+), 22 deletions(-)
diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c
index fadd98e67..ddc385b47 100644
--- a/libfreerdp/codec/clear.c
+++ b/libfreerdp/codec/clear.c
@@ -591,13 +591,9 @@ static BOOL resize_vbar_entry(CLEAR_CONTEXT* clear, CLEAR_VBAR_ENTRY* vBarEntry)
static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 bandsByteCount,
UINT32 nWidth, UINT32 nHeight, BYTE* pDstData,
UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst,
- UINT32 nYDst)
+ UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight)
{
- UINT32 i, y;
- UINT32 count;
- UINT32 suboffset;
- UINT32 nXDstRel;
- UINT32 nYDstRel;
+ UINT32 suboffset = 0;
if (Stream_GetRemainingLength(s) < bandsByteCount)
{
@@ -605,8 +601,6 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32
return FALSE;
}
- suboffset = 0;
-
while (suboffset < bandsByteCount)
{
BYTE r, g, b;
@@ -652,7 +646,7 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32
vBarCount = (xEnd - xStart) + 1;
- for (i = 0; i < vBarCount; i++)
+ for (UINT32 i = 0; i < vBarCount; i++)
{
UINT32 vBarHeight;
CLEAR_VBAR_ENTRY* vBarEntry = NULL;
@@ -740,11 +734,12 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32
if (!resize_vbar_entry(clear, vBarShortEntry))
return FALSE;
- for (y = 0; y < vBarShortPixelCount; y++)
+ for (UINT32 y = 0; y < vBarShortPixelCount; y++)
{
- BYTE r, g, b;
- BYTE* dstBuffer = &vBarShortEntry->pixels[y * GetBytesPerPixel(clear->format)];
- UINT32 color;
+ BYTE r = 0, g = 0, b = 0;
+ BYTE* dstBuffer =
+ &vBarShortEntry->pixels[y * GetBytesPerPixel(clear->format)];
+ UINT32 color = 0;
Stream_Read_UINT8(s, b);
Stream_Read_UINT8(s, g);
Stream_Read_UINT8(s, r);
@@ -804,8 +799,8 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32
dstBuffer = vBarEntry->pixels;
/* if (y < vBarYOn), use colorBkg */
- y = 0;
- count = vBarYOn;
+ UINT32 y = 0;
+ UINT32 count = vBarYOn;
if ((y + count) > vBarPixelCount)
count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
@@ -868,21 +863,28 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32
return FALSE;
}
- nXDstRel = nXDst + xStart;
- nYDstRel = nYDst + yStart;
+ const UINT32 nXDstRel = nXDst + xStart;
+ const UINT32 nYDstRel = nYDst + yStart;
pSrcPixel = vBarEntry->pixels;
if (i < nWidth)
{
- count = vBarEntry->count;
+ UINT32 count = vBarEntry->count;
if (count > nHeight)
count = nHeight;
- for (y = 0; y < count; y++)
+ if (nXDstRel + i > nDstWidth)
+ return FALSE;
+
+ for (UINT32 y = 0; y < count; y++)
{
- BYTE* pDstPixel8 = &pDstData[((nYDstRel + y) * nDstStep) +
- ((nXDstRel + i) * GetBytesPerPixel(DstFormat))];
+ if (nYDstRel + y > nDstHeight)
+ return FALSE;
+
+ BYTE* pDstPixel8 =
+ &pDstData[((nYDstRel + y) * nDstStep) +
+ ((nXDstRel + i) * GetBytesPerPixel(DstFormat))];
UINT32 color = ReadColor(pSrcPixel, clear->format);
color = FreeRDPConvertColor(color, clear->format, DstFormat, NULL);
@@ -1117,7 +1119,7 @@ INT32 clear_decompress(CLEAR_CONTEXT* clear, const BYTE* pSrcData, UINT32 SrcSiz
if (bandsByteCount > 0)
{
if (!clear_decompress_bands_data(clear, s, bandsByteCount, nWidth, nHeight, pDstData,
- DstFormat, nDstStep, nXDst, nYDst))
+ DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight))
{
WLog_ERR(TAG, "clear_decompress_bands_data failed!");
goto fail;
--
2.42.1
From 351357eb35017e3e43e83941bc4d93661bdb8ee8 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Tue, 22 Aug 2023 15:05:20 +0200
Subject: [PATCH 11/14] [codec,progressive] fix missing destination checks
---
libfreerdp/codec/progressive.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c
index 08b8199e7..71da854f8 100644
--- a/libfreerdp/codec/progressive.c
+++ b/libfreerdp/codec/progressive.c
@@ -2396,11 +2396,17 @@ INT32 progressive_decompress_ex(PROGRESSIVE_CONTEXT* progressive, const BYTE* pS
for (j = 0; j < nbUpdateRects; j++)
{
const RECTANGLE_16* rect = &updateRects[j];
- const UINT32 nXSrc = rect->left - (nXDst + tile->x);
- const UINT32 nYSrc = rect->top - (nYDst + tile->y);
+ if (rect->left < updateRect.left)
+ goto fail;
+ const UINT32 nXSrc = rect->left - updateRect.left;
+ const UINT32 nYSrc = rect->top - updateRect.top;
const UINT32 width = rect->right - rect->left;
const UINT32 height = rect->bottom - rect->top;
+ if (rect->left + width > surface->width)
+ goto fail;
+ if (rect->top + height > surface->height)
+ goto fail;
if (!freerdp_image_copy(pDstData, DstFormat, nDstStep, rect->left, rect->top, width,
height, tile->data, progressive->format, tile->stride, nXSrc,
nYSrc, NULL, FREERDP_FLIP_NONE))
--
2.42.1
From 9370739bad26420f8ca43d36519c0dad4dca2558 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Wed, 23 Aug 2023 08:38:23 +0200
Subject: [PATCH 12/14] [primitives,yuv] clean up code, assert arguments
---
libfreerdp/primitives/prim_YUV.c | 32 ++++++++++++++++++++------------
1 file changed, 20 insertions(+), 12 deletions(-)
diff --git a/libfreerdp/primitives/prim_YUV.c b/libfreerdp/primitives/prim_YUV.c
index 0bca4befe..4b871e387 100644
--- a/libfreerdp/primitives/prim_YUV.c
+++ b/libfreerdp/primitives/prim_YUV.c
@@ -30,6 +30,8 @@
#include <freerdp/codec/color.h>
#include "prim_internal.h"
+#include <winpr/assert.h>
+
static pstatus_t general_LumaToYUV444(const BYTE* const pSrcRaw[3], const UINT32 srcStep[3],
BYTE* pDstRaw[3], const UINT32 dstStep[3],
const RECTANGLE_16* roi)
@@ -382,21 +384,24 @@ static pstatus_t general_YUV444ToRGB_8u_P3AC4R_general(const BYTE* const pSrc[3]
UINT32 dstStep, UINT32 DstFormat,
const prim_size_t* roi)
{
- UINT32 x, y;
- UINT32 nWidth, nHeight;
const DWORD formatSize = GetBytesPerPixel(DstFormat);
fkt_writePixel writePixel = getPixelWriteFunction(DstFormat, FALSE);
- nWidth = roi->width;
- nHeight = roi->height;
- for (y = 0; y < nHeight; y++)
+ WINPR_ASSERT(pSrc);
+ WINPR_ASSERT(pDst);
+ WINPR_ASSERT(roi);
+
+ const UINT32 nWidth = roi->width;
+ const UINT32 nHeight = roi->height;
+
+ for (UINT32 y = 0; y < nHeight; y++)
{
const BYTE* pY = pSrc[0] + y * srcStep[0];
const BYTE* pU = pSrc[1] + y * srcStep[1];
const BYTE* pV = pSrc[2] + y * srcStep[2];
BYTE* pRGB = pDst + y * dstStep;
- for (x = 0; x < nWidth; x++)
+ for (UINT32 x = 0; x < nWidth; x++)
{
const BYTE Y = pY[x];
const BYTE U = pU[x];
@@ -416,20 +421,23 @@ static pstatus_t general_YUV444ToRGB_8u_P3AC4R_BGRX(const BYTE* const pSrc[3],
UINT32 dstStep, UINT32 DstFormat,
const prim_size_t* roi)
{
- UINT32 x, y;
- UINT32 nWidth, nHeight;
const DWORD formatSize = GetBytesPerPixel(DstFormat);
- nWidth = roi->width;
- nHeight = roi->height;
- for (y = 0; y < nHeight; y++)
+ WINPR_ASSERT(pSrc);
+ WINPR_ASSERT(pDst);
+ WINPR_ASSERT(roi);
+
+ const UINT32 nWidth = roi->width;
+ const UINT32 nHeight = roi->height;
+
+ for (UINT32 y = 0; y < nHeight; y++)
{
const BYTE* pY = pSrc[0] + y * srcStep[0];
const BYTE* pU = pSrc[1] + y * srcStep[1];
const BYTE* pV = pSrc[2] + y * srcStep[2];
BYTE* pRGB = pDst + y * dstStep;
- for (x = 0; x < nWidth; x++)
+ for (UINT32 x = 0; x < nWidth; x++)
{
const BYTE Y = pY[x];
const BYTE U = pU[x];
--
2.42.1
From 1b81dc470d31956d5ace1313fee0ba26d4c39ac1 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Wed, 23 Aug 2023 09:24:00 +0200
Subject: [PATCH 13/14] [codec,interleaved] fix bounds checks
---
libfreerdp/codec/include/bitmap.c | 54 ++++++++++-----------------
libfreerdp/codec/interleaved.c | 61 ++++++++++++++++++++++---------
2 files changed, 63 insertions(+), 52 deletions(-)
diff --git a/libfreerdp/codec/include/bitmap.c b/libfreerdp/codec/include/bitmap.c
index 38bcaa859..355c697e0 100644
--- a/libfreerdp/codec/include/bitmap.c
+++ b/libfreerdp/codec/include/bitmap.c
@@ -46,7 +46,6 @@ static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 r
data = xorPixel;
DESTWRITEPIXEL(pbDest, data);
- DESTNEXTPIXEL(pbDest);
mask = mask << 1;
});
return pbDest;
@@ -76,7 +75,6 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd,
data = BLACK_PIXEL;
DESTWRITEPIXEL(pbDest, data);
- DESTNEXTPIXEL(pbDest);
mask = mask << 1;
});
return pbDest;
@@ -134,6 +132,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
if (code == REGULAR_BG_RUN || code == MEGA_MEGA_BG_RUN)
{
runLength = ExtractRunLength(code, pbSrc, &advance);
+ if (advance == 0)
+ return FALSE;
pbSrc = pbSrc + advance;
if (fFirstLine)
@@ -144,17 +144,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 +162,6 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
return FALSE;
DESTWRITEPIXEL(pbDest, temp ^ fgPel);
- DESTNEXTPIXEL(pbDest);
runLength--;
}
@@ -176,7 +171,6 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
UNROLL(runLength, {
DESTREADPIXEL(temp, pbDest - rowDelta);
DESTWRITEPIXEL(pbDest, temp);
- DESTNEXTPIXEL(pbDest);
});
}
@@ -197,14 +191,15 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
case LITE_SET_FG_FG_RUN:
case MEGA_MEGA_SET_FG_RUN:
runLength = ExtractRunLength(code, pbSrc, &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 (pbSrc + sizeof(fgPel) >= pbEnd)
return FALSE;
SRCREADPIXEL(fgPel, pbSrc);
- SRCNEXTPIXEL(pbSrc);
}
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
@@ -212,17 +207,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);
});
}
@@ -232,24 +223,22 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
case LITE_DITHERED_RUN:
case MEGA_MEGA_DITHERED_RUN:
runLength = ExtractRunLength(code, pbSrc, &advance);
+ if (advance == 0)
+ return FALSE;
pbSrc = pbSrc + advance;
- if (pbSrc >= pbEnd)
+ if (pbSrc + sizeof(pixelA) >= pbEnd)
return FALSE;
SRCREADPIXEL(pixelA, pbSrc);
- SRCNEXTPIXEL(pbSrc);
- if (pbSrc >= pbEnd)
+ if (pbSrc + sizeof(pixelB) >= 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;
@@ -257,19 +246,17 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
case REGULAR_COLOR_RUN:
case MEGA_MEGA_COLOR_RUN:
runLength = ExtractRunLength(code, pbSrc, &advance);
+ if (advance == 0)
+ return FALSE;
pbSrc = pbSrc + advance;
- if (pbSrc >= pbEnd)
+ if (pbSrc + sizeof(pixelA) >= 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. */
@@ -278,14 +265,15 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
case LITE_SET_FG_FGBG_IMAGE:
case MEGA_MEGA_SET_FGBG_IMAGE:
runLength = ExtractRunLength(code, pbSrc, &advance);
+ if (advance == 0)
+ return FALSE;
pbSrc = pbSrc + advance;
- if (pbSrc >= pbEnd)
+ if (pbSrc + sizeof(fgPel) >= pbEnd)
return FALSE;
if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
{
SRCREADPIXEL(fgPel, pbSrc);
- SRCNEXTPIXEL(pbSrc);
}
if (fFirstLine)
@@ -343,6 +331,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
case REGULAR_COLOR_IMAGE:
case MEGA_MEGA_COLOR_IMAGE:
runLength = ExtractRunLength(code, pbSrc, &advance);
+ if (advance == 0)
+ return FALSE;
pbSrc = pbSrc + advance;
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
return FALSE;
@@ -351,9 +341,7 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
if (pbSrc >= pbEnd)
return FALSE;
SRCREADPIXEL(temp, pbSrc);
- SRCNEXTPIXEL(pbSrc);
DESTWRITEPIXEL(pbDest, temp);
- DESTNEXTPIXEL(pbDest);
});
break;
@@ -405,7 +393,6 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
return FALSE;
DESTWRITEPIXEL(pbDest, WHITE_PIXEL);
- DESTNEXTPIXEL(pbDest);
break;
/* Handle Black Order. */
@@ -416,7 +403,6 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
return FALSE;
DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
- DESTNEXTPIXEL(pbDest);
break;
default:
diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c
index b76fe1ca3..223cb71fc 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -25,6 +25,8 @@
#include "config.h"
#endif
+#include <winpr/assert.h>
+
#include <freerdp/codec/interleaved.h>
#include <freerdp/log.h>
@@ -134,6 +136,9 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3
ladvance = 1;
runLength = 0;
+ WINPR_ASSERT(pbOrderHdr);
+ WINPR_ASSERT(advance);
+
switch (code)
{
case REGULAR_FGBG_IMAGE:
@@ -239,19 +244,26 @@ 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 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 +275,25 @@ 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 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 +305,26 @@ 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)
+#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
--
2.42.1
From ef2286eb5ede9d8e42a4c7b39b06a538010b0fe1 Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Mon, 28 Aug 2023 09:06:42 +0200
Subject: [PATCH 14/14] [codec,ncrush] fix index checks
properly verify all offsets while decoding data.
---
libfreerdp/codec/ncrush.c | 141 ++++++++++++++++++++++++++++++--------
1 file changed, 112 insertions(+), 29 deletions(-)
diff --git a/libfreerdp/codec/ncrush.c b/libfreerdp/codec/ncrush.c
index 3d6a216d3..545ff2a54 100644
--- a/libfreerdp/codec/ncrush.c
+++ b/libfreerdp/codec/ncrush.c
@@ -23,6 +23,7 @@
#include "config.h"
#endif
+#include <winpr/assert.h>
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/bitstream.h>
@@ -1994,15 +1995,9 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
UINT32* pDstSize, UINT32 flags)
{
UINT32 index;
- UINT32 bits;
- INT32 nbits;
- const BYTE* SrcPtr;
- const BYTE* SrcEnd;
- UINT16 Mask;
BYTE Literal;
UINT32 IndexLEC;
UINT32 BitLength;
- UINT32 MaskedBits;
UINT32 CopyOffset;
UINT32 CopyLength;
UINT32 OldCopyOffset;
@@ -2010,9 +2005,6 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
UINT32 LengthOfMatch;
UINT32 CopyOffsetIndex;
UINT32 OffsetCacheIndex;
- BYTE* HistoryPtr;
- BYTE* HistoryBuffer;
- BYTE* HistoryBufferEnd;
UINT32 CopyOffsetBits;
UINT32 CopyOffsetBase;
UINT32 LengthOfMatchBits;
@@ -2021,8 +2013,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
if (ncrush->HistoryEndOffset != 65535)
return -1001;
- HistoryBuffer = ncrush->HistoryBuffer;
- HistoryBufferEnd = &HistoryBuffer[ncrush->HistoryEndOffset];
+ BYTE* HistoryBuffer = ncrush->HistoryBuffer;
+ const BYTE* HistoryBufferEnd = &HistoryBuffer[ncrush->HistoryEndOffset];
if (flags & PACKET_AT_FRONT)
{
@@ -2041,7 +2033,7 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
ZeroMemory(&(ncrush->OffsetCache), sizeof(ncrush->OffsetCache));
}
- HistoryPtr = ncrush->HistoryPtr;
+ BYTE* HistoryPtr = ncrush->HistoryPtr;
if (!(flags & PACKET_COMPRESSED))
{
@@ -2050,17 +2042,19 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
return 1;
}
- SrcEnd = &pSrcData[SrcSize];
- nbits = 32;
- bits = get_dword(pSrcData);
- SrcPtr = pSrcData + 4;
+ const BYTE* SrcEnd = &pSrcData[SrcSize];
+ const BYTE* SrcPtr = pSrcData + 4;
+ INT32 nbits = 32;
+ UINT32 bits = get_dword(pSrcData);
while (1)
{
while (1)
{
- Mask = get_word(&HuffTableMask[29]);
- MaskedBits = bits & Mask;
+ const UINT16 Mask = get_word(&HuffTableMask[29]);
+ const UINT32 MaskedBits = bits & Mask;
+ if (MaskedBits >= ARRAYSIZE(HuffTableLEC))
+ return -1;
IndexLEC = HuffTableLEC[MaskedBits] & 0xFFF;
BitLength = HuffTableLEC[MaskedBits] >> 12;
bits >>= BitLength;
@@ -2096,8 +2090,10 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
return -1004;
CopyOffset = ncrush->OffsetCache[OffsetCacheIndex];
- Mask = get_word(&HuffTableMask[21]);
- MaskedBits = bits & Mask;
+ const UINT16 Mask = get_word(&HuffTableMask[21]);
+ const UINT32 MaskedBits = bits & Mask;
+ if (MaskedBits > ARRAYSIZE(HuffTableLOM))
+ return -1;
LengthOfMatch = HuffTableLOM[MaskedBits] & 0xFFF;
BitLength = HuffTableLOM[MaskedBits] >> 12;
bits >>= BitLength;
@@ -2106,13 +2102,23 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
if (!NCrushFetchBits(&SrcPtr, &SrcEnd, &nbits, &bits))
return -1;
+ if (LengthOfMatch >= ARRAYSIZE(LOMBitsLUT))
+ return -1;
+
LengthOfMatchBits = LOMBitsLUT[LengthOfMatch];
+
+ if (LengthOfMatch >= ARRAYSIZE(LOMBaseLUT))
+ return -1;
LengthOfMatchBase = LOMBaseLUT[LengthOfMatch];
if (LengthOfMatchBits)
{
- Mask = get_word(&HuffTableMask[(2 * LengthOfMatchBits) + 3]);
- MaskedBits = bits & Mask;
+ const size_t idx = (2ull * LengthOfMatchBits) + 3ull;
+ if (idx >= ARRAYSIZE(HuffTableMask))
+ return -1;
+
+ const UINT16 Mask = get_word(&HuffTableMask[idx]);
+ const UINT32 MaskedBits = bits & Mask;
bits >>= LengthOfMatchBits;
nbits -= LengthOfMatchBits;
LengthOfMatchBase += MaskedBits;
@@ -2127,15 +2133,28 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
}
else
{
+ if (CopyOffsetIndex >= ARRAYSIZE(CopyOffsetBitsLUT))
+ return -1;
+
CopyOffsetBits = CopyOffsetBitsLUT[CopyOffsetIndex];
+
+ if (CopyOffsetIndex >= ARRAYSIZE(CopyOffsetBaseLUT))
+ return -1;
CopyOffsetBase = CopyOffsetBaseLUT[CopyOffsetIndex];
CopyOffset = CopyOffsetBase - 1;
if (CopyOffsetBits)
{
- Mask = get_word(&HuffTableMask[(2 * CopyOffsetBits) + 3]);
- MaskedBits = bits & Mask;
- CopyOffset = CopyOffsetBase + MaskedBits - 1;
+ const size_t idx = (2ull * CopyOffsetBits) + 3ull;
+ if (idx >= ARRAYSIZE(HuffTableMask))
+ return -1;
+
+ const UINT16 Mask = get_word(&HuffTableMask[idx]);
+ const UINT32 MaskedBits = bits & Mask;
+ const UINT32 tmp = CopyOffsetBase + MaskedBits;
+ if (tmp < 1)
+ return -1;
+ CopyOffset = tmp - 1;
bits >>= CopyOffsetBits;
nbits -= CopyOffsetBits;
@@ -2143,8 +2162,11 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
return -1;
}
- Mask = get_word(&HuffTableMask[21]);
- MaskedBits = bits & Mask;
+ const UINT16 Mask = get_word(&HuffTableMask[21]);
+ const UINT32 MaskedBits = bits & Mask;
+ if (MaskedBits >= ARRAYSIZE(HuffTableLOM))
+ return -1;
+
LengthOfMatch = HuffTableLOM[MaskedBits] & 0xFFF;
BitLength = HuffTableLOM[MaskedBits] >> 12;
bits >>= BitLength;
@@ -2153,13 +2175,23 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
if (!NCrushFetchBits(&SrcPtr, &SrcEnd, &nbits, &bits))
return -1;
+ if (LengthOfMatch >= ARRAYSIZE(LOMBitsLUT))
+ return -1;
+
LengthOfMatchBits = LOMBitsLUT[LengthOfMatch];
+
+ if (LengthOfMatch >= ARRAYSIZE(LOMBaseLUT))
+ return -1;
LengthOfMatchBase = LOMBaseLUT[LengthOfMatch];
if (LengthOfMatchBits)
{
- Mask = get_word(&HuffTableMask[(2 * LengthOfMatchBits) + 3]);
- MaskedBits = bits & Mask;
+ const size_t idx = (2ull * LengthOfMatchBits) + 3ull;
+ if (idx >= ARRAYSIZE(HuffTableMask))
+ return -1;
+
+ const UINT16 Mask = get_word(&HuffTableMask[idx]);
+ const UINT32 MaskedBits = bits & Mask;
bits >>= LengthOfMatchBits;
nbits -= LengthOfMatchBits;
LengthOfMatchBase += MaskedBits;
@@ -2583,7 +2615,12 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
}
IndexLEC = Literal;
+ if (IndexLEC >= ARRAYSIZE(HuffLengthLEC))
+ return -1;
BitLength = HuffLengthLEC[IndexLEC];
+
+ if (IndexLEC * 2ull >= ARRAYSIZE(HuffCodeLEC))
+ return -1;
CodeLEC = get_word(&HuffCodeLEC[IndexLEC * 2]);
if (BitLength > 15)
@@ -2666,9 +2703,18 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
bits = CopyOffset;
CopyOffsetIndex = ncrush->HuffTableCopyOffset[bits + 2];
+
+ if (CopyOffsetIndex >= ARRAYSIZE(CopyOffsetBitsLUT))
+ return -1;
+
CopyOffsetBits = CopyOffsetBitsLUT[CopyOffsetIndex];
IndexLEC = 257 + CopyOffsetIndex;
+ if (IndexLEC >= ARRAYSIZE(HuffLengthLEC))
+ return -1;
BitLength = HuffLengthLEC[IndexLEC];
+
+ if (IndexLEC * 2ull >= ARRAYSIZE(HuffCodeLEC))
+ return -1;
CodeLEC = get_word(&HuffCodeLEC[IndexLEC * 2]);
if (BitLength > 15)
@@ -2687,13 +2733,23 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
else
IndexCO = ncrush->HuffTableLOM[MatchLength];
+ if (IndexCO >= ARRAYSIZE(HuffLengthLOM))
+ return -1;
BitLength = HuffLengthLOM[IndexCO];
+
+ if (IndexCO >= ARRAYSIZE(LOMBitsLUT))
+ return -1;
IndexLOM = LOMBitsLUT[IndexCO];
+
+ if (IndexCO >= ARRAYSIZE(HuffCodeLOM))
+ return -1;
NCrushWriteBits(&DstPtr, &accumulator, &offset, HuffCodeLOM[IndexCO], BitLength);
Mask = ((1 << IndexLOM) - 1);
MaskedBits = (MatchLength - 2) & Mask;
NCrushWriteBits(&DstPtr, &accumulator, &offset, MaskedBits, IndexLOM);
+ if (IndexCO >= ARRAYSIZE(LOMBaseLUT))
+ return -1;
if ((MaskedBits + LOMBaseLUT[IndexCO]) != MatchLength)
return -1010;
}
@@ -2701,7 +2757,11 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
{
/* CopyOffset in OffsetCache */
IndexLEC = 289 + OffsetCacheIndex;
+ if (IndexLEC >= ARRAYSIZE(HuffLengthLEC))
+ return -1;
BitLength = HuffLengthLEC[IndexLEC];
+ if (IndexLEC * 2ull >= ARRAYSIZE(HuffCodeLEC))
+ return -1;
CodeLEC = get_word(&HuffCodeLEC[IndexLEC * 2]);
if (BitLength >= 15)
@@ -2714,13 +2774,24 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
else
IndexCO = ncrush->HuffTableLOM[MatchLength];
+ if (IndexCO >= ARRAYSIZE(HuffLengthLOM))
+ return -1;
+
BitLength = HuffLengthLOM[IndexCO];
+
+ if (IndexCO >= ARRAYSIZE(LOMBitsLUT))
+ return -1;
IndexLOM = LOMBitsLUT[IndexCO];
+
+ if (IndexCO >= ARRAYSIZE(HuffCodeLOM))
+ return -1;
NCrushWriteBits(&DstPtr, &accumulator, &offset, HuffCodeLOM[IndexCO], BitLength);
Mask = ((1 << IndexLOM) - 1);
MaskedBits = (MatchLength - 2) & Mask;
NCrushWriteBits(&DstPtr, &accumulator, &offset, MaskedBits, IndexLOM);
+ if (IndexCO >= ARRAYSIZE(LOMBaseLUT))
+ return -1;
if ((MaskedBits + LOMBaseLUT[IndexCO]) != MatchLength)
return -1012;
}
@@ -2745,6 +2816,10 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
Literal = *SrcPtr++;
HistoryPtr++;
IndexLEC = Literal;
+ if (IndexLEC >= ARRAYSIZE(HuffLengthLEC))
+ return -1;
+ if (IndexLEC * 2ull >= ARRAYSIZE(HuffCodeLEC))
+ return -1;
BitLength = HuffLengthLEC[IndexLEC];
CodeLEC = get_word(&HuffCodeLEC[IndexLEC * 2]);
@@ -2801,6 +2876,9 @@ static int ncrush_generate_tables(NCRUSH_CONTEXT* context)
int j, l;
k = 0;
+ WINPR_ASSERT(context);
+ WINPR_ASSERT(28 < ARRAYSIZE(LOMBitsLUT));
+
for (i = 0; i < 28; i++)
{
for (j = 0; j < 1 << LOMBitsLUT[i]; j++)
@@ -2817,6 +2895,11 @@ static int ncrush_generate_tables(NCRUSH_CONTEXT* context)
else
i = context->HuffTableLOM[k];
+ if (i >= ARRAYSIZE(LOMBitsLUT))
+ return -1;
+ if (i >= ARRAYSIZE(LOMBaseLUT))
+ return -1;
+
if (((((1 << LOMBitsLUT[i]) - 1) & (k - 2)) + LOMBaseLUT[i]) != k)
return -1;
}
--
2.42.1