Commit b11ed18e authored by Dave Rodgman's avatar Dave Rodgman Committed by Linus Torvalds

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.comSigned-off-by: default avatarDave Rodgman <dave.rodgman@arm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6147e136
...@@ -102,9 +102,11 @@ Byte sequences ...@@ -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 ]
......
...@@ -291,13 +291,14 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, ...@@ -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, ...@@ -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, ...@@ -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;
......
...@@ -54,11 +54,9 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, ...@@ -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;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment