1
0
Fork 0

lib/lzo: fix bugs for very short or empty input

For very short input data (0 - 1 bytes), lzo-rle was not behaving
correctly.  Fix this behaviour and update documentation accordingly.

For zero-length input, lzo v0 outputs an end-of-stream marker only,
which was misinterpreted by lzo-rle as a bitstream version number.
Ensure bitstream versions > 0 require a minimum stream length of 5.

Also fixes a bug in handling the tail for very short inputs when a
bitstream version is present.

Link: http://lkml.kernel.org/r/20190326165857.34613-1-dave.rodgman@arm.com
Signed-off-by: Dave Rodgman <dave.rodgman@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
hifive-unleashed-5.1
Dave Rodgman 2019-04-05 18:38:58 -07:00 committed by Linus Torvalds
parent 6147e136ff
commit b11ed18efa
3 changed files with 12 additions and 9 deletions

View File

@ -102,9 +102,11 @@ Byte sequences
dictionary which is empty, and that it will always be dictionary which is empty, and that it will always be
invalid at this place. invalid at this place.
17 : bitstream version. If the first byte is 17, the next byte 17 : bitstream version. If the first byte is 17, and compressed
gives the bitstream version (version 1 only). If the first byte stream length is at least 5 bytes (length of shortest possible
is not 17, the bitstream version is 0. versioned bitstream), the next byte gives the bitstream version
(version 1 only).
Otherwise, the bitstream version is 0.
18..21 : copy 0..3 literals 18..21 : copy 0..3 literals
state = (byte - 17) = 0..3 [ copy <state> literals ] state = (byte - 17) = 0..3 [ copy <state> literals ]

View File

@ -291,13 +291,14 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
{ {
const unsigned char *ip = in; const unsigned char *ip = in;
unsigned char *op = out; unsigned char *op = out;
unsigned char *data_start;
size_t l = in_len; size_t l = in_len;
size_t t = 0; size_t t = 0;
signed char state_offset = -2; signed char state_offset = -2;
unsigned int m4_max_offset; unsigned int m4_max_offset;
// LZO v0 will never write 17 as first byte, // LZO v0 will never write 17 as first byte (except for zero-length
// so this is used to version the bitstream // input), so this is used to version the bitstream
if (bitstream_version > 0) { if (bitstream_version > 0) {
*op++ = 17; *op++ = 17;
*op++ = bitstream_version; *op++ = bitstream_version;
@ -306,6 +307,8 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
m4_max_offset = M4_MAX_OFFSET_V0; m4_max_offset = M4_MAX_OFFSET_V0;
} }
data_start = op;
while (l > 20) { while (l > 20) {
size_t ll = l <= (m4_max_offset + 1) ? l : (m4_max_offset + 1); size_t ll = l <= (m4_max_offset + 1) ? l : (m4_max_offset + 1);
uintptr_t ll_end = (uintptr_t) ip + ll; uintptr_t ll_end = (uintptr_t) ip + ll;
@ -324,7 +327,7 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
if (t > 0) { if (t > 0) {
const unsigned char *ii = in + in_len - t; const unsigned char *ii = in + in_len - t;
if (op == out && t <= 238) { if (op == data_start && t <= 238) {
*op++ = (17 + t); *op++ = (17 + t);
} else if (t <= 3) { } else if (t <= 3) {
op[state_offset] |= t; op[state_offset] |= t;

View File

@ -54,11 +54,9 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
if (unlikely(in_len < 3)) if (unlikely(in_len < 3))
goto input_overrun; goto input_overrun;
if (likely(*ip == 17)) { if (likely(in_len >= 5) && likely(*ip == 17)) {
bitstream_version = ip[1]; bitstream_version = ip[1];
ip += 2; ip += 2;
if (unlikely(in_len < 5))
goto input_overrun;
} else { } else {
bitstream_version = 0; bitstream_version = 0;
} }