From 8e3a36a6dba3a35220a70fd572ace95947651b52 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 1 Jun 2016 00:18:28 +0200 Subject: [PATCH] decompression validates frame content checksum --- lib/common/error_private.h | 1 + lib/common/error_public.h | 1 + lib/decompress/zstd_decompress.c | 45 ++++++++++++++++++++------------ 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/common/error_private.h b/lib/common/error_private.h index 6b243c07..88906149 100644 --- a/lib/common/error_private.h +++ b/lib/common/error_private.h @@ -102,6 +102,7 @@ ERR_STATIC const char* ERR_getErrorString(ERR_enum code) case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; case PREFIX(srcSize_wrong): return "Src size incorrect"; case PREFIX(corruption_detected): return "Corrupted block detected"; + case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; diff --git a/lib/common/error_public.h b/lib/common/error_public.h index 660b2d3f..e8cfcc91 100644 --- a/lib/common/error_public.h +++ b/lib/common/error_public.h @@ -54,6 +54,7 @@ typedef enum { ZSTD_error_dstSize_tooSmall, ZSTD_error_srcSize_wrong, ZSTD_error_corruption_detected, + ZSTD_error_checksum_wrong, ZSTD_error_tableLog_tooLarge, ZSTD_error_maxSymbolValue_tooLarge, ZSTD_error_maxSymbolValue_tooSmall, diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 6ade3871..ace0ad30 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -148,12 +148,6 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) return 0; } -ZSTD_DCtx* ZSTD_createDCtx(void) -{ - ZSTD_customMem customMem = { NULL, NULL }; - return ZSTD_createDCtx_advanced(customMem); -} - ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) { ZSTD_DCtx* dctx; @@ -180,6 +174,12 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) return dctx; } +ZSTD_DCtx* ZSTD_createDCtx(void) +{ + ZSTD_customMem const customMem = { NULL, NULL }; + return ZSTD_createDCtx_advanced(customMem); +} + size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) { @@ -340,9 +340,9 @@ size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t BYTE const checkByte = ip[5]; size_t pos = ZSTD_frameHeaderSize_min; U32 const dictIDSizeCode = checkByte&3; - fparamsPtr->windowLog = (allocByte & 0xF) + ZSTD_WINDOWLOG_ABSOLUTEMIN; if ((allocByte & 0x30) != 0) return ERROR(frameParameter_unsupported); /* reserved bits */ if ((checkByte & 0xEC) != 0) return ERROR(frameParameter_unsupported); /* reserved bits */ + fparamsPtr->windowLog = (allocByte & 0xF) + ZSTD_WINDOWLOG_ABSOLUTEMIN; fparamsPtr->checksumFlag = checkByte & 0x10; switch(dictIDSizeCode) /* fcsId */ { @@ -961,6 +961,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, if (cBlockSize == 0) break; /* bt_end */ if (ZSTD_isError(decodedSize)) return decodedSize; + if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, op, decodedSize); op += decodedSize; ip += cBlockSize; remainingSize -= cBlockSize; @@ -1065,6 +1066,13 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); if (ZSTD_isError(cBlockSize)) return cBlockSize; if (bp.blockType == bt_end) { + if (dctx->fParams.checksumFlag) { + U64 const h64 = XXH64_digest(&dctx->xxhState); + U32 const h32 = (U32)(h64>>11) & ((1<<22)-1); + const BYTE* const ip = (const BYTE*)src; + U32 const check32 = ip[2] + (ip[1] << 8) + ((ip[0] & 0x3F) << 16); + if (check32 != h32) return ERROR(checksum_wrong); + } dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; } else { @@ -1096,6 +1104,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c dctx->stage = ZSTDds_decodeBlockHeader; dctx->expected = ZSTD_blockHeaderSize; dctx->previousDstEnd = (char*)dst + rSize; + if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize); return rSize; } default: @@ -1112,18 +1121,19 @@ static void ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSi dctx->previousDstEnd = (const char*)dict + dictSize; } -static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* dict, size_t const dictSizeStart) { - size_t hSize, offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize; + size_t dictSize = dictSizeStart; - hSize = HUF_readDTableX4(dctx->hufTableX4, dict, dictSize); - if (HUF_isError(hSize)) return ERROR(dictionary_corrupted); - dict = (const char*)dict + hSize; - dictSize -= hSize; + { size_t const hSize = HUF_readDTableX4(dctx->hufTableX4, dict, dictSize); + if (HUF_isError(hSize)) return ERROR(dictionary_corrupted); + dict = (const char*)dict + hSize; + dictSize -= hSize; + } { short offcodeNCount[MaxOff+1]; U32 offcodeMaxValue=MaxOff, offcodeLog=OffFSELog; - offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize); + size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize); if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); { size_t const errorCode = FSE_buildDTable(dctx->OffTable, offcodeNCount, offcodeMaxValue, offcodeLog); if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); } @@ -1133,7 +1143,7 @@ static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* dict, size_t dictSiz { short matchlengthNCount[MaxML+1]; unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog; - matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize); + size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize); if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); { size_t const errorCode = FSE_buildDTable(dctx->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog); if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); } @@ -1143,14 +1153,15 @@ static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* dict, size_t dictSiz { short litlengthNCount[MaxLL+1]; unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog; - litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize); + size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize); if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); { size_t const errorCode = FSE_buildDTable(dctx->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog); if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); } + dictSize -= litlengthHeaderSize; } dctx->flagRepeatTable = 1; - return hSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize; + return dictSizeStart - dictSize; } static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)