diff --git a/wiretap/ngsniffer.c b/wiretap/ngsniffer.c
index 99feaa2..888ed25 100644 (file)
--- a/wiretap/ngsniffer.c
+++ b/wiretap/ngsniffer.c
@@ -2242,7 +2242,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;
@@ -2250,20 +2251,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 = pletoh16(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 = pletoh16(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
@@ -2358,6 +2369,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 */
@@ -2387,6 +2404,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 */
@@ -2395,10 +2418,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 */