NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/49373: Running if_clone_create and if_clone_destroy in parallel causes panic



>Number:         49373
>Category:       kern
>Synopsis:       Running if_clone_create and if_clone_destroy in parallel causes panic
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Nov 07 09:15:00 +0000 2014
>Originator:     Ryota Ozaki
>Release:        current
>Organization:
>Environment:
NetBSD kvm 7.99.1 NetBSD 7.99.1 (GENERIC.201411061000Z) #0: Thu Nov  6 10:48:02 UTC 2014  snj%b45.netbsd.org@localhost:/home/builds/ab/HEAD/amd64/201411061000Z-obj/home/source
/ab/HEAD/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
if_clone_create and if_clone_destroy are not expected to run on
an interface in parallel. However, we can do by executing
ifconfig create/destroy in parallel.

Normally we don't do such operations, but we should fix the problem
because it causes kernel panic easily.

A fix is to serialize if_clone_create and if_clone_destroy by a mutex.
It's simple but enough to fix the problem.

>How-To-Repeat:
cat > test.sh <<-EOF
while true; do
        ifconfig tap0 destroy &
        ifconfig tap0 create &
        ifconfig tap0 create &
        ifconfig tap0 destroy &
        ifconfig tap0 create &
        ifconfig tap0 create &
done
EOF
while true; do echo hogs >/dev/null; done &
while true; do sh test.sh ; done

>Fix:
Index: sys/net/if.c
===================================================================
RCS file: /cvsroot/src/sys/net/if.c,v
retrieving revision 1.291
diff -u -p -r1.291 if.c
--- sys/net/if.c	9 Sep 2014 20:16:12 -0000	1.291
+++ sys/net/if.c	7 Nov 2014 09:02:11 -0000
@@ -164,6 +164,7 @@ static u_int			if_index = 1;
 static size_t			if_indexlim = 0;
 static uint64_t			index_gen;
 static kmutex_t			index_gen_mtx;
+static kmutex_t			if_clone_mtx;
 
 static struct ifaddr **		ifnet_addrs = NULL;
 
@@ -252,6 +253,7 @@ void
 ifinit1(void)
 {
 	mutex_init(&index_gen_mtx, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&if_clone_mtx, MUTEX_DEFAULT, IPL_NONE);
 	TAILQ_INIT(&ifnet_list);
 	if_indexlim = 8;
 
@@ -1850,6 +1852,7 @@ doifioctl(struct socket *so, u_long cmd,
 	struct ifreq ifrb;
 	struct oifreq *oifr = NULL;
 #endif
+	int r;
 
 	switch (cmd) {
 #ifdef COMPAT_OIFREQ
@@ -1891,9 +1894,12 @@ doifioctl(struct socket *so, u_long cmd,
 			if (error != 0)
 				return error;
 		}
-		return (cmd == SIOCIFCREATE) ?
+		mutex_enter(&if_clone_mtx);
+		r = (cmd == SIOCIFCREATE) ?
 			if_clone_create(ifr->ifr_name) :
 			if_clone_destroy(ifr->ifr_name);
+		mutex_exit(&if_clone_mtx);
+		return r;
 
 	case SIOCIFGCLONERS:
 		return if_clone_list((struct if_clonereq *)data);



Home | Main Index | Thread Index | Old Index