From e6edcfa79562b1f876d40ed108f5f9dd8ff6e220 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 22 Jul 2019 13:05:09 -0700 Subject: [PATCH] [legacy] Fix bug in zstd-0.5 decoder The match length and literal length extra bytes could either by 2 bytes or 3 bytes in version 0.5. All earlier verions were always 3 bytes, and later version didn't have dumps. The bug, introduced by commit 0fd322f812211e653a83492c0c114b933f8b6bc5, was triggered when the last dump was a 2-byte dump, because we didn't separate that case from a 3-byte dump, and thought we were over-reading. I've tested this fix with every zstd version < 1.0.0 on the buggy file, and we are now always successfully decompressing with the right checksum. Fixes #1693. --- lib/legacy/zstd_v05.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/legacy/zstd_v05.c b/lib/legacy/zstd_v05.c index a7ea6066f..e347b00dc 100644 --- a/lib/legacy/zstd_v05.c +++ b/lib/legacy/zstd_v05.c @@ -218,11 +218,6 @@ 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()) @@ -3158,10 +3153,14 @@ static void ZSTDv05_decodeSequence(seq_t* seq, seqState_t* seqState) if (litLength == MaxLL) { const U32 add = *dumps++; if (add < 255) litLength += add; - else if (dumps + 3 <= de) { - litLength = MEM_readLE24(dumps); - if (litLength&1) litLength>>=1, dumps += 3; - else litLength = (U16)(litLength)>>1, dumps += 2; + else if (dumps + 2 <= de) { + litLength = MEM_readLE16(dumps); + dumps += 2; + if ((litLength & 1) && dumps < de) { + litLength += *dumps << 16; + dumps += 1; + } + litLength>>=1; } if (dumps >= de) { dumps = de-1; } /* late correction, to avoid read overflow (data is now corrupted anyway) */ } @@ -3191,10 +3190,14 @@ static void ZSTDv05_decodeSequence(seq_t* seq, seqState_t* seqState) if (matchLength == MaxML) { const U32 add = dumps>=1, dumps += 3; - else matchLength = (U16)(matchLength)>>1, dumps += 2; + else if (dumps + 2 <= de) { + matchLength = MEM_readLE16(dumps); + dumps += 2; + if ((matchLength & 1) && dumps < de) { + matchLength += *dumps << 16; + dumps += 1; + } + matchLength >>= 1; } if (dumps >= de) { dumps = de-1; } /* late correction, to avoid read overflow (data is now corrupted anyway) */ }