diff options
author | Dave Rodgman <dave.rodgman@arm.com> | 2019-04-05 21:38:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-04-05 22:02:30 -0400 |
commit | b11ed18efa8f3dc58b259b812588317b765b1cfc (patch) | |
tree | f98183968067ec487a0fd4e732d3fa7ac7ff29cf | |
parent | 6147e136ff5071609b54f18982dea87706288e21 (diff) |
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>
-rw-r--r-- | Documentation/lzo.txt | 8 | ||||
-rw-r--r-- | lib/lzo/lzo1x_compress.c | 9 | ||||
-rw-r--r-- | lib/lzo/lzo1x_decompress_safe.c | 4 |
3 files changed, 12 insertions, 9 deletions
diff --git a/Documentation/lzo.txt b/Documentation/lzo.txt index f79934225d8d..ca983328976b 100644 --- a/Documentation/lzo.txt +++ b/Documentation/lzo.txt | |||
@@ -102,9 +102,11 @@ Byte sequences | |||
102 | dictionary which is empty, and that it will always be | 102 | dictionary which is empty, and that it will always be |
103 | invalid at this place. | 103 | invalid at this place. |
104 | 104 | ||
105 | 17 : bitstream version. If the first byte is 17, the next byte | 105 | 17 : bitstream version. If the first byte is 17, and compressed |
106 | gives the bitstream version (version 1 only). If the first byte | 106 | stream length is at least 5 bytes (length of shortest possible |
107 | is not 17, the bitstream version is 0. | 107 | versioned bitstream), the next byte gives the bitstream version |
108 | (version 1 only). | ||
109 | Otherwise, the bitstream version is 0. | ||
108 | 110 | ||
109 | 18..21 : copy 0..3 literals | 111 | 18..21 : copy 0..3 literals |
110 | state = (byte - 17) = 0..3 [ copy <state> literals ] | 112 | state = (byte - 17) = 0..3 [ copy <state> literals ] |
diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c index 4525fb094844..a8ede77afe0d 100644 --- a/lib/lzo/lzo1x_compress.c +++ b/lib/lzo/lzo1x_compress.c | |||
@@ -291,13 +291,14 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, | |||
291 | { | 291 | { |
292 | const unsigned char *ip = in; | 292 | const unsigned char *ip = in; |
293 | unsigned char *op = out; | 293 | unsigned char *op = out; |
294 | unsigned char *data_start; | ||
294 | size_t l = in_len; | 295 | size_t l = in_len; |
295 | size_t t = 0; | 296 | size_t t = 0; |
296 | signed char state_offset = -2; | 297 | signed char state_offset = -2; |
297 | unsigned int m4_max_offset; | 298 | unsigned int m4_max_offset; |
298 | 299 | ||
299 | // LZO v0 will never write 17 as first byte, | 300 | // LZO v0 will never write 17 as first byte (except for zero-length |
300 | // so this is used to version the bitstream | 301 | // input), so this is used to version the bitstream |
301 | if (bitstream_version > 0) { | 302 | if (bitstream_version > 0) { |
302 | *op++ = 17; | 303 | *op++ = 17; |
303 | *op++ = bitstream_version; | 304 | *op++ = bitstream_version; |
@@ -306,6 +307,8 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, | |||
306 | m4_max_offset = M4_MAX_OFFSET_V0; | 307 | m4_max_offset = M4_MAX_OFFSET_V0; |
307 | } | 308 | } |
308 | 309 | ||
310 | data_start = op; | ||
311 | |||
309 | while (l > 20) { | 312 | while (l > 20) { |
310 | size_t ll = l <= (m4_max_offset + 1) ? l : (m4_max_offset + 1); | 313 | size_t ll = l <= (m4_max_offset + 1) ? l : (m4_max_offset + 1); |
311 | uintptr_t ll_end = (uintptr_t) ip + ll; | 314 | 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 | if (t > 0) { | 327 | if (t > 0) { |
325 | const unsigned char *ii = in + in_len - t; | 328 | const unsigned char *ii = in + in_len - t; |
326 | 329 | ||
327 | if (op == out && t <= 238) { | 330 | if (op == data_start && t <= 238) { |
328 | *op++ = (17 + t); | 331 | *op++ = (17 + t); |
329 | } else if (t <= 3) { | 332 | } else if (t <= 3) { |
330 | op[state_offset] |= t; | 333 | op[state_offset] |= t; |
diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c index 6d2600ea3b55..9e07e9ef1aad 100644 --- a/lib/lzo/lzo1x_decompress_safe.c +++ b/lib/lzo/lzo1x_decompress_safe.c | |||
@@ -54,11 +54,9 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, | |||
54 | if (unlikely(in_len < 3)) | 54 | if (unlikely(in_len < 3)) |
55 | goto input_overrun; | 55 | goto input_overrun; |
56 | 56 | ||
57 | if (likely(*ip == 17)) { | 57 | if (likely(in_len >= 5) && likely(*ip == 17)) { |
58 | bitstream_version = ip[1]; | 58 | bitstream_version = ip[1]; |
59 | ip += 2; | 59 | ip += 2; |
60 | if (unlikely(in_len < 5)) | ||
61 | goto input_overrun; | ||
62 | } else { | 60 | } else { |
63 | bitstream_version = 0; | 61 | bitstream_version = 0; |
64 | } | 62 | } |