Skip to content

Commit 75fa3f2

Browse files
authored
Merge pull request #1446 from terrelln/overflow
[libzstd] Fix infinite loop in decompression
2 parents 4acf139 + aaea4ef commit 75fa3f2

File tree

2 files changed

+30
-11
lines changed

2 files changed

+30
-11
lines changed

lib/decompress/zstd_decompress.c

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,21 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
343343
} }
344344
}
345345

346+
static size_t readSkippableFrameSize(void const* src, size_t srcSize)
347+
{
348+
size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;
349+
U32 sizeU32;
350+
351+
if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
352+
return ERROR(srcSize_wrong);
353+
354+
sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
355+
if ((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32)
356+
return ERROR(frameParameter_unsupported);
357+
358+
return skippableHeaderSize + sizeU32;
359+
}
360+
346361
/** ZSTD_findDecompressedSize() :
347362
* compatible with legacy mode
348363
* `srcSize` must be the exact length of some number of ZSTD compressed and/or
@@ -356,11 +371,9 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
356371
U32 const magicNumber = MEM_readLE32(src);
357372

358373
if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
359-
size_t skippableSize;
360-
if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
361-
return ERROR(srcSize_wrong);
362-
skippableSize = MEM_readLE32((const BYTE *)src + ZSTD_FRAMEIDSIZE)
363-
+ ZSTD_SKIPPABLEHEADERSIZE;
374+
size_t const skippableSize = readSkippableFrameSize(src, srcSize);
375+
if (ZSTD_isError(skippableSize))
376+
return skippableSize;
364377
if (srcSize < skippableSize) {
365378
return ZSTD_CONTENTSIZE_ERROR;
366379
}
@@ -436,7 +449,7 @@ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
436449
#endif
437450
if ( (srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
438451
&& (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START ) {
439-
return ZSTD_SKIPPABLEHEADERSIZE + MEM_readLE32((const BYTE*)src + ZSTD_FRAMEIDSIZE);
452+
return readSkippableFrameSize(src, srcSize);
440453
} else {
441454
const BYTE* ip = (const BYTE*)src;
442455
const BYTE* const ipstart = ip;
@@ -660,11 +673,9 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
660673
DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
661674
(U32)magicNumber, (U32)ZSTD_MAGICNUMBER);
662675
if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
663-
size_t skippableSize;
664-
if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
665-
return ERROR(srcSize_wrong);
666-
skippableSize = MEM_readLE32((const BYTE*)src + ZSTD_FRAMEIDSIZE)
667-
+ ZSTD_SKIPPABLEHEADERSIZE;
676+
size_t const skippableSize = readSkippableFrameSize(src, srcSize);
677+
if (ZSTD_isError(skippableSize))
678+
return skippableSize;
668679
if (srcSize < skippableSize) return ERROR(srcSize_wrong);
669680

670681
src = (const BYTE *)src + skippableSize;

tests/fuzzer.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,14 @@ static int basicUnitTests(U32 seed, double compressibility)
353353
ZSTD_freeCCtx(cctx);
354354
}
355355

356+
DISPLAYLEVEL(3, "test%3i : decompress skippable frame -8 size : ", testNb++);
357+
{
358+
char const skippable8[] = "\x50\x2a\x4d\x18\xf8\xff\xff\xff";
359+
size_t const size = ZSTD_decompress(NULL, 0, skippable8, 8);
360+
if (!ZSTD_isError(size)) goto _output_error;
361+
}
362+
DISPLAYLEVEL(3, "OK \n");
363+
356364

357365
DISPLAYLEVEL(3, "test%3i : ZSTD_getFrameContentSize test : ", testNb++);
358366
{ unsigned long long const rSize = ZSTD_getFrameContentSize(compressedBuffer, cSize);

0 commit comments

Comments
 (0)