[codec,ncrush] fix index checks

properly verify all offsets while decoding data.
This commit is contained in:
Armin Novak 2023-08-28 09:06:42 +02:00 committed by Martin Fleisz
parent 1bbed81041
commit 16141a30f9
1 changed files with 109 additions and 29 deletions

View File

@ -2016,15 +2016,9 @@ 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;
@ -2032,9 +2026,6 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
UINT32 LengthOfMatch;
UINT32 CopyOffsetIndex;
UINT32 OffsetCacheIndex;
BYTE* HistoryPtr;
BYTE* HistoryBuffer;
BYTE* HistoryBufferEnd;
UINT32 CopyOffsetBits;
UINT32 CopyOffsetBase;
UINT32 LengthOfMatchBits;
@ -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)
{
@ -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))
{
@ -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;
@ -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;
@ -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;
@ -2154,15 +2159,28 @@ 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;
@ -2170,8 +2188,11 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
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;
@ -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;
@ -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)
@ -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)
@ -2748,13 +2793,23 @@ 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;
}
@ -2762,7 +2817,11 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSize
{
/* 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)
@ -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;
}
@ -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]);
@ -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++)
{
@ -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;
}