From dbdff35463796eef5965cfbb47d8f005b042ca24 Mon Sep 17 00:00:00 2001
From: Guy Harris <guy@alum.mit.edu>
Date: Thu, 11 Sep 2014 13:29:37 -0700
Subject: [PATCH 6/6] Add some additional checks in SnifferDecompress().

Check the input pointer in the while clause of the loop, so that we
handle an empty input buffer.

When reading a bit mask, check before fetching the bit mask that we have
two bytes of bit mask and the byte after it.

Before putting an uncompressed input byte into the output, make sure we
wouldn't run past the end of the output buffer.

Before copying an earlier string from the output buffer, make sure it
doesn't run past the end of the data we've decompressed so far.

Bug: 10461
Change-Id: I8bb8d0d291368ae8bf0ac26970ff54d3262a7e6e
Reviewed-on: https://code.wireshark.org/review/4083
Reviewed-by: Guy Harris <guy@alum.mit.edu>
(cherry picked from commit 47c592938ba9f0caeacc4c2ccadb370e72f293a2)
Reviewed-on: https://code.wireshark.org/review/4085
Reviewed-on: https://code.wireshark.org/review/4427
Reviewed-by: Balint Reczey <balint@balintreczey.hu>
Tested-by: Balint Reczey <balint@balintreczey.hu>
---
 wiretap/ngsniffer.c | 39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/wiretap/ngsniffer.c b/wiretap/ngsniffer.c
index 604fd30..3f2b2ad 100644
--- a/wiretap/ngsniffer.c
+++ b/wiretap/ngsniffer.c
@@ -2270,7 +2270,8 @@ SnifferDecompress(unsigned char *inbuf, size_t inlen, unsigned char *outbuf,
 	}
 
 	bit_mask  = 0;  /* don't have any bits yet */
-	while (1)
+	/* Process until we've consumed all the input */
+	while (pin < pin_end)
 	{
 		/* Shift down the bit mask we use to see whats encoded */
 		bit_mask = bit_mask >> 1;
@@ -2278,20 +2279,30 @@ SnifferDecompress(unsigned char *inbuf, size_t inlen, unsigned char *outbuf,
 		/* If there are no bits left, time to get another 16 bits */
 		if ( 0 == bit_mask )
 		{
-			bit_mask  = 0x8000;  /* start with the high bit */
-			bit_value = pletohs(pin);   /* get the next 16 bits */
-			pin += 2;          /* skip over what we just grabbed */
-			if ( pin >= pin_end )
+			/* make sure there are at least *three* bytes
+			   available - the two bytes of the bit value,
+			   plus one byte after it */
+			if ( pin + 2 >= pin_end )
 			{
-				*err = WTAP_ERR_UNC_TRUNCATED;	 /* data was oddly truncated */
+				*err = WTAP_ERR_UNC_TRUNCATED;
 				return ( -1 );
 			}
+			bit_mask  = 0x8000;  /* start with the high bit */
+			bit_value = pletohs(pin);   /* get the next 16 bits */
+			pin += 2;          /* skip over what we just grabbed */
 		}
 
 		/* Use the bits in bit_value to see what's encoded and what is raw data */
 		if ( !(bit_mask & bit_value) )
 		{
 			/* bit not set - raw byte we just copy */
+
+			/* If length would put us past end of output, avoid overflow */
+			if ( pout + 1 > pout_end )
+			{
+				*err = WTAP_ERR_UNC_OVERFLOW;
+				return ( -1 );
+			}
 			*(pout++) = *(pin++);
 		}
 		else
@@ -2386,6 +2397,12 @@ SnifferDecompress(unsigned char *inbuf, size_t inlen, unsigned char *outbuf,
 					*err = WTAP_ERR_UNC_OVERFLOW;
 					return ( -1 );
 				}
+				/* Check if offset would cause us to copy on top of ourselves */
+				if ( pout - offset + length > pout )
+				{
+					*err = WTAP_ERR_UNC_BAD_OFFSET;
+					return ( -1 );
+				}
 
 				/* Copy the string from previous text to output position,
 				   advance output pointer */
@@ -2415,6 +2432,12 @@ SnifferDecompress(unsigned char *inbuf, size_t inlen, unsigned char *outbuf,
 					*err = WTAP_ERR_UNC_OVERFLOW;
 					return ( -1 );
 				}
+				/* Check if offset would cause us to copy on top of ourselves */
+				if ( pout - offset + length > pout )
+				{
+					*err = WTAP_ERR_UNC_BAD_OFFSET;
+					return ( -1 );
+				}
 
 				/* Copy the string from previous text to output position,
 				   advance output pointer */
@@ -2423,10 +2446,6 @@ SnifferDecompress(unsigned char *inbuf, size_t inlen, unsigned char *outbuf,
 				break;
 			}
 		}
-
-		/* If we've consumed all the input, we are done */
-		if ( pin >= pin_end )
-			break;
 	}
 
 	return (int) ( pout - outbuf );  /* return length of expanded text */
-- 
2.1.1

