mirror of
https://github.com/lz4/lz4.git
synced 2026-10-24 01:48:57 +03:00
lz4hc: LZ4_saveDictHC() before any compression no longer corrupts the next block
On a new or reset stream (prefixStart == NULL), LZ4_saveDictHC() installed @safeBuffer as prefix, which skipped the initialization done by the next compression (LZ4HC_init_internal()). The stream then started at index 0, which the hash table uses for empty entries : positions matched themselves (offset 0), and the block decoded into wrong data, at all HC levels, also with an attached dictionary. Present in v1.10.0. It now saves nothing, leaving the stream to be initialized by the next compression. Found by lz4frame with uncompressed then compressed segments in linked blocks. tests : fuzzer.c saveDictHC test #926 compresses after LZ4_saveDictHC(), without and with an attached dictionary.
This commit is contained in:
1
NEWS
1
NEWS
@@ -4,6 +4,7 @@ fix : `LZ4_compress_fast_continue()` produced wrong data when a block overwrote
|
||||
fix : `LZ4_compress_destSize_extState()` corrupted data with `acceleration <= 0`, and could read out of bounds (since v1.10.0)
|
||||
fix : negative sizes crashed `LZ4_decompress_safe_partial()` (since v1.9.3) and `LZ4_decompress_fast()` (since v1.9.4)
|
||||
fix : `LZ4_saveDict()` with a negative `dictSize` copied up to 64 KB into `safeBuffer`, by @arthuz-th
|
||||
fix : `LZ4_saveDictHC()` before any compression (new or reset stream) corrupted the next compressed block
|
||||
fix : `LZ4_decompress_safe_partial()` could leave previous `dst` content in decoded data with an invalid offset 0 (since v1.8.3)
|
||||
fix : heap overflow with an invalid `blockSizeID` in `LZ4F_compressBegin()` and `LZ4F_writeOpen()`, by @jaypatrickhoward
|
||||
fix : `LZ4F_compressBegin()` failing on allocation left an inconsistent frame in progress : it is now invalidated
|
||||
|
||||
@@ -1793,6 +1793,9 @@ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictS
|
||||
LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
|
||||
int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);
|
||||
DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
|
||||
/* nothing compressed yet (new or reset stream) : nothing to save,
|
||||
* the stream remains to be initialized by next compression (attached dictionary included) */
|
||||
if (streamPtr->prefixStart == NULL) return 0;
|
||||
assert(prefixSize >= 0);
|
||||
if (dictSize > 64 KB) dictSize = 64 KB;
|
||||
if (dictSize < 4) dictSize = 0;
|
||||
|
||||
@@ -1747,6 +1747,34 @@ static void FUZ_unitTests(int compressionLevel)
|
||||
{ char tmp_buffer[240] = { 0 };
|
||||
FUZ_CHECKTEST( LZ4_saveDictHC(ctx, tmp_buffer, sizeof(tmp_buffer)) != 0,
|
||||
"LZ4_saveDictHC() can't save anything since compression hasn't started");
|
||||
}
|
||||
|
||||
/* next block is compressed as the first one of the stream,
|
||||
* without (attach==0) or with (attach==1) an attached dictionary */
|
||||
{ LZ4_streamHC_t* const dictHC = LZ4_createStreamHC();
|
||||
int const levels[] = { LZ4HC_CLEVEL_DEFAULT, 3, LZ4HC_CLEVEL_OPT_MIN, LZ4HC_CLEVEL_MAX }; /* first : level of LZ4_initStreamHC() */
|
||||
int attach, l;
|
||||
FUZ_CHECKTEST(dictHC == NULL, "LZ4_createStreamHC() allocation failed");
|
||||
for (l = 0; l < (int)(sizeof(levels) / sizeof(levels[0])); l++) {
|
||||
for (attach = 0; attach <= 1; attach++) {
|
||||
char saveBuffer[240];
|
||||
int cSize, dSize;
|
||||
if (l || attach) LZ4_resetStreamHC_fast(ctx, levels[l]); /* first test : right after init */
|
||||
if (attach) {
|
||||
LZ4_resetStreamHC_fast(dictHC, levels[l]);
|
||||
FUZ_CHECKTEST(LZ4_loadDictHC(dictHC, testInput, 64 KB) != 64 KB, "LZ4_loadDictHC() failed");
|
||||
LZ4_attach_HC_dictionary(ctx, dictHC);
|
||||
}
|
||||
FUZ_CHECKTEST( LZ4_saveDictHC(ctx, saveBuffer, sizeof(saveBuffer)) != 0,
|
||||
"LZ4_saveDictHC() can't save anything since compression hasn't started");
|
||||
cSize = LZ4_compress_HC_continue(ctx, testInput + 64 KB, testCompressed, 64 KB, testCompressedSize);
|
||||
FUZ_CHECKTEST(cSize <= 0, "LZ4_compress_HC_continue() failed");
|
||||
dSize = LZ4_decompress_safe_usingDict(testCompressed, testVerify, cSize, 64 KB,
|
||||
testInput, attach ? 64 KB : 0);
|
||||
FUZ_CHECKTEST(dSize != 64 KB || memcmp(testVerify, testInput + 64 KB, 64 KB),
|
||||
"level %i, dictionary %i : block compressed after LZ4_saveDictHC() is corrupted", levels[l], attach);
|
||||
} }
|
||||
LZ4_freeStreamHC(dictHC);
|
||||
} }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user