Date: Wed, 1 Sep 2010 07:58:01 GMT From: Guy Harris <guy@alum.mit.edu> To: freebsd-gnats-submit@FreeBSD.org Subject: misc/150176: p->cc can go negative in libpcap Message-ID: <201009010758.o817w11s014026@www.freebsd.org> Resent-Message-ID: <201009010800.o8180BEp092773@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 150176 >Category: misc >Synopsis: p->cc can go negative in libpcap >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Sep 01 08:00:10 UTC 2010 >Closed-Date: >Last-Modified: >Originator: Guy Harris >Release: Top of CVS tree >Organization: >Environment: >Description: In pcap_read_bpf(), ep is set based on the return value of read(), but read() from a BPF device doesn't necessarily return a value that's a multiple of the alignment value for BPF_WORDALIGN(). However, whenever we increment bp, we round up the increment value by a value rounded up by BPF_WORDALIGN(), so we could increment bp past ep after processing the last packet in the buffer. >How-To-Repeat: Run a program that opens a capture device with a timeout of 0, in a loop, calls pcap_dispatch() with a cnt argument of 1, and reports when it returns a value of 0. The timeout of 0 means that the read() that libpcap does shouldn't return until there's packet data, so a timeout won't cause pcap_dispatch() to return 0. Do a large amount of network data transfer, to fill up the BPF bucket; notice that, on occasion, the program will report that pcap_dispatch() returns 0. >Fix: Patch attached with submission follows: diff --git a/pcap-bpf.c b/pcap-bpf.c index 666acf9..bcbfbef 100644 --- a/pcap-bpf.c +++ b/pcap-bpf.c @@ -955,14 +955,28 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) * processed so far. */ if (p->break_loop) { + p->bp = bp; + p->cc = ep - bp; + /* + * ep is set based on the return value of read(), + * but read() from a BPF device doesn't necessarily + * return a value that's a multiple of the alignment + * value for BPF_WORDALIGN(). However, whenever we + * increment bp, we round up the increment value by + * a value rounded up by BPF_WORDALIGN(), so we + * could increment bp past ep after processing the + * last packet in the buffer. + * + * We treat ep < bp as an indication that this + * happened, and just set p->cc to 0. + */ + if (p->cc < 0) + p->cc = 0; if (n == 0) { p->break_loop = 0; return (PCAP_ERROR_BREAK); - } else { - p->bp = bp; - p->cc = ep - bp; + } else return (n); - } } caplen = bhp->bh_caplen; @@ -1014,6 +1028,11 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) if (++n >= cnt && cnt > 0) { p->bp = bp; p->cc = ep - bp; + /* + * See comment above about p->cc < 0. + */ + if (p->cc < 0) + p->cc = 0; return (n); } } else { >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009010758.o817w11s014026>