Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 2 Jul 2005 04:39:01 +0200 (CEST)
From:      Dan Lukes <dan@obluda.cz>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   i386/82882: [ PATCH ] ip_mroute abends kernel when interface detached
Message-ID:  <200507020239.j622d1f9000809@kulesh.obluda.cz>
Resent-Message-ID: <200507020240.j622eE1d025717@freefall.freebsd.org>

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

>Number:         82882
>Category:       i386
>Synopsis:       [ PATCH ] ip_mroute abends kernel when interface detached
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-i386
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Jul 02 02:40:14 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator:     Dan Lukes
>Release:        FreeBSD 5.4-STABLE i386
>Organization:
Obludarium
>Environment:
System: FreeBSD 5.4-STABLE i386
src/sys/netinet/ip_mroute.c,v 1.106.2.3 2004/10/09 15:12:04 rwatson

>Description:
	MROUTE code didn't care about interface deletion. It's maintain it's
own copy of ifp within it's table. Using it copy after interface detached
may cause kernel abend or other malfunction.

>How-To-Repeat:
	ifconfig vlan666 create
	ifconfig vlan666 127.0.0.5/32 vlan 666 vlandev <a parent interface>
	run a mroute daemon which add vlan666 as vif to kernel
	ifconfig vlan666 destroy
	now shutdown the mrouted - kernel abend during MRT_DEL_VIF (or MRT_DONE)

>Fix:

	ip_mroute should monitor if_detach interface event invoked by if.c:if_detach()
	It should delete delte destryed interface from it's tables

--- ip_mroute.patch begins here ---
--- sys/netinet/ip_mroute.c.ORIG	Tue Nov 30 14:58:31 2004
+++ sys/netinet/ip_mroute.c	Sat Jul  2 04:11:13 2005
@@ -124,6 +124,8 @@
 
 static u_char		nexpire[MFCTBLSIZ];
 
+static eventhandler_tag if_detach_event_tag = NULL;
+
 static struct callout expire_upcalls_ch;
 
 #define		EXPIRE_TIMEOUT	(hz / 4)	/* 4x / second		*/
@@ -268,8 +270,10 @@
 
 static int get_sg_cnt(struct sioc_sg_req *);
 static int get_vif_cnt(struct sioc_vif_req *);
+static void if_detached_event(void *arg __unused, struct ifnet *);
 static int ip_mrouter_init(struct socket *, int);
 static int add_vif(struct vifctl *);
+static int del_vif_locked(vifi_t);
 static int del_vif(vifi_t);
 static int add_mfc(struct mfcctl2 *);
 static int del_mfc(struct mfcctl2 *);
@@ -619,6 +623,29 @@
 
 static struct mtx mrouter_mtx;		/* used to synch init/done work */
 
+static void
+if_detached_event(void *arg __unused, struct ifnet *ifp)
+{
+    vifi_t vifi;
+
+    mtx_lock(&mrouter_mtx);
+
+    if (ip_mrouter == NULL) {
+	mtx_unlock(&mrouter_mtx);
+    }
+
+    VIF_LOCK();
+    /*
+     * For each phyint in use, disable promiscuous reception of all IP
+     * multicasts.
+     */
+    for (vifi = 0; vifi < numvifs; vifi++)
+	if (viftable[vifi].v_ifp == ifp)
+	    del_vif_locked(vifi);
+    VIF_UNLOCK();
+    mtx_unlock(&mrouter_mtx);
+}
+                        
 /*
  * Enable multicast routing
  */
@@ -642,6 +669,11 @@
 	return EADDRINUSE;
     }
 
+    if_detach_event_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, 
+        if_detached_event, NULL, EVENTHANDLER_PRI_ANY);
+    if (if_detach_event_tag == NULL)
+	return (ENOMEM);
+
     callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls, NULL);
 
     callout_reset(&bw_upcalls_ch, BW_UPCALLS_PERIOD,
@@ -716,6 +748,7 @@
     numvifs = 0;
     pim_assert = 0;
     VIF_UNLOCK();
+    EVENTHANDLER_DEREGISTER(ifnet_departure_event, if_detach_event_tag);
 
     /*
      * Free all multicast forwarding cache entries.
@@ -1050,19 +1083,17 @@
  * Delete a vif from the vif table
  */
 static int
-del_vif(vifi_t vifi)
+del_vif_locked(vifi_t vifi)
 {
     struct vif *vifp;
 
-    VIF_LOCK();
+    VIF_LOCK_ASSERT();
 
     if (vifi >= numvifs) {
-	VIF_UNLOCK();
 	return EINVAL;
     }
     vifp = &viftable[vifi];
     if (vifp->v_lcl_addr.s_addr == INADDR_ANY) {
-	VIF_UNLOCK();
 	return EADDRNOTAVAIL;
     }
 
@@ -1101,9 +1132,19 @@
 	    break;
     numvifs = vifi;
 
+    return 0;
+}
+
+static int
+del_vif(vifi_t vifi)
+{
+    int cc;
+
+    VIF_LOCK();
+    cc = del_vif_locked(vifi);
     VIF_UNLOCK();
 
-    return 0;
+    return cc;
 }
 
 /*
--- ip_mroute.patch ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:



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