On Sep 9, 2014, at 3:11 PM, Lewis Burns <[email protected]> wrote:

> We've recently done some unit testing on open source projects. One of issues 
> we've found is related to the SnifferDecompress function in the 
> wiretap/ngsniffer.c file. We're unable to determine that the memory issues 
> shown by valgrind can actually appear in the program due to our unfamiliarity 
> with the code base. I'm sending in a small testcase to the list and hoping 
> that some developers can validate or invalidate that this is a bug in the 
> code.

There's one place where the code isn't doing bounds checking, which probably 
accounts for

> ==5795== Invalid write of size 1
> ==5795==    at 0x400798: SnifferDecompress (in 
> /home/chaoqiang/workspace/se/klee/exp/a.out)
> ==5795==    by 0x400B6F: main (in /home/chaoqiang/workspace/se/klee/exp/a.out)
> ==5795==  Address 0x521d080 is 0 bytes after a block of size 65,536 alloc'd
> ==5795==    at 0x4C2AB80: malloc (in 
> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
> ==5795==    by 0x400AE8: main (in /home/chaoqiang/workspace/se/klee/exp/a.out)

as, when I tried reproducing this, with a version of the test program built 
with -g, it reported

==55119== Invalid write of size 1
==55119==    at 0x100001618: SnifferDecompress (ngsniffer_noklee.c:90)
==55119==    by 0x100001E32: main (ngsniffer_noklee.c:250)
==55119==  Address 0x10003c150 is 0 bytes after a block of size 65,536 alloc'd
==55119==    at 0xC658: malloc (vg_replace_malloc.c:295)
==55119==    by 0x100001D83: main (ngsniffer_noklee.c:241)

which is the "*(pout++) = *(pin++);" in

                /* 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 */
                        *(pout++) = *(pin++);
                }

which, unlike other code copying to the output buffer, doesn't do a bounds 
check.

I couldn't reproduce the overlap complaint, but perhaps valgrind doesn't 
replace memcpy() on OS X or perhaps its replacement memcpy() doesn't check for 
overlaps.  I *suspect* the overlap problems come from

                        case 2  :   /* LZ77 long strings */
                                /*
                                  Low 4 bits of offset to string is the low 
nybble of the
                                  first code byte, upper 8 bits of offset is in
                                  the next byte.
                                  Length of string immediately follows.
                                  Total code size: 3 bytes.
                                */
                                offset = code_low + ((unsigned int)(*pin++) << 
4) + 3;
                                /* If we are already at end of input, there is 
no byte
                                   to repeat */
                                if ( pin >= pin_end )
                                {
                                        *err = WTAP_ERR_UNC_TRUNCATED;   /* 
data was oddly truncated */
                                        return ( -1 );
                                }
                                /* Check if offset would put us back past begin 
of buffer */
                                if ( pout - offset < outbuf )
                                {
                                        *err = WTAP_ERR_UNC_BAD_OFFSET;
                                        return ( -1 );
                                }

                                /* get length from next byte, make sure it 
won't overrun buf */
                                length = (unsigned int)(*pin++) + 16;
                                if ( pout + length > pout_end )
                                {
                                        *err = WTAP_ERR_UNC_OVERFLOW;
                                        return ( -1 );
                                }

                                /* Copy the string from previous text to output 
position,
                                   advance output pointer */
                                memcpy( pout, pout - offset, length );
                                pout += length;
                                break;
                        default :   /* (3 to 15): LZ77 short strings */
                                /*
                                  Low 4 bits of offset to string is the low 
nybble of the
                                  first code byte, upper 8 bits of offset is in
                                  the next byte.
                                  Length of string to repeat is overloaded into 
code_type.
                                  Total code size: 2 bytes.
                                */
                                offset = code_low + ((unsigned int)(*pin++) << 
4) + 3;
                                /* Check if offset would put us back past begin 
of buffer */
                                if ( pout - offset < outbuf )
                                {
                                        *err = WTAP_ERR_UNC_BAD_OFFSET;
                                        return ( -1 );
                                }

                                /* get length from code_type, make sure it 
won't overrun buf */
                                length = code_type;
                                if ( pout + length > pout_end )
                                {
                                        *err = WTAP_ERR_UNC_OVERFLOW;
                                        return ( -1 );
                                }

                                /* Copy the string from previous text to output 
position,
                                   advance output pointer */
                                memcpy( pout, pout - offset, length );
                                pout += length;
                                break;

where it's *supposed* to be copying a string from earlier in the decompressed 
output (thus being before the current position in the output, and thus not 
overlapping), but isn't checking to make sure that the source is fully within 
the already-produced portion of the output.

I'll check in fixes for both of those problems.

Thanks.

> Steps to repeat the issue:
>  gcc -DRANDOM ngsniffer_noklee.c

As per the above

        gcc -g -DRANDOM ngsniffer_noklee.c

may produce better debugging output from valgrind, with line numbers.
___________________________________________________________________________
Sent via:    Wireshark-dev mailing list <[email protected]>
Archives:    http://www.wireshark.org/lists/wireshark-dev
Unsubscribe: https://wireshark.org/mailman/options/wireshark-dev
             mailto:[email protected]?subject=unsubscribe

Reply via email to