summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Rodgman <dave.rodgman@arm.com>2019-04-05 21:38:58 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-04-05 22:02:30 -0400
commitb11ed18efa8f3dc58b259b812588317b765b1cfc (patch)
treef98183968067ec487a0fd4e732d3fa7ac7ff29cf
parent6147e136ff5071609b54f18982dea87706288e21 (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.txt8
-rw-r--r--lib/lzo/lzo1x_compress.c9
-rw-r--r--lib/lzo/lzo1x_decompress_safe.c4
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 }