Skip to content

Commit

Permalink
lib/lzo: fix bugs for very short or empty input
Browse files Browse the repository at this point in the history
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/[email protected]
Signed-off-by: Dave Rodgman <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
daverodgman authored and torvalds committed Apr 6, 2019
1 parent 6147e13 commit b11ed18
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 9 deletions.
8 changes: 5 additions & 3 deletions Documentation/lzo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,11 @@ Byte sequences
dictionary which is empty, and that it will always be
invalid at this place.

17 : bitstream version. If the first byte is 17, the next byte
gives the bitstream version (version 1 only). If the first byte
is not 17, the bitstream version is 0.
17 : bitstream version. If the first byte is 17, and compressed
stream length is at least 5 bytes (length of shortest possible
versioned bitstream), the next byte gives the bitstream version
(version 1 only).
Otherwise, the bitstream version is 0.

18..21 : copy 0..3 literals
state = (byte - 17) = 0..3 [ copy <state> literals ]
Expand Down
9 changes: 6 additions & 3 deletions lib/lzo/lzo1x_compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,14 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
{
const unsigned char *ip = in;
unsigned char *op = out;
unsigned char *data_start;
size_t l = in_len;
size_t t = 0;
signed char state_offset = -2;
unsigned int m4_max_offset;

// LZO v0 will never write 17 as first byte,
// so this is used to version the bitstream
// LZO v0 will never write 17 as first byte (except for zero-length
// input), so this is used to version the bitstream
if (bitstream_version > 0) {
*op++ = 17;
*op++ = bitstream_version;
Expand All @@ -306,6 +307,8 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
m4_max_offset = M4_MAX_OFFSET_V0;
}

data_start = op;

while (l > 20) {
size_t ll = l <= (m4_max_offset + 1) ? l : (m4_max_offset + 1);
uintptr_t ll_end = (uintptr_t) ip + ll;
Expand All @@ -324,7 +327,7 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
if (t > 0) {
const unsigned char *ii = in + in_len - t;

if (op == out && t <= 238) {
if (op == data_start && t <= 238) {
*op++ = (17 + t);
} else if (t <= 3) {
op[state_offset] |= t;
Expand Down
4 changes: 1 addition & 3 deletions lib/lzo/lzo1x_decompress_safe.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,9 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
if (unlikely(in_len < 3))
goto input_overrun;

if (likely(*ip == 17)) {
if (likely(in_len >= 5) && likely(*ip == 17)) {
bitstream_version = ip[1];
ip += 2;
if (unlikely(in_len < 5))
goto input_overrun;
} else {
bitstream_version = 0;
}
Expand Down

0 comments on commit b11ed18

Please sign in to comment.