Guard against invalid sequences from external matchfinders (#3465)
This commit is contained in:
@@ -277,14 +277,8 @@ static ZSTD_paramSwitch_e ZSTD_resolveEnableLdm(ZSTD_paramSwitch_e mode,
|
||||
return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27) ? ZSTD_ps_enable : ZSTD_ps_disable;
|
||||
}
|
||||
|
||||
/* Enables validation for external sequences in debug builds. */
|
||||
static int ZSTD_resolveExternalSequenceValidation(int mode) {
|
||||
#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=2)
|
||||
(void)mode;
|
||||
return 1;
|
||||
#else
|
||||
return mode;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Resolves maxBlockSize to the default if no value is present. */
|
||||
@@ -3050,6 +3044,23 @@ static size_t ZSTD_postProcessExternalMatchFinderResult(
|
||||
}
|
||||
}
|
||||
|
||||
/* ZSTD_fastSequenceLengthSum() :
|
||||
* Returns sum(litLen) + sum(matchLen) + lastLits for *seqBuf*.
|
||||
* Similar to another function in zstd_compress.c (determine_blockSize),
|
||||
* except it doesn't check for a block delimiter to end summation.
|
||||
* Removing the early exit allows the compiler to auto-vectorize (https://godbolt.org/z/cY1cajz9P).
|
||||
* This function can be deleted and replaced by determine_blockSize after we resolve issue #3456. */
|
||||
static size_t ZSTD_fastSequenceLengthSum(ZSTD_Sequence const* seqBuf, size_t seqBufSize) {
|
||||
size_t matchLenSum, litLenSum, i;
|
||||
matchLenSum = 0;
|
||||
litLenSum = 0;
|
||||
for (i = 0; i < seqBufSize; i++) {
|
||||
litLenSum += seqBuf[i].litLength;
|
||||
matchLenSum += seqBuf[i].matchLength;
|
||||
}
|
||||
return litLenSum + matchLenSum;
|
||||
}
|
||||
|
||||
typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e;
|
||||
|
||||
static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
|
||||
@@ -3167,8 +3178,15 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
|
||||
/* Return early if there is no error, since we don't need to worry about last literals */
|
||||
if (!ZSTD_isError(nbPostProcessedSeqs)) {
|
||||
ZSTD_sequencePosition seqPos = {0,0,0};
|
||||
ZSTD_copySequencesToSeqStoreExplicitBlockDelim(
|
||||
zc, &seqPos, zc->externalMatchCtx.seqBuffer, nbPostProcessedSeqs, src, srcSize
|
||||
size_t const seqLenSum = ZSTD_fastSequenceLengthSum(zc->externalMatchCtx.seqBuffer, nbPostProcessedSeqs);
|
||||
RETURN_ERROR_IF(seqLenSum > srcSize, externalSequences_invalid, "External sequences imply too large a block!");
|
||||
FORWARD_IF_ERROR(
|
||||
ZSTD_copySequencesToSeqStoreExplicitBlockDelim(
|
||||
zc, &seqPos,
|
||||
zc->externalMatchCtx.seqBuffer, nbPostProcessedSeqs,
|
||||
src, srcSize
|
||||
),
|
||||
"Failed to copy external sequences to seqStore!"
|
||||
);
|
||||
ms->ldmSeqStore = NULL;
|
||||
DEBUGLOG(5, "Copied %lu sequences from external matchfinder to internal seqStore.", (unsigned long)nbExternalSeqs);
|
||||
@@ -6286,7 +6304,7 @@ ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx,
|
||||
ip += inSeqs[idx].litLength;
|
||||
seqPos->posInSrc += inSeqs[idx].litLength;
|
||||
}
|
||||
RETURN_ERROR_IF(ip != iend, corruption_detected, "Blocksize doesn't agree with block delimiter!");
|
||||
RETURN_ERROR_IF(ip != iend, externalSequences_invalid, "Blocksize doesn't agree with block delimiter!");
|
||||
seqPos->idx = idx+1;
|
||||
return 0;
|
||||
}
|
||||
@@ -6444,13 +6462,13 @@ blockSize_explicitDelimiter(const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD
|
||||
blockSize += inSeqs[spos].litLength + inSeqs[spos].matchLength;
|
||||
if (end) {
|
||||
if (inSeqs[spos].matchLength != 0)
|
||||
RETURN_ERROR(corruption_detected, "delimiter format error : both matchlength and offset must be == 0");
|
||||
RETURN_ERROR(externalSequences_invalid, "delimiter format error : both matchlength and offset must be == 0");
|
||||
break;
|
||||
}
|
||||
spos++;
|
||||
}
|
||||
if (!end)
|
||||
RETURN_ERROR(corruption_detected, "Reached end of sequences without finding a block delimiter");
|
||||
RETURN_ERROR(externalSequences_invalid, "Reached end of sequences without finding a block delimiter");
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
@@ -6471,9 +6489,9 @@ static size_t determine_blockSize(ZSTD_sequenceFormat_e mode,
|
||||
{ size_t const explicitBlockSize = blockSize_explicitDelimiter(inSeqs, inSeqsSize, seqPos);
|
||||
FORWARD_IF_ERROR(explicitBlockSize, "Error while determining block size with explicit delimiters");
|
||||
if (explicitBlockSize > blockSize)
|
||||
RETURN_ERROR(corruption_detected, "sequences incorrectly define a too large block");
|
||||
RETURN_ERROR(externalSequences_invalid, "sequences incorrectly define a too large block");
|
||||
if (explicitBlockSize > remaining)
|
||||
RETURN_ERROR(srcSize_wrong, "sequences define a frame longer than source");
|
||||
RETURN_ERROR(externalSequences_invalid, "sequences define a frame longer than source");
|
||||
return explicitBlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user