Module Name: src Committed By: christos Date: Mon Sep 9 20:53:52 UTC 2013
Modified Files: src/sys/net: bpf.c Log Message: PR/48198: Peter Bex: Avoid kernel panic caused by setting a very small bpf buffer size. XXX: Pullup -6 To generate a diff of this commit: cvs rdiff -u -r1.175 -r1.176 src/sys/net/bpf.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/bpf.c diff -u src/sys/net/bpf.c:1.175 src/sys/net/bpf.c:1.176 --- src/sys/net/bpf.c:1.175 Fri Aug 30 11:00:08 2013 +++ src/sys/net/bpf.c Mon Sep 9 16:53:51 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: bpf.c,v 1.175 2013/08/30 15:00:08 rmind Exp $ */ +/* $NetBSD: bpf.c,v 1.176 2013/09/09 20:53:51 christos Exp $ */ /* * Copyright (c) 1990, 1991, 1993 @@ -39,7 +39,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.175 2013/08/30 15:00:08 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.176 2013/09/09 20:53:51 christos Exp $"); #if defined(_KERNEL_OPT) #include "opt_bpf.h" @@ -1576,11 +1576,8 @@ static void catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, void *(*cpfn)(void *, const void *, size_t), struct timespec *ts) { - struct bpf_hdr *hp; -#ifdef _LP64 - struct bpf_hdr32 *hp32; -#endif - int totlen, curlen; + char *h; + int totlen, curlen, caplen; int hdrlen = bpf_hdrlen(d); int do_wakeup = 0; @@ -1595,6 +1592,13 @@ catchpacket(struct bpf_d *d, u_char *pkt totlen = hdrlen + min(snaplen, pktlen); if (totlen > d->bd_bufsize) totlen = d->bd_bufsize; + /* + * If we adjusted totlen to fit the bufsize, it could be that + * totlen is smaller than hdrlen because of the link layer header. + */ + caplen = totlen - hdrlen; + if (caplen < 0) + caplen = 0; /* * Round up the end of the previous packet to the next longword. @@ -1635,33 +1639,34 @@ catchpacket(struct bpf_d *d, u_char *pkt /* * Append the bpf header. */ + h = (char *)d->bd_sbuf + curlen; #ifdef _LP64 if (d->bd_compat32) { - hp32 = (struct bpf_hdr32 *)((char *)d->bd_sbuf + curlen); + struct bpf_hdr32 *hp32; + + hp32 = (struct bpf_hdr32 *)h; hp32->bh_tstamp.tv_sec = ts->tv_sec; hp32->bh_tstamp.tv_usec = ts->tv_nsec / 1000; hp32->bh_datalen = pktlen; hp32->bh_hdrlen = hdrlen; - /* - * Copy the packet data into the store buffer and update its length. - */ - (*cpfn)((u_char *)hp32 + hdrlen, pkt, - (hp32->bh_caplen = totlen - hdrlen)); + hp32->bh_caplen = caplen; } else #endif { - hp = (struct bpf_hdr *)((char *)d->bd_sbuf + curlen); + struct bpf_hdr *hp; + + hp = (struct bpf_hdr *)h; hp->bh_tstamp.tv_sec = ts->tv_sec; hp->bh_tstamp.tv_usec = ts->tv_nsec / 1000; hp->bh_datalen = pktlen; hp->bh_hdrlen = hdrlen; - /* - * Copy the packet data into the store buffer and update - * its length. - */ - (*cpfn)((u_char *)hp + hdrlen, pkt, - (hp->bh_caplen = totlen - hdrlen)); + hp->bh_caplen = caplen; } + + /* + * Copy the packet data into the store buffer and update its length. + */ + (*cpfn)(h + hdrlen, pkt, caplen); d->bd_slen = curlen + totlen; /*