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>
