mirror of
https://github.com/facebook/zstd.git
synced 2025-03-07 01:10:04 +02:00
Merge pull request #3439 from daniellerozenblit/sequence-validation-bug-fix
Fix sequence validation and seqStore bounds check
This commit is contained in:
commit
9116000be6
@ -53,6 +53,7 @@ const char* ERR_getErrorString(ERR_enum code)
|
|||||||
case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong";
|
case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong";
|
||||||
case PREFIX(srcBuffer_wrong): return "Source buffer is wrong";
|
case PREFIX(srcBuffer_wrong): return "Source buffer is wrong";
|
||||||
case PREFIX(externalMatchFinder_failed): return "External matchfinder returned an error code";
|
case PREFIX(externalMatchFinder_failed): return "External matchfinder returned an error code";
|
||||||
|
case PREFIX(externalSequences_invalid): return "External sequences are not valid";
|
||||||
case PREFIX(maxCode):
|
case PREFIX(maxCode):
|
||||||
default: return notErrorCode;
|
default: return notErrorCode;
|
||||||
}
|
}
|
||||||
|
@ -6195,8 +6195,8 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx,
|
|||||||
* @returns a ZSTD error code if sequence is not valid
|
* @returns a ZSTD error code if sequence is not valid
|
||||||
*/
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
ZSTD_validateSequence(U32 offCode, U32 matchLength,
|
ZSTD_validateSequence(U32 offCode, U32 matchLength, U32 minMatch,
|
||||||
size_t posInSrc, U32 windowLog, size_t dictSize)
|
size_t posInSrc, U32 windowLog, size_t dictSize, int useExternalMatchFinder)
|
||||||
{
|
{
|
||||||
U32 const windowSize = 1u << windowLog;
|
U32 const windowSize = 1u << windowLog;
|
||||||
/* posInSrc represents the amount of data the decoder would decode up to this point.
|
/* posInSrc represents the amount of data the decoder would decode up to this point.
|
||||||
@ -6205,8 +6205,10 @@ ZSTD_validateSequence(U32 offCode, U32 matchLength,
|
|||||||
* window size. After output surpasses windowSize, we're limited to windowSize offsets again.
|
* window size. After output surpasses windowSize, we're limited to windowSize offsets again.
|
||||||
*/
|
*/
|
||||||
size_t const offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize;
|
size_t const offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize;
|
||||||
RETURN_ERROR_IF(offCode > OFFSET_TO_OFFBASE(offsetBound), corruption_detected, "Offset too large!");
|
size_t const matchLenLowerBound = (minMatch == 3 || useExternalMatchFinder) ? 3 : 4;
|
||||||
RETURN_ERROR_IF(matchLength < MINMATCH, corruption_detected, "Matchlength too small");
|
RETURN_ERROR_IF(offCode > OFFSET_TO_OFFBASE(offsetBound), externalSequences_invalid, "Offset too large!");
|
||||||
|
/* Validate maxNbSeq is large enough for the given matchLength and minMatch */
|
||||||
|
RETURN_ERROR_IF(matchLength < matchLenLowerBound, externalSequences_invalid, "Matchlength too small for the minMatch");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6259,11 +6261,11 @@ ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx,
|
|||||||
DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength);
|
DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength);
|
||||||
if (cctx->appliedParams.validateSequences) {
|
if (cctx->appliedParams.validateSequences) {
|
||||||
seqPos->posInSrc += litLength + matchLength;
|
seqPos->posInSrc += litLength + matchLength;
|
||||||
FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, seqPos->posInSrc,
|
FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc,
|
||||||
cctx->appliedParams.cParams.windowLog, dictSize),
|
cctx->appliedParams.cParams.windowLog, dictSize, cctx->appliedParams.useExternalMatchFinder),
|
||||||
"Sequence validation failed");
|
"Sequence validation failed");
|
||||||
}
|
}
|
||||||
RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation,
|
RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid,
|
||||||
"Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
|
"Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
|
||||||
ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength);
|
ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength);
|
||||||
ip += matchLength + litLength;
|
ip += matchLength + litLength;
|
||||||
@ -6371,12 +6373,12 @@ ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition*
|
|||||||
|
|
||||||
if (cctx->appliedParams.validateSequences) {
|
if (cctx->appliedParams.validateSequences) {
|
||||||
seqPos->posInSrc += litLength + matchLength;
|
seqPos->posInSrc += litLength + matchLength;
|
||||||
FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, seqPos->posInSrc,
|
FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc,
|
||||||
cctx->appliedParams.cParams.windowLog, dictSize),
|
cctx->appliedParams.cParams.windowLog, dictSize, cctx->appliedParams.useExternalMatchFinder),
|
||||||
"Sequence validation failed");
|
"Sequence validation failed");
|
||||||
}
|
}
|
||||||
DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength);
|
DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength);
|
||||||
RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation,
|
RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid,
|
||||||
"Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
|
"Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
|
||||||
ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength);
|
ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength);
|
||||||
ip += matchLength + litLength;
|
ip += matchLength + litLength;
|
||||||
|
@ -94,6 +94,7 @@ typedef enum {
|
|||||||
ZSTD_error_dstBuffer_wrong = 104,
|
ZSTD_error_dstBuffer_wrong = 104,
|
||||||
ZSTD_error_srcBuffer_wrong = 105,
|
ZSTD_error_srcBuffer_wrong = 105,
|
||||||
ZSTD_error_externalMatchFinder_failed = 106,
|
ZSTD_error_externalMatchFinder_failed = 106,
|
||||||
|
ZSTD_error_externalSequences_invalid = 107,
|
||||||
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
|
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
|
||||||
} ZSTD_ErrorCode;
|
} ZSTD_ErrorCode;
|
||||||
|
|
||||||
|
@ -2087,6 +2087,107 @@ static int basicUnitTests(U32 seed, double compressibility, int bigTests)
|
|||||||
}
|
}
|
||||||
DISPLAYLEVEL(3, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
|
/* Test Sequence Validation */
|
||||||
|
DISPLAYLEVEL(3, "test%3i : Testing sequence validation: ", testNb++);
|
||||||
|
{
|
||||||
|
ZSTD_CCtx* cctx = ZSTD_createCCtx();
|
||||||
|
|
||||||
|
/* Test minMatch >= 4, matchLength < 4 */
|
||||||
|
{
|
||||||
|
size_t srcSize = 11;
|
||||||
|
void* const src = CNBuffer;
|
||||||
|
size_t dstSize = ZSTD_compressBound(srcSize);
|
||||||
|
void* const dst = compressedBuffer;
|
||||||
|
size_t const kNbSequences = 4;
|
||||||
|
ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
|
||||||
|
|
||||||
|
memset(src, 'x', srcSize);
|
||||||
|
|
||||||
|
sequences[0] = (ZSTD_Sequence) {1, 1, 3, 0};
|
||||||
|
sequences[1] = (ZSTD_Sequence) {1, 0, 3, 0};
|
||||||
|
sequences[2] = (ZSTD_Sequence) {1, 0, 3, 0};
|
||||||
|
sequences[3] = (ZSTD_Sequence) {0, 1, 0, 0};
|
||||||
|
|
||||||
|
/* Test with sequence validation */
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1));
|
||||||
|
|
||||||
|
cSize = ZSTD_compressSequences(cctx, dst, dstSize,
|
||||||
|
sequences, kNbSequences,
|
||||||
|
src, srcSize);
|
||||||
|
|
||||||
|
CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
|
||||||
|
CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
|
||||||
|
|
||||||
|
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
|
||||||
|
|
||||||
|
/* Test without sequence validation */
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 0));
|
||||||
|
|
||||||
|
cSize = ZSTD_compressSequences(cctx, dst, dstSize,
|
||||||
|
sequences, kNbSequences,
|
||||||
|
src, srcSize);
|
||||||
|
|
||||||
|
CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
|
||||||
|
CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
|
||||||
|
|
||||||
|
free(sequences);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
|
||||||
|
|
||||||
|
{ /* Test case with two additional sequences */
|
||||||
|
size_t srcSize = 19;
|
||||||
|
void* const src = CNBuffer;
|
||||||
|
size_t dstSize = ZSTD_compressBound(srcSize);
|
||||||
|
void* const dst = compressedBuffer;
|
||||||
|
size_t const kNbSequences = 7;
|
||||||
|
ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
|
||||||
|
|
||||||
|
memset(src, 'x', srcSize);
|
||||||
|
|
||||||
|
sequences[0] = (ZSTD_Sequence) {1, 1, 3, 0};
|
||||||
|
sequences[1] = (ZSTD_Sequence) {1, 0, 3, 0};
|
||||||
|
sequences[2] = (ZSTD_Sequence) {1, 0, 3, 0};
|
||||||
|
sequences[3] = (ZSTD_Sequence) {1, 0, 3, 0};
|
||||||
|
sequences[4] = (ZSTD_Sequence) {1, 0, 3, 0};
|
||||||
|
sequences[5] = (ZSTD_Sequence) {1, 0, 3, 0};
|
||||||
|
sequences[6] = (ZSTD_Sequence) {0, 0, 0, 0};
|
||||||
|
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1));
|
||||||
|
|
||||||
|
cSize = ZSTD_compressSequences(cctx, dst, dstSize,
|
||||||
|
sequences, kNbSequences,
|
||||||
|
src, srcSize);
|
||||||
|
|
||||||
|
CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
|
||||||
|
CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
|
||||||
|
|
||||||
|
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
|
||||||
|
|
||||||
|
/* Test without sequence validation */
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
|
||||||
|
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 0));
|
||||||
|
|
||||||
|
cSize = ZSTD_compressSequences(cctx, dst, dstSize,
|
||||||
|
sequences, kNbSequences,
|
||||||
|
src, srcSize);
|
||||||
|
|
||||||
|
CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
|
||||||
|
CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
|
||||||
|
|
||||||
|
free(sequences);
|
||||||
|
}
|
||||||
|
ZSTD_freeCCtx(cctx);
|
||||||
|
}
|
||||||
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
_end:
|
_end:
|
||||||
FUZ_freeDictionary(dictionary);
|
FUZ_freeDictionary(dictionary);
|
||||||
ZSTD_freeCStream(zc);
|
ZSTD_freeCStream(zc);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user