Backport CVE-2023-40589.

replaced WINPR_ASSERT with plain assert, as this macro is defined only in later versions and if verbose asserting is disabled it will actually do assert() itself.
This commit is contained in:
Tobias Frost 2023-10-03 11:14:37 +02:00
parent 6ae95183f4
commit 500b4499a7
3 changed files with 326 additions and 1 deletions

2
debian/changelog vendored
View File

@ -14,7 +14,7 @@ freerdp2 (2.3.0+dfsg1-2~deb10u3) UNRELEASED; urgency=medium
CVE-2020-13397 CVE-2020-13398 and
CVE-2020-15103 (Closes: #965979)
* Backporting remaining issues: (Closes: #1051638)
CVE-2023-39350 CVE-2023-39354 CVE-2023-39355
CVE-2023-39350 CVE-2023-39354 CVE-2023-39355 CVE-2023-40589
-- Tobias Frost <tobi@debian.org> Mon, 02 Oct 2023 17:10:48 +0200

324
debian/patches/0040-CVE-2023-40589.patch vendored Normal file
View File

@ -0,0 +1,324 @@
Description: Upstream fix for CVE-2023-40589 - Global-Buffer-Overflow in ncrush_decompress
Origin: https://github.com/FreeRDP/FreeRDP/commit/16141a30f983dd6f7a6e5b0356084171942c9416
Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-gc34-mw6m-g42x
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1051638
--- a/libfreerdp/codec/ncrush.c
+++ b/libfreerdp/codec/ncrush.c
@@ -30,6 +30,8 @@
#include <freerdp/log.h>
#include <freerdp/codec/ncrush.h>
+#include <assert.h>
+
#define TAG FREERDP_TAG("codec")
struct _NCRUSH_CONTEXT
@@ -1994,15 +1996,9 @@
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 +2006,6 @@
UINT32 LengthOfMatch;
UINT32 CopyOffsetIndex;
UINT32 OffsetCacheIndex;
- BYTE* HistoryPtr;
- BYTE* HistoryBuffer;
- BYTE* HistoryBufferEnd;
UINT32 CopyOffsetBits;
UINT32 CopyOffsetBase;
UINT32 LengthOfMatchBits;
@@ -2021,8 +2014,8 @@
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 +2034,7 @@
ZeroMemory(&(ncrush->OffsetCache), sizeof(ncrush->OffsetCache));
}
- HistoryPtr = ncrush->HistoryPtr;
+ BYTE* HistoryPtr = ncrush->HistoryPtr;
if (!(flags & PACKET_COMPRESSED))
{
@@ -2050,17 +2043,19 @@
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 +2091,10 @@
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 +2103,23 @@
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 +2134,28 @@
}
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 +2163,11 @@
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 +2176,23 @@
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 +2616,12 @@
}
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 +2704,18 @@
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 +2734,23 @@
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 +2758,11 @@
{
/* 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 +2775,24 @@
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 +2817,10 @@
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 +2877,9 @@
int j, l;
k = 0;
+ assert(context);
+ assert(28 < ARRAYSIZE(LOMBitsLUT));
+
for (i = 0; i < 28; i++)
{
for (j = 0; j < 1 << LOMBitsLUT[i]; j++)
@@ -2817,6 +2896,11 @@
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;
}

View File

@ -26,3 +26,4 @@
0036-CVE-2023-39350.patch
0037-CVE-2023-39354.patch
0038-CVE-2023-39355.patch
0040-CVE-2023-40589.patch