From owner-freebsd-bugs@FreeBSD.ORG Fri Jul 15 02:50:08 2011 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 7E74C106566C for ; Fri, 15 Jul 2011 02:50:08 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 215028FC12 for ; Fri, 15 Jul 2011 02:50:08 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p6F2o7Hh025958 for ; Fri, 15 Jul 2011 02:50:07 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p6F2o7kB025957; Fri, 15 Jul 2011 02:50:07 GMT (envelope-from gnats) Resent-Date: Fri, 15 Jul 2011 02:50:07 GMT Resent-Message-Id: <201107150250.p6F2o7kB025957@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, lanxiaowei Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 018FA106566B for ; Fri, 15 Jul 2011 02:42:51 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22]) by mx1.freebsd.org (Postfix) with ESMTP id DBD148FC12 for ; Fri, 15 Jul 2011 02:42:50 +0000 (UTC) Received: from red.freebsd.org (localhost [127.0.0.1]) by red.freebsd.org (8.14.4/8.14.4) with ESMTP id p6F2goBI048737 for ; Fri, 15 Jul 2011 02:42:50 GMT (envelope-from nobody@red.freebsd.org) Received: (from nobody@localhost) by red.freebsd.org (8.14.4/8.14.4/Submit) id p6F2goEN048734; Fri, 15 Jul 2011 02:42:50 GMT (envelope-from nobody) Message-Id: <201107150242.p6F2goEN048734@red.freebsd.org> Date: Fri, 15 Jul 2011 02:42:50 GMT From: lanxiaowei To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: kern/158930: BPF element leak in ifp->bpf_if->bif_dlist X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 15 Jul 2011 02:50:08 -0000 >Number: 158930 >Category: kern >Synopsis: BPF element leak in ifp->bpf_if->bif_dlist >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Jul 15 02:50:07 UTC 2011 >Closed-Date: >Last-Modified: >Originator: lanxiaowei >Release: bsd7.0 >Organization: arraynetworks >Environment: FreeBSD dev170-04.arraynetworks.net 7.0-RELEASE FreeBSD 7.0-RELEASE #0: Sun Feb 24 10:35:36 UTC 2008 root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC amd64 >Description: when i send arp repeatedly in userland by BPF, i find: when the data flow is large, the performance will be very slow. for example: if i dont' send arp, the data flow can reach 3.5G, if i send arp, the data flow can only reach 1.5G. Finally, i find the reason: the BPF will leak some device in ifp->bpf_if->bif_dlist, so the system will capture passing packets in ETHER_BPF_MTAP! >How-To-Repeat: 1. run daemon userland code: AN# cat a.c #include #include #include #include #include #include #include #include #include int open_bpf(char *ifname) { struct ifreq ifr; int fd, n = 0; char device[sizeof "/dev/bpf000"]; /* * Go through all the minors and find one that isn't in use. */ do { (void)sprintf(device, "/dev/bpf%d", n++); fd = open(device, O_RDWR); } while (fd < 0 && errno == EBUSY && n < 100); if (fd < 0) { return -1; } (void)strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, (caddr_t) &ifr) < 0) { return -1; } return fd; } main() { int fd; char buf[3333]; int len=3332; while(1){ fd = open_bpf("em0"); if (fd < 0) { return -1; } len = write(fd, buf, len); close(fd); sleep(10); } } 2.kgdb /kernel /dev/mem (kgdb) p bpf_bpfd_cnt $1 = 8 (it will increase, so it's a leak!) >Fix: in devfs_close(), i found the fd can't correctly closed.: if (vp->v_iflag & VI_DOOMED) { /* Forced close. */ } else if (dsw->d_flags & D_TRACKCLOSE) { /* Keep device updated on status. */ } else if (count_dev(dev) > 1) {<----------------it go into this case! VI_UNLOCK(vp); dev_relthread(dev); return (0); } i don't know why it go into this case when close BPF device, so it don't call bpfclose() to remove the BPF device from ifp->bpf_if->bif_dlist. thanks. Patch attached with submission follows: #include #include #include #include #include #include #include #include #include int open_bpf(char *ifname) { struct ifreq ifr; int fd, n = 0; char device[sizeof "/dev/bpf000"]; /* * Go through all the minors and find one that isn't in use. */ do { (void)sprintf(device, "/dev/bpf%d", n++); fd = open(device, O_RDWR); } while (fd < 0 && errno == EBUSY && n < 100); if (fd < 0) { return -1; } (void)strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, (caddr_t) &ifr) < 0) { return -1; } return fd; } main() { int fd; char buf[3333]; int len=3332; while(1){ fd = open_bpf("em0"); if (fd < 0) { return -1; } len = write(fd, buf, len); close(fd); sleep(10); } } >Release-Note: >Audit-Trail: >Unformatted: