diff options
Diffstat (limited to 'lib/lzo/lzo1x_compress.c')
| -rw-r--r-- | lib/lzo/lzo1x_compress.c | 102 | 
1 files changed, 77 insertions, 25 deletions
| diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c index 47d6d43ea957..7b10ca86a893 100644 --- a/lib/lzo/lzo1x_compress.c +++ b/lib/lzo/lzo1x_compress.c @@ -18,11 +18,22 @@  #include <linux/lzo.h>  #include "lzodefs.h" -static noinline size_t -lzo1x_1_do_compress(const unsigned char *in, size_t in_len, -		    unsigned char *out, size_t *out_len, -		    size_t ti, void *wrkmem, signed char *state_offset, -		    const unsigned char bitstream_version) +#undef LZO_UNSAFE + +#ifndef LZO_SAFE +#define LZO_UNSAFE 1 +#define LZO_SAFE(name) name +#define HAVE_OP(x) 1 +#endif + +#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun + +static noinline int +LZO_SAFE(lzo1x_1_do_compress)(const unsigned char *in, size_t in_len, +			      unsigned char **out, unsigned char *op_end, +			      size_t *tp, void *wrkmem, +			      signed char *state_offset, +			      const unsigned char bitstream_version)  {  	const unsigned char *ip;  	unsigned char *op; @@ -30,8 +41,9 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,  	const unsigned char * const ip_end = in + in_len - 20;  	const unsigned char *ii;  	lzo_dict_t * const dict = (lzo_dict_t *) wrkmem; +	size_t ti = *tp; -	op = out; +	op = *out;  	ip = in;  	ii = ip;  	ip += ti < 4 ? 4 - ti : 0; @@ -116,25 +128,32 @@ next:  		if (t != 0) {  			if (t <= 3) {  				op[*state_offset] |= t; +				NEED_OP(4);  				COPY4(op, ii);  				op += t;  			} else if (t <= 16) { +				NEED_OP(17);  				*op++ = (t - 3);  				COPY8(op, ii);  				COPY8(op + 8, ii + 8);  				op += t;  			} else {  				if (t <= 18) { +					NEED_OP(1);  					*op++ = (t - 3);  				} else {  					size_t tt = t - 18; +					NEED_OP(1);  					*op++ = 0;  					while (unlikely(tt > 255)) {  						tt -= 255; +						NEED_OP(1);  						*op++ = 0;  					} +					NEED_OP(1);  					*op++ = tt;  				} +				NEED_OP(t);  				do {  					COPY8(op, ii);  					COPY8(op + 8, ii + 8); @@ -151,6 +170,7 @@ next:  		if (unlikely(run_length)) {  			ip += run_length;  			run_length -= MIN_ZERO_RUN_LENGTH; +			NEED_OP(4);  			put_unaligned_le32((run_length << 21) | 0xfffc18  					   | (run_length & 0x7), op);  			op += 4; @@ -243,10 +263,12 @@ m_len_done:  		ip += m_len;  		if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {  			m_off -= 1; +			NEED_OP(2);  			*op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2));  			*op++ = (m_off >> 3);  		} else if (m_off <= M3_MAX_OFFSET) {  			m_off -= 1; +			NEED_OP(1);  			if (m_len <= M3_MAX_LEN)  				*op++ = (M3_MARKER | (m_len - 2));  			else { @@ -254,14 +276,18 @@ m_len_done:  				*op++ = M3_MARKER | 0;  				while (unlikely(m_len > 255)) {  					m_len -= 255; +					NEED_OP(1);  					*op++ = 0;  				} +				NEED_OP(1);  				*op++ = (m_len);  			} +			NEED_OP(2);  			*op++ = (m_off << 2);  			*op++ = (m_off >> 6);  		} else {  			m_off -= 0x4000; +			NEED_OP(1);  			if (m_len <= M4_MAX_LEN)  				*op++ = (M4_MARKER | ((m_off >> 11) & 8)  						| (m_len - 2)); @@ -282,11 +308,14 @@ m_len_done:  				m_len -= M4_MAX_LEN;  				*op++ = (M4_MARKER | ((m_off >> 11) & 8));  				while (unlikely(m_len > 255)) { +					NEED_OP(1);  					m_len -= 255;  					*op++ = 0;  				} +				NEED_OP(1);  				*op++ = (m_len);  			} +			NEED_OP(2);  			*op++ = (m_off << 2);  			*op++ = (m_off >> 6);  		} @@ -295,14 +324,20 @@ finished_writing_instruction:  		ii = ip;  		goto next;  	} -	*out_len = op - out; -	return in_end - (ii - ti); +	*out = op; +	*tp = in_end - (ii - ti); +	return LZO_E_OK; + +output_overrun: +	return LZO_E_OUTPUT_OVERRUN;  } -static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, -		     unsigned char *out, size_t *out_len, -		     void *wrkmem, const unsigned char bitstream_version) +static int LZO_SAFE(lzogeneric1x_1_compress)( +	const unsigned char *in, size_t in_len, +	unsigned char *out, size_t *out_len, +	void *wrkmem, const unsigned char bitstream_version)  { +	unsigned char * const op_end = out + *out_len;  	const unsigned char *ip = in;  	unsigned char *op = out;  	unsigned char *data_start; @@ -326,14 +361,18 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,  	while (l > 20) {  		size_t ll = min_t(size_t, l, m4_max_offset + 1);  		uintptr_t ll_end = (uintptr_t) ip + ll; +		int err; +  		if ((ll_end + ((t + ll) >> 5)) <= ll_end)  			break;  		BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS);  		memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t)); -		t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem, -					&state_offset, bitstream_version); +		err = LZO_SAFE(lzo1x_1_do_compress)( +			ip, ll, &op, op_end, &t, wrkmem, +			&state_offset, bitstream_version); +		if (err != LZO_E_OK) +			return err;  		ip += ll; -		op += *out_len;  		l  -= ll;  	}  	t += l; @@ -342,20 +381,26 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,  		const unsigned char *ii = in + in_len - t;  		if (op == data_start && t <= 238) { +			NEED_OP(1);  			*op++ = (17 + t);  		} else if (t <= 3) {  			op[state_offset] |= t;  		} else if (t <= 18) { +			NEED_OP(1);  			*op++ = (t - 3);  		} else {  			size_t tt = t - 18; +			NEED_OP(1);  			*op++ = 0;  			while (tt > 255) {  				tt -= 255; +				NEED_OP(1);  				*op++ = 0;  			} +			NEED_OP(1);  			*op++ = tt;  		} +		NEED_OP(t);  		if (t >= 16) do {  			COPY8(op, ii);  			COPY8(op + 8, ii + 8); @@ -368,31 +413,38 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,  		} while (--t > 0);  	} +	NEED_OP(3);  	*op++ = M4_MARKER | 1;  	*op++ = 0;  	*op++ = 0;  	*out_len = op - out;  	return LZO_E_OK; + +output_overrun: +	return LZO_E_OUTPUT_OVERRUN;  } -int lzo1x_1_compress(const unsigned char *in, size_t in_len, -		     unsigned char *out, size_t *out_len, -		     void *wrkmem) +int LZO_SAFE(lzo1x_1_compress)(const unsigned char *in, size_t in_len, +			       unsigned char *out, size_t *out_len, +			       void *wrkmem)  { -	return lzogeneric1x_1_compress(in, in_len, out, out_len, wrkmem, 0); +	return LZO_SAFE(lzogeneric1x_1_compress)( +		in, in_len, out, out_len, wrkmem, 0);  } -int lzorle1x_1_compress(const unsigned char *in, size_t in_len, -		     unsigned char *out, size_t *out_len, -		     void *wrkmem) +int LZO_SAFE(lzorle1x_1_compress)(const unsigned char *in, size_t in_len, +				  unsigned char *out, size_t *out_len, +				  void *wrkmem)  { -	return lzogeneric1x_1_compress(in, in_len, out, out_len, -				       wrkmem, LZO_VERSION); +	return LZO_SAFE(lzogeneric1x_1_compress)( +		in, in_len, out, out_len, wrkmem, LZO_VERSION);  } -EXPORT_SYMBOL_GPL(lzo1x_1_compress); -EXPORT_SYMBOL_GPL(lzorle1x_1_compress); +EXPORT_SYMBOL_GPL(LZO_SAFE(lzo1x_1_compress)); +EXPORT_SYMBOL_GPL(LZO_SAFE(lzorle1x_1_compress)); +#ifndef LZO_UNSAFE  MODULE_LICENSE("GPL");  MODULE_DESCRIPTION("LZO1X-1 Compressor"); +#endif | 
