Subject: kern/856: tcpdump can cause kernel panic; fix included
To: None <gnats-admin@NetBSD.ORG>
From: Lon Willett <lon%softt.uucp@math.utah.edu>
List: netbsd-bugs
Date: 03/08/1995 15:20:05
>Number:         856
>Category:       kern
>Synopsis:       tcpdump can cause kernel panic; fix included
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Mar  8 15:20:04 1995
>Originator:     Lon Willett
>Organization:
none
>Release:        NetBSD-current 8 Mar 95
>Environment:

System: NetBSD hilly 1.0A NetBSD 1.0A (HILLY) #150: Wed Mar 8 13:40:25 MST 1995 lon@hilly:/usr/src/sys/arch/i386/compile/HILLY i386

>Description:

If an interface that bpf (i.e. tcpdump) has put in promiscuous mode goes
down, then when the bpf device is closed out (i.e. tcpdump exits), the
kernel panics.  NB: this also includes PPP interfaces, even though they
don't have a promiscuous mode, because they are perfectly willing to let
you set the IFF_PROMISC flag without complaining.

>How-To-Repeat:

e.g. How I came across it:
	# pppd ...
	(now ppp0 is up)
	# tcpdump -i ppp0
	(now it is marked in promiscuous mode)
	(interface goes down, e.g. on another tty:
	# ifconfig ppp0 down	# does this work?  or must you kill PPPD-PID
	)
	Type ^C to kill tcpdump.

You should get a panic: "ifpromisc failed".

>Fix:

Here's a "diff -u" of how I fixed it.  The problem is that "ifpromisc" was
checking IFF_UP too soon when turning promiscuous mode off.

--- usr/src/sys/net/bpf.c.orig	Fri Feb 24 04:20:37 1995
+++ usr/src/sys/net/bpf.c	Wed Mar  8 11:22:01 1995
@@ -245,8 +245,10 @@
 	 * If so, turn it off.
 	 */
 	if (d->bd_promisc) {
+		int error;
 		d->bd_promisc = 0;
-		if (ifpromisc(bp->bif_ifp, 0))
+		if ((error = ifpromisc(bp->bif_ifp, 0)) != 0 &&
+		    error != EINVAL) /* PPP/SLIP/etc. return EINVAL */
 			/*
 			 * Something is really wrong if we were able to put
 			 * the driver into promiscuous mode, but can't
@@ -1240,14 +1242,14 @@
 	int pswitch;
 {
 	struct ifreq ifr;
-	/*
-	 * If the device is not configured up, we cannot put it in
-	 * promiscuous mode.
-	 */
-	if ((ifp->if_flags & IFF_UP) == 0)
-		return (ENETDOWN);
 
 	if (pswitch) {
+		/*
+		 * If the device is not configured up, we cannot put it in
+		 * promiscuous mode.
+		 */
+		if ((ifp->if_flags & IFF_UP) == 0)
+			return (ENETDOWN);
 		if (ifp->if_pcount++ != 0)
 			return (0);
 		ifp->if_flags |= IFF_PROMISC;
@@ -1255,6 +1257,14 @@
 		if (--ifp->if_pcount > 0)
 			return (0);
 		ifp->if_flags &= ~IFF_PROMISC;
+		/*
+		 * If the device is not configured up, we should not need to
+		 * turn off promiscuous mode (device should have turned it
+		 * off when interface went down; and will look at IFF_PROMISC
+		 * again next time interface comes up).
+		 */
+		if ((ifp->if_flags & IFF_UP) == 0)
+			return (0);
 	}
 	ifr.ifr_flags = ifp->if_flags;
 	return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
>Audit-Trail:
>Unformatted: