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

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: 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
Loading
Loading
Loading
Loading
+5 −3
Original line number Original line Diff line number Diff line
@@ -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 ]
+6 −3
Original line number Original line Diff line number Diff line
@@ -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;
+1 −3
Original line number Original line Diff line number Diff line
@@ -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;
	}
	}