lzo: properly check for overruns
The lzo decompressor can, if given some really crazy data, possibly overrun some variable types. Modify the checking logic to properly detect overruns before they happen. Reported-by: "Don A. Bailey" <donb@securitymouse.com> Tested-by: "Don A. Bailey" <donb@securitymouse.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
					parent
					
						
							
								7171511eae
							
						
					
				
			
			
				commit
				
					
						206a81c184
					
				
			
		
					 1 changed files with 41 additions and 21 deletions
				
			
		|  | @ -19,11 +19,31 @@ | |||
| #include <linux/lzo.h> | ||||
| #include "lzodefs.h" | ||||
| 
 | ||||
| #define HAVE_IP(x)      ((size_t)(ip_end - ip) >= (size_t)(x)) | ||||
| #define HAVE_OP(x)      ((size_t)(op_end - op) >= (size_t)(x)) | ||||
| #define NEED_IP(x)      if (!HAVE_IP(x)) goto input_overrun | ||||
| #define NEED_OP(x)      if (!HAVE_OP(x)) goto output_overrun | ||||
| #define TEST_LB(m_pos)  if ((m_pos) < out) goto lookbehind_overrun | ||||
| #define HAVE_IP(t, x)					\ | ||||
| 	(((size_t)(ip_end - ip) >= (size_t)(t + x)) &&	\ | ||||
| 	 (((t + x) >= t) && ((t + x) >= x))) | ||||
| 
 | ||||
| #define HAVE_OP(t, x)					\ | ||||
| 	(((size_t)(op_end - op) >= (size_t)(t + x)) &&	\ | ||||
| 	 (((t + x) >= t) && ((t + x) >= x))) | ||||
| 
 | ||||
| #define NEED_IP(t, x)					\ | ||||
| 	do {						\ | ||||
| 		if (!HAVE_IP(t, x))			\ | ||||
| 			goto input_overrun;		\ | ||||
| 	} while (0) | ||||
| 
 | ||||
| #define NEED_OP(t, x)					\ | ||||
| 	do {						\ | ||||
| 		if (!HAVE_OP(t, x))			\ | ||||
| 			goto output_overrun;		\ | ||||
| 	} while (0) | ||||
| 
 | ||||
| #define TEST_LB(m_pos)					\ | ||||
| 	do {						\ | ||||
| 		if ((m_pos) < out)			\ | ||||
| 			goto lookbehind_overrun;	\ | ||||
| 	} while (0) | ||||
| 
 | ||||
| int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, | ||||
| 			  unsigned char *out, size_t *out_len) | ||||
|  | @ -58,14 +78,14 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, | |||
| 					while (unlikely(*ip == 0)) { | ||||
| 						t += 255; | ||||
| 						ip++; | ||||
| 						NEED_IP(1); | ||||
| 						NEED_IP(1, 0); | ||||
| 					} | ||||
| 					t += 15 + *ip++; | ||||
| 				} | ||||
| 				t += 3; | ||||
| copy_literal_run: | ||||
| #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) | ||||
| 				if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) { | ||||
| 				if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) { | ||||
| 					const unsigned char *ie = ip + t; | ||||
| 					unsigned char *oe = op + t; | ||||
| 					do { | ||||
|  | @ -81,8 +101,8 @@ copy_literal_run: | |||
| 				} else | ||||
| #endif | ||||
| 				{ | ||||
| 					NEED_OP(t); | ||||
| 					NEED_IP(t + 3); | ||||
| 					NEED_OP(t, 0); | ||||
| 					NEED_IP(t, 3); | ||||
| 					do { | ||||
| 						*op++ = *ip++; | ||||
| 					} while (--t > 0); | ||||
|  | @ -95,7 +115,7 @@ copy_literal_run: | |||
| 				m_pos -= t >> 2; | ||||
| 				m_pos -= *ip++ << 2; | ||||
| 				TEST_LB(m_pos); | ||||
| 				NEED_OP(2); | ||||
| 				NEED_OP(2, 0); | ||||
| 				op[0] = m_pos[0]; | ||||
| 				op[1] = m_pos[1]; | ||||
| 				op += 2; | ||||
|  | @ -119,10 +139,10 @@ copy_literal_run: | |||
| 				while (unlikely(*ip == 0)) { | ||||
| 					t += 255; | ||||
| 					ip++; | ||||
| 					NEED_IP(1); | ||||
| 					NEED_IP(1, 0); | ||||
| 				} | ||||
| 				t += 31 + *ip++; | ||||
| 				NEED_IP(2); | ||||
| 				NEED_IP(2, 0); | ||||
| 			} | ||||
| 			m_pos = op - 1; | ||||
| 			next = get_unaligned_le16(ip); | ||||
|  | @ -137,10 +157,10 @@ copy_literal_run: | |||
| 				while (unlikely(*ip == 0)) { | ||||
| 					t += 255; | ||||
| 					ip++; | ||||
| 					NEED_IP(1); | ||||
| 					NEED_IP(1, 0); | ||||
| 				} | ||||
| 				t += 7 + *ip++; | ||||
| 				NEED_IP(2); | ||||
| 				NEED_IP(2, 0); | ||||
| 			} | ||||
| 			next = get_unaligned_le16(ip); | ||||
| 			ip += 2; | ||||
|  | @ -154,7 +174,7 @@ copy_literal_run: | |||
| #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) | ||||
| 		if (op - m_pos >= 8) { | ||||
| 			unsigned char *oe = op + t; | ||||
| 			if (likely(HAVE_OP(t + 15))) { | ||||
| 			if (likely(HAVE_OP(t, 15))) { | ||||
| 				do { | ||||
| 					COPY8(op, m_pos); | ||||
| 					op += 8; | ||||
|  | @ -164,7 +184,7 @@ copy_literal_run: | |||
| 					m_pos += 8; | ||||
| 				} while (op < oe); | ||||
| 				op = oe; | ||||
| 				if (HAVE_IP(6)) { | ||||
| 				if (HAVE_IP(6, 0)) { | ||||
| 					state = next; | ||||
| 					COPY4(op, ip); | ||||
| 					op += next; | ||||
|  | @ -172,7 +192,7 @@ copy_literal_run: | |||
| 					continue; | ||||
| 				} | ||||
| 			} else { | ||||
| 				NEED_OP(t); | ||||
| 				NEED_OP(t, 0); | ||||
| 				do { | ||||
| 					*op++ = *m_pos++; | ||||
| 				} while (op < oe); | ||||
|  | @ -181,7 +201,7 @@ copy_literal_run: | |||
| #endif | ||||
| 		{ | ||||
| 			unsigned char *oe = op + t; | ||||
| 			NEED_OP(t); | ||||
| 			NEED_OP(t, 0); | ||||
| 			op[0] = m_pos[0]; | ||||
| 			op[1] = m_pos[1]; | ||||
| 			op += 2; | ||||
|  | @ -194,15 +214,15 @@ match_next: | |||
| 		state = next; | ||||
| 		t = next; | ||||
| #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) | ||||
| 		if (likely(HAVE_IP(6) && HAVE_OP(4))) { | ||||
| 		if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) { | ||||
| 			COPY4(op, ip); | ||||
| 			op += t; | ||||
| 			ip += t; | ||||
| 		} else | ||||
| #endif | ||||
| 		{ | ||||
| 			NEED_IP(t + 3); | ||||
| 			NEED_OP(t); | ||||
| 			NEED_IP(t, 3); | ||||
| 			NEED_OP(t, 0); | ||||
| 			while (t > 0) { | ||||
| 				*op++ = *ip++; | ||||
| 				t--; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Greg Kroah-Hartman
				Greg Kroah-Hartman