Skip to content

Commit

Permalink
[codec,ncrush] fix index checks
Browse files Browse the repository at this point in the history
properly verify all offsets while decoding data.
  • Loading branch information
akallabeth authored and mfleisz committed Aug 28, 2023
1 parent 1bbed81 commit 16141a3
Showing 1 changed file with 109 additions and 29 deletions.
138 changes: 109 additions & 29 deletions libfreerdp/codec/ncrush.c
Expand Up @@ -2016,25 +2016,16 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
const BYTE** ppDstData, 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;
BYTE* CopyOffsetPtr;
UINT32 LengthOfMatch;
UINT32 CopyOffsetIndex;
UINT32 OffsetCacheIndex;
BYTE* HistoryPtr;
BYTE* HistoryBuffer;
BYTE* HistoryBufferEnd;
UINT32 CopyOffsetBits;
UINT32 CopyOffsetBase;
UINT32 LengthOfMatchBits;
Expand All @@ -2048,8 +2039,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
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)
{
Expand All @@ -2068,7 +2059,7 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
ZeroMemory(&(ncrush->OffsetCache), sizeof(ncrush->OffsetCache));
}

HistoryPtr = ncrush->HistoryPtr;
BYTE* HistoryPtr = ncrush->HistoryPtr;

if (!(flags & PACKET_COMPRESSED))
{
Expand All @@ -2077,17 +2068,19 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
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;
Expand Down Expand Up @@ -2123,8 +2116,10 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
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;
Expand All @@ -2133,13 +2128,23 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
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;
Expand All @@ -2154,24 +2159,40 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
}
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;

if (!NCrushFetchBits(&SrcPtr, &SrcEnd, &nbits, &bits))
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;
Expand All @@ -2180,13 +2201,23 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
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;
Expand Down Expand Up @@ -2644,7 +2675,12 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSize
}

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)
Expand Down Expand Up @@ -2727,9 +2763,18 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSize
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)
Expand All @@ -2748,21 +2793,35 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSize
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;
}
else
{
/* 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)
Expand All @@ -2775,13 +2834,24 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSize
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;
}
Expand All @@ -2806,6 +2876,10 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSize
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]);

Expand Down Expand Up @@ -2866,6 +2940,7 @@ static int ncrush_generate_tables(NCRUSH_CONTEXT* context)
k = 0;

WINPR_ASSERT(context);
WINPR_ASSERT(28 < ARRAYSIZE(LOMBitsLUT));

for (i = 0; i < 28; i++)
{
Expand All @@ -2883,6 +2958,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;
}
Expand Down

0 comments on commit 16141a3

Please sign in to comment.