- renamed variable caused failures in the QA runs - Since teh variable is was used in an assert, the normal builds did not fail Related: cve-2019-17543
80 lines
3.2 KiB
Diff
80 lines
3.2 KiB
Diff
From 6bc6f836a18d1f8fd05c8fc2b42f1d800bc25de1 Mon Sep 17 00:00:00 2001
|
|
From: Nick Terrell <terrelln@fb.com>
|
|
Date: Wed, 17 Jul 2019 11:28:38 -0700
|
|
Subject: [PATCH] [LZ4_compress_destSize] Fix rare data corruption bug
|
|
|
|
---
|
|
lib/lz4.c | 30 ++++++++++++++++++++++++++++++
|
|
1 file changed, 30 insertions(+)
|
|
|
|
diff --git a/lib/lz4.c b/lib/lz4.c
|
|
index 1e80c9812..461644da0 100644
|
|
--- a/lib/lz4.c
|
|
+++ b/lib/lz4.c
|
|
@@ -648,6 +648,18 @@ LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tab
|
|
return LZ4_hash4(LZ4_read32(p), tableType);
|
|
}
|
|
|
|
+static void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType)
|
|
+{
|
|
+ switch (tableType)
|
|
+ {
|
|
+ default: /* fallthrough */
|
|
+ case clearedTable: { /* illegal! */ assert(0); return; }
|
|
+ case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = NULL; return; }
|
|
+ case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = 0; return; }
|
|
+ case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = 0; return; }
|
|
+ }
|
|
+}
|
|
+
|
|
static void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType)
|
|
{
|
|
switch (tableType)
|
|
@@ -848,6 +860,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
|
|
for ( ; ; ) {
|
|
const BYTE* match;
|
|
BYTE* token;
|
|
+ const BYTE* filledIp;
|
|
|
|
/* Find a match */
|
|
if (tableType == byPtr) {
|
|
@@ -934,6 +947,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
|
|
}
|
|
|
|
/* Catch up */
|
|
+ filledIp = ip;
|
|
while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }
|
|
|
|
/* Encode Literals */
|
|
@@ -1018,7 +1032,21 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
|
|
/* Match description too long : reduce it */
|
|
U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 1 - LASTLITERALS) * 255;
|
|
ip -= matchCode - newMatchCode;
|
|
+ assert(newMatchCode < matchCode);
|
|
matchCode = newMatchCode;
|
|
+ if (unlikely(ip < filledIp)) {
|
|
+ /* We have already filled up to filledIp so if ip ends up less than filledIp
|
|
+ * we have positions in the hash table beyond the current position. This is
|
|
+ * a problem if we reuse the hash table. So we have to remove these positions
|
|
+ * from the hash table.
|
|
+ */
|
|
+ const BYTE* ptr;
|
|
+ DEBUGLOG(5, "Clearing %u positions", (U32)(filledIp - ip));
|
|
+ for (ptr = ip; ptr <= filledIp; ++ptr) {
|
|
+ U32 const h = LZ4_hashPosition(ptr, tableType);
|
|
+ LZ4_clearHash(h, cctx->hashTable, tableType);
|
|
+ }
|
|
+ }
|
|
}
|
|
}
|
|
if (matchCode >= ML_MASK) {
|
|
@@ -1038,6 +1066,8 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
|
|
} else
|
|
*token += (BYTE)(matchCode);
|
|
}
|
|
+ /* Ensure we have enough space for the last literals. */
|
|
+ assert(!(outputLimited == fillOutput && op + 1 + LASTLITERALS > olimit));
|
|
|
|
anchor = ip;
|
|
|