From: Nick Terrell Date: Fri, 19 Apr 2019 18:34:52 +0000 (-0700) Subject: [legacy] Fix ZSTDv0*_decodeSequence() X-Git-Tag: v1.4.1^2~50^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0fd322f812211e653a83492c0c114b933f8b6bc5;p=thirdparty%2Fzstd.git [legacy] Fix ZSTDv0*_decodeSequence() * Version <= 0.5 could read beyond the end of `dumps`, which points into the input buffer. * Check the validity of `dumps` before using it, if it is out of bounds return garbage values. There is no return code for this function. * Introduce `MEM_readLE24()` for simplicity, since I don't want to trust that there is an extra byte after `dumps`. --- diff --git a/lib/legacy/zstd_v01.c b/lib/legacy/zstd_v01.c index 35d849767..ae8cba2a3 100644 --- a/lib/legacy/zstd_v01.c +++ b/lib/legacy/zstd_v01.c @@ -1358,8 +1358,6 @@ static unsigned ZSTD_isLittleEndian(void) static U16 ZSTD_read16(const void* p) { U16 r; memcpy(&r, p, sizeof(r)); return r; } -static U32 ZSTD_read32(const void* p) { U32 r; memcpy(&r, p, sizeof(r)); return r; } - static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); } @@ -1384,16 +1382,9 @@ static U16 ZSTD_readLE16(const void* memPtr) } } - -static U32 ZSTD_readLE32(const void* memPtr) +static U32 ZSTD_readLE24(const void* memPtr) { - if (ZSTD_isLittleEndian()) - return ZSTD_read32(memPtr); - else - { - const BYTE* p = (const BYTE*)memPtr; - return (U32)((U32)p[0] + ((U32)p[1]<<8) + ((U32)p[2]<<16) + ((U32)p[3]<<24)); - } + return ZSTD_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); } static U32 ZSTD_readBE32(const void* memPtr) @@ -1707,13 +1698,13 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) seqState->prevOffset = seq->offset; if (litLength == MaxLL) { - U32 add = dumps 1 byte */ + litLength = ZSTD_readLE24(dumps); dumps += 3; } } @@ -1735,13 +1726,13 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); if (matchLength == MaxML) { - U32 add = dumps 1 byte */ + matchLength = ZSTD_readLE24(dumps); dumps += 3; } } diff --git a/lib/legacy/zstd_v02.c b/lib/legacy/zstd_v02.c index 561bc412e..793df6024 100644 --- a/lib/legacy/zstd_v02.c +++ b/lib/legacy/zstd_v02.c @@ -217,6 +217,11 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) } } +MEM_STATIC U32 MEM_readLE24(const void* memPtr) +{ + return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); +} + MEM_STATIC U32 MEM_readLE32(const void* memPtr) { if (MEM_isLittleEndian()) @@ -3043,11 +3048,11 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) seqState->prevOffset = seq->offset; if (litLength == MaxLL) { - U32 add = *dumps++; + const U32 add = dumps 1 byte */ + litLength = MEM_readLE24(dumps); dumps += 3; } if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ @@ -3073,11 +3078,11 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); if (matchLength == MaxML) { - U32 add = *dumps++; + const U32 add = dumps 1 byte */ + matchLength = MEM_readLE24(dumps); dumps += 3; } if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ diff --git a/lib/legacy/zstd_v03.c b/lib/legacy/zstd_v03.c index a1bf0fa9b..7a0e7c9b6 100644 --- a/lib/legacy/zstd_v03.c +++ b/lib/legacy/zstd_v03.c @@ -219,6 +219,11 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) } } +MEM_STATIC U32 MEM_readLE24(const void* memPtr) +{ + return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); +} + MEM_STATIC U32 MEM_readLE32(const void* memPtr) { if (MEM_isLittleEndian()) @@ -2684,11 +2689,11 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) seqState->prevOffset = seq->offset; if (litLength == MaxLL) { - U32 add = *dumps++; + const U32 add = dumps 1 byte */ + litLength = MEM_readLE24(dumps); dumps += 3; } if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ @@ -2714,11 +2719,11 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); if (matchLength == MaxML) { - U32 add = *dumps++; + const U32 add = dumps 1 byte */ + matchLength = MEM_readLE24(dumps); dumps += 3; } if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ diff --git a/lib/legacy/zstd_v04.c b/lib/legacy/zstd_v04.c index 4342330e2..645a6e313 100644 --- a/lib/legacy/zstd_v04.c +++ b/lib/legacy/zstd_v04.c @@ -189,6 +189,11 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) } } +MEM_STATIC U32 MEM_readLE24(const void* memPtr) +{ + return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); +} + MEM_STATIC U32 MEM_readLE32(const void* memPtr) { if (MEM_isLittleEndian()) @@ -2808,13 +2813,12 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) litLength = FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream)); prevOffset = litLength ? seq->offset : seqState->prevOffset; if (litLength == MaxLL) { - U32 add = *dumps++; + const U32 add = dumps de) { litLength = MaxLL+255; } /* late correction, to avoid using uninitialized memory */ if (dumps >= de) { dumps = de-1; } /* late correction, to avoid read overflow (data is now corrupted anyway) */ } @@ -2837,13 +2841,12 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) /* MatchLength */ matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); if (matchLength == MaxML) { - U32 add = *dumps++; + const U32 add = dumps de) { matchLength = MaxML+255; } /* late correction, to avoid using uninitialized memory */ if (dumps >= de) { dumps = de-1; } /* late correction, to avoid read overflow (data is now corrupted anyway) */ } matchLength += MINMATCH; diff --git a/lib/legacy/zstd_v05.c b/lib/legacy/zstd_v05.c index 800aa15e7..a7ea6066f 100644 --- a/lib/legacy/zstd_v05.c +++ b/lib/legacy/zstd_v05.c @@ -218,6 +218,11 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) } } +MEM_STATIC U32 MEM_readLE24(const void* memPtr) +{ + return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); +} + MEM_STATIC U32 MEM_readLE32(const void* memPtr) { if (MEM_isLittleEndian()) @@ -3151,14 +3156,13 @@ static void ZSTDv05_decodeSequence(seq_t* seq, seqState_t* seqState) litLength = FSEv05_peakSymbol(&(seqState->stateLL)); prevOffset = litLength ? seq->offset : seqState->prevOffset; if (litLength == MaxLL) { - U32 add = *dumps++; + const U32 add = *dumps++; if (add < 255) litLength += add; - else { - litLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no risk : dumps is always followed by seq tables > 1 byte */ + else if (dumps + 3 <= de) { + litLength = MEM_readLE24(dumps); if (litLength&1) litLength>>=1, dumps += 3; else litLength = (U16)(litLength)>>1, dumps += 2; } - if (dumps > de) { litLength = MaxLL+255; } /* late correction, to avoid using uninitialized memory */ if (dumps >= de) { dumps = de-1; } /* late correction, to avoid read overflow (data is now corrupted anyway) */ } @@ -3185,14 +3189,13 @@ static void ZSTDv05_decodeSequence(seq_t* seq, seqState_t* seqState) /* MatchLength */ matchLength = FSEv05_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); if (matchLength == MaxML) { - U32 add = *dumps++; + const U32 add = dumps 1 byte */ + else if (dumps + 3 <= de) { + matchLength = MEM_readLE24(dumps); if (matchLength&1) matchLength>>=1, dumps += 3; else matchLength = (U16)(matchLength)>>1, dumps += 2; } - if (dumps > de) { matchLength = MaxML+255; } /* late correction, to avoid using uninitialized memory */ if (dumps >= de) { dumps = de-1; } /* late correction, to avoid read overflow (data is now corrupted anyway) */ } matchLength += MINMATCH;