Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 31 Jul 2001 17:26:45 +0900 (JST)
From:      inoue@nd.net.fujitsu.co.jp
To:        FreeBSD-gnats-submit@freebsd.org
Cc:        inoue@nd.net.fujitsu.co.jp
Subject:   kern/29345: freebsd can crash after removing a network card
Message-ID:  <200107310826.f6V8QjX45246@router.tcs.dnsalias.org>

next in thread | raw e-mail | index | archive | help

>Number:         29345
>Category:       kern
>Synopsis:       freebsd can crash after removing a network card
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jul 31 01:30:01 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Inoue Yuichi
>Release:        FreeBSD 5.0-CURRENT-20010729-JPSNAP
>Organization:
FUJITSU
>Environment:
	FreeBSD dhcp022158141.nd.net.fujitsu.co.jp
	5.0-CURRENT-20010729-JPSNAP FreeBSD 5.0-CURRENT-20010729-JPSNAP #1:
	Tue Jul 31 12:56:22 JST 2001
	inoue@dhcp022158141.nd.net.fujitsu.co.jp:
	/usr/src/sys/i386/compile/GENERIC i386

	FreeBSD 4.3-RELEASE
>Description:
	When running aplication joined multicast address,
	removing network card, and kill aplication.
	imo_membership[].inm_ifp refer interface pointer
	after removing interface.
	When kill aplication, release socket,and imo_membership.
	imo_membership use already not exist interface pointer.
	Then, kernel panic.
>How-To-Repeat:
	shell> route6d
	removing a netword card
	shell> kill `cat /var/run/route6d`
	kernel panic
>Fix:
--- netinet.patch ---
diff -uNr netinet/in.c /usr/src/sys/netinet/in.c
--- netinet/in.c	Tue Jul 31 14:04:40 2001
+++ /usr/src/sys/netinet/in.c	Tue Jul 31 12:54:46 2001
@@ -48,6 +48,7 @@
 
 #include <netinet/in.h>
 #include <netinet/in_var.h>
+#include <netinet/in_pcb.h>
 
 #include <netinet/igmp_var.h>
 
@@ -68,6 +69,9 @@
 
 struct in_multihead in_multihead; /* XXX BSS initialization */
 
+extern struct inpcbinfo ripcbinfo;
+extern struct inpcbinfo udbinfo;
+
 /*
  * Return 1 if an internet address is for a ``local'' host
  * (one to which we have a connection).  If subnetsarelocal
@@ -402,6 +406,14 @@
 		 * a routing process they will come back.
 		 */
 		in_ifadown(&ia->ia_ifa, 1);
+		/*
+		 * XXX horrible hack to detect that we are being called
+		 * from if_detach()
+		 */
+		if (!ifnet_addrs[ifp->if_index - 1]) {
+			in_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp);
+			in_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp);
+		}
 
 		/*
 		 * Protect from ipintr() traversing address list
diff -uNr netinet/in_pcb.c /usr/src/sys/netinet/in_pcb.c
--- netinet/in_pcb.c	Tue Jul 31 14:04:40 2001
+++ /usr/src/sys/netinet/in_pcb.c	Tue Jul 31 12:53:05 2001
@@ -689,6 +689,44 @@
 	splx(s);
 }
 
+void
+in_pcbpurgeif0(head, ifp)
+	struct inpcb *head;
+	struct ifnet *ifp;
+{
+	struct inpcb *inp;
+	struct ip_moptions *imo;
+	int i, gap;
+
+	for (inp = head; inp != NULL; inp = LIST_NEXT(inp, inp_list)) {
+		imo = inp->inp_moptions;
+		if ((inp->inp_vflag & INP_IPV4) &&
+		    imo != NULL) {
+			/*
+			 * Unselect the outgoing interface if it is being
+			 * detached.
+			 */
+			if (imo->imo_multicast_ifp == ifp)
+				imo->imo_multicast_ifp = NULL;
+
+			/*
+			 * Drop multicast group membership if we joined
+			 * through the interface being detached.
+			 */
+			for (i = 0, gap = 0; i < imo->imo_num_memberships;
+			    i++) {
+				if (imo->imo_membership[i]->inm_ifp == ifp) {
+					in_delmulti(imo->imo_membership[i]);
+					gap++;
+				} else if (gap != 0)
+					imo->imo_membership[i - gap] =
+					    imo->imo_membership[i];
+			}
+			imo->imo_num_memberships -= gap;
+		}
+	}
+}
+
 /*
  * Check for alternatives when higher level complains
  * about service problems.  For now, invalidate cached
diff -uNr netinet/in_pcb.h /usr/src/sys/netinet/in_pcb.h
--- netinet/in_pcb.h	Tue Jul 31 14:04:40 2001
+++ /usr/src/sys/netinet/in_pcb.h	Tue Jul 31 12:53:05 2001
@@ -275,6 +275,7 @@
 extern int	ipport_hifirstauto;
 extern int	ipport_hilastauto;
 
+void	in_pcbpurgeif0 __P((struct inpcb *, struct ifnet *));
 void	in_losing __P((struct inpcb *));
 void	in_rtchange __P((struct inpcb *, int));
 int	in_pcballoc __P((struct socket *, struct inpcbinfo *, struct proc *));
--- netinet.patch ---

--- netinet6.patch ---
diff -uNr netinet6/in6_ifattach.c /usr/src/sys/netinet6/in6_ifattach.c
--- netinet6/in6_ifattach.c	Tue Jul 31 14:04:47 2001
+++ /usr/src/sys/netinet6/in6_ifattach.c	Tue Jul 31 12:55:52 2001
@@ -47,10 +47,12 @@
 #include <netinet/in.h>
 #include <netinet/in_var.h>
 #include <netinet/if_ether.h>
+#include <netinet/in_pcb.h>
 
 #include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
 #include <netinet6/in6_var.h>
+#include <netinet6/in6_pcb.h>
 #include <netinet6/in6_ifattach.h>
 #include <netinet6/ip6_var.h>
 #include <netinet6/nd6.h>
@@ -72,6 +74,9 @@
 
 struct callout in6_tmpaddrtimer_ch;
 
+extern struct inpcbinfo udbinfo;
+extern struct inpcbinfo ripcbinfo;
+
 static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
 static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *));
 static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));
@@ -942,6 +947,8 @@
 	}
 
 	/* leave from all multicast groups joined */
+	in6_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp);
+	in6_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp);
 	for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) {
 		in6m_next = LIST_NEXT(in6m, in6m_entry);
 		if (in6m->in6m_ifp != ifp)
diff -uNr netinet6/in6_pcb.c /usr/src/sys/netinet6/in6_pcb.c
--- netinet6/in6_pcb.c	Tue Jul 31 14:04:47 2001
+++ /usr/src/sys/netinet6/in6_pcb.c	Tue Jul 31 12:53:10 2001
@@ -932,6 +932,45 @@
 	}
 }
 
+void
+in6_pcbpurgeif0(head, ifp)
+	struct in6pcb *head;
+	struct ifnet *ifp;
+{
+	struct in6pcb *in6p;
+	struct ip6_moptions *im6o;
+	struct in6_multi_mship *imm, *nimm;
+
+	for (in6p = head; in6p != NULL; in6p = LIST_NEXT(in6p, inp_list)) {
+		im6o = in6p->in6p_moptions;
+		if ((in6p->inp_vflag & INP_IPV6) &&
+		    im6o) {
+			/*
+			 * Unselect the outgoing interface if it is being
+			 * detached.
+			 */
+			if (im6o->im6o_multicast_ifp == ifp)
+				im6o->im6o_multicast_ifp = NULL;
+
+			/*
+			 * Drop multicast group membership if we joined
+			 * through the interface being detached.
+			 * XXX controversial - is it really legal for kernel
+			 * to force this?
+			 */
+			for (imm = im6o->im6o_memberships.lh_first;
+			     imm != NULL; imm = nimm) {
+				nimm = imm->i6mm_chain.le_next;
+				if (imm->i6mm_maddr->in6m_ifp == ifp) {
+					LIST_REMOVE(imm, i6mm_chain);
+					in6_delmulti(imm->i6mm_maddr);
+					free(imm, M_IPMADDR);
+				}
+			}
+		}
+	}
+}
+
 /*
  * Check for alternatives when higher level complains
  * about service problems.  For now, invalidate cached
diff -uNr netinet6/in6_pcb.h /usr/src/sys/netinet6/in6_pcb.h
--- netinet6/in6_pcb.h	Tue Jul 31 14:04:47 2001
+++ /usr/src/sys/netinet6/in6_pcb.h	Tue Jul 31 12:53:10 2001
@@ -74,6 +74,7 @@
 #define	sin6tosa(sin6)	((struct sockaddr *)(sin6))
 #define	ifatoia6(ifa)	((struct in6_ifaddr *)(ifa))
 
+void	in6_pcbpurgeif0 __P((struct in6pcb *, struct ifnet *));
 void	in6_losing __P((struct inpcb *));
 int	in6_pcballoc __P((struct socket *, struct inpcbinfo *, struct proc *));
 int	in6_pcbbind __P((struct inpcb *, struct sockaddr *, struct proc *));
--- netinet6.patch ---
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200107310826.f6V8QjX45246>