From a97e9a627adf18b0efc9f2c4aeeac25b2a2af730 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 23 May 2018 12:16:00 -0700 Subject: [PATCH 1/3] [zstd] Fix decompression edge case This edge case is only possible with the new optimal encoding selector, since before zstd would always choose `set_basic` for small numbers of sequences. Fix `FSE_readNCount()` to support buffers < 4 bytes. Credit to OSS-Fuzz --- lib/common/entropy_common.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/common/entropy_common.c b/lib/common/entropy_common.c index 344c32361..a8d0b146b 100644 --- a/lib/common/entropy_common.c +++ b/lib/common/entropy_common.c @@ -72,7 +72,14 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t unsigned charnum = 0; int previous0 = 0; - if (hbSize < 4) return ERROR(srcSize_wrong); + if (hbSize < 4) { + /* This function only works when hbSize >= 4 */ + char buffer[4]; + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, headerBuffer, hbSize); + return FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, buffer, sizeof(buffer)); + } + bitStream = MEM_readLE32(ip); nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); @@ -105,6 +112,7 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); while (charnum < n0) normalizedCounter[charnum++] = 0; if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + assert((bitCount >> 3) <= 3); /* For first condition to work */ ip += bitCount>>3; bitCount &= 7; bitStream = MEM_readLE32(ip) >> bitCount; From c92dd11940f68c71d3b627de2612537b7e2ae92a Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 23 May 2018 14:47:20 -0700 Subject: [PATCH 2/3] Error if reported size is too large in edge case --- lib/common/entropy_common.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/common/entropy_common.c b/lib/common/entropy_common.c index a8d0b146b..2edb6e9be 100644 --- a/lib/common/entropy_common.c +++ b/lib/common/entropy_common.c @@ -77,8 +77,13 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t char buffer[4]; memset(buffer, 0, sizeof(buffer)); memcpy(buffer, headerBuffer, hbSize); - return FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, buffer, sizeof(buffer)); + size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, + buffer, sizeof(buffer)); + if (FSE_isError(countSize)) return countSize; + if (countSize > hbSize) return ERROR(corruption_detected); + return countSize; } + assert(hbSize >= 4); bitStream = MEM_readLE32(ip); nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ From f2d0924b87e4dab590cb53f98bb33a21c4375119 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 23 May 2018 14:58:58 -0700 Subject: [PATCH 3/3] Variable declarations --- lib/common/entropy_common.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/common/entropy_common.c b/lib/common/entropy_common.c index 2edb6e9be..33fd04bd6 100644 --- a/lib/common/entropy_common.c +++ b/lib/common/entropy_common.c @@ -73,16 +73,16 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t int previous0 = 0; if (hbSize < 4) { - /* This function only works when hbSize >= 4 */ - char buffer[4]; - memset(buffer, 0, sizeof(buffer)); - memcpy(buffer, headerBuffer, hbSize); - size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, - buffer, sizeof(buffer)); - if (FSE_isError(countSize)) return countSize; - if (countSize > hbSize) return ERROR(corruption_detected); - return countSize; - } + /* This function only works when hbSize >= 4 */ + char buffer[4]; + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, headerBuffer, hbSize); + { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, + buffer, sizeof(buffer)); + if (FSE_isError(countSize)) return countSize; + if (countSize > hbSize) return ERROR(corruption_detected); + return countSize; + } } assert(hbSize >= 4); bitStream = MEM_readLE32(ip);