Allow for safe in-place decoding

Add a check to allow safe "in-place" decoding (meaning that the
beginning of the source buffer partially overlaps the end of the
destination buffer). This is usually possible as long as the output
stops at least 15 bytes before the end of the input buffer (7 to account
for the extra spill from LZ4_wildCopy, 4 for a possible block checksum,
and 4 for the terminating block header), but in some pathological edge
cases it could be possible for the output stream to overwrite a byte in
the input stream before it gets decoded. With this patch the decoder
will reliably detect those cases and return a decoding error.

Signed-off-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
Julius Werner 2016-02-12 15:35:41 -08:00
parent 4fcb2e17fb
commit dc868cd5b1

View File

@ -1182,6 +1182,7 @@ FORCE_INLINE int LZ4_decompress_generic(
const int safeDecode = (endOnInput==endOnInputSize);
const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
const int inPlaceDecode = ((ip >= op) && (ip < oend));
/* Special cases */
@ -1198,6 +1199,8 @@ FORCE_INLINE int LZ4_decompress_generic(
const BYTE* match;
size_t offset;
if (unlikely((inPlaceDecode) && (op + WILDCOPYLENGTH > ip))) goto _output_error; /* output stream ran over input stream */
/* get literal length */
token = *ip++;
if ((length=(token>>ML_BITS)) == RUN_MASK)
@ -1228,7 +1231,7 @@ FORCE_INLINE int LZ4_decompress_generic(
if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
}
memcpy(op, ip, length);
memmove(op, ip, length);
ip += length;
op += length;
break; /* Necessarily EOF, due to parsing restrictions */