Module Name:    src
Committed By:   ozaki-r
Date:           Wed Dec  6 05:59:59 UTC 2017

Modified Files:
        src/sys/net: if.c if.h if_vlan.c

Log Message:
Fix locking against myself on ifpromisc

vlan_unconfig_locked could be called with holding if_ioctl_lock.


To generate a diff of this commit:
cvs rdiff -u -r1.401 -r1.402 src/sys/net/if.c
cvs rdiff -u -r1.245 -r1.246 src/sys/net/if.h
cvs rdiff -u -r1.114 -r1.115 src/sys/net/if_vlan.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.401 src/sys/net/if.c:1.402
--- src/sys/net/if.c:1.401	Wed Dec  6 05:11:10 2017
+++ src/sys/net/if.c	Wed Dec  6 05:59:59 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.c,v 1.401 2017/12/06 05:11:10 ozaki-r Exp $	*/
+/*	$NetBSD: if.c,v 1.402 2017/12/06 05:59:59 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.401 2017/12/06 05:11:10 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.402 2017/12/06 05:59:59 ozaki-r Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -2506,12 +2506,12 @@ if_slowtimo(void *arg)
  * Results are undefined if the "off" and "on" requests are not matched.
  */
 int
-ifpromisc(struct ifnet *ifp, int pswitch)
+ifpromisc_locked(struct ifnet *ifp, int pswitch)
 {
 	int pcount, ret = 0;
 	short nflags;
 
-	mutex_enter(ifp->if_ioctl_lock);
+	KASSERT(mutex_owned(ifp->if_ioctl_lock));
 
 	pcount = ifp->if_pcount;
 	if (pswitch) {
@@ -2534,10 +2534,21 @@ ifpromisc(struct ifnet *ifp, int pswitch
 		ifp->if_pcount = pcount;
 	}
 out:
-	mutex_exit(ifp->if_ioctl_lock);
 	return ret;
 }
 
+int
+ifpromisc(struct ifnet *ifp, int pswitch)
+{
+	int e;
+
+	mutex_enter(ifp->if_ioctl_lock);
+	e = ifpromisc_locked(ifp, pswitch);
+	mutex_exit(ifp->if_ioctl_lock);
+
+	return e;
+}
+
 /*
  * Map interface name to
  * interface structure pointer.

Index: src/sys/net/if.h
diff -u src/sys/net/if.h:1.245 src/sys/net/if.h:1.246
--- src/sys/net/if.h:1.245	Wed Dec  6 05:11:10 2017
+++ src/sys/net/if.h	Wed Dec  6 05:59:59 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.h,v 1.245 2017/12/06 05:11:10 ozaki-r Exp $	*/
+/*	$NetBSD: if.h,v 1.246 2017/12/06 05:59:59 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -1015,6 +1015,7 @@ int	ifaddrpref_ioctl(struct socket *, u_
 extern int (*ifioctl)(struct socket *, u_long, void *, struct lwp *);
 int	ifioctl_common(struct ifnet *, u_long, void *);
 int	ifpromisc(struct ifnet *, int);
+int	ifpromisc_locked(struct ifnet *, int);
 int	if_addr_init(ifnet_t *, struct ifaddr *, bool);
 int	if_do_dad(struct ifnet *);
 int	if_mcast_op(ifnet_t *, const unsigned long, const struct sockaddr *);

Index: src/sys/net/if_vlan.c
diff -u src/sys/net/if_vlan.c:1.114 src/sys/net/if_vlan.c:1.115
--- src/sys/net/if_vlan.c:1.114	Wed Dec  6 05:11:10 2017
+++ src/sys/net/if_vlan.c	Wed Dec  6 05:59:59 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_vlan.c,v 1.114 2017/12/06 05:11:10 ozaki-r Exp $	*/
+/*	$NetBSD: if_vlan.c,v 1.115 2017/12/06 05:59:59 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@@ -78,7 +78,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.114 2017/12/06 05:11:10 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.115 2017/12/06 05:59:59 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -255,6 +255,16 @@ vlan_safe_ifpromisc(struct ifnet *ifp, i
 	return e;
 }
 
+static inline int
+vlan_safe_ifpromisc_locked(struct ifnet *ifp, int pswitch)
+{
+	int e;
+	KERNEL_LOCK_UNLESS_NET_MPSAFE();
+	e = ifpromisc_locked(ifp, pswitch);
+	KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
+	return e;
+}
+
 void
 vlanattach(int n)
 {
@@ -387,7 +397,9 @@ vlan_clone_destroy(struct ifnet *ifp)
 	LIST_REMOVE(ifv, ifv_list);
 	mutex_exit(&ifv_list.lock);
 
+	mutex_enter(ifp->if_ioctl_lock);
 	vlan_unconfig(ifp);
+	mutex_exit(ifp->if_ioctl_lock);
 	if_detach(ifp);
 
 	psref_target_destroy(&ifv->ifv_mib->ifvm_psref, ifvm_psref_class);
@@ -549,6 +561,8 @@ vlan_unconfig(struct ifnet *ifp)
 	struct ifvlan_linkmib *nmib = NULL;
 	int error;
 
+	KASSERT(mutex_owned(ifp->if_ioctl_lock));
+
 	nmib = kmem_alloc(sizeof(*nmib), KM_SLEEP);
 
 	mutex_enter(&ifv->ifv_lock);
@@ -567,6 +581,7 @@ vlan_unconfig_locked(struct ifvlan *ifv,
 	struct ifvlan_linkmib *omib;
 	int error = 0;
 
+	KASSERT(mutex_owned(ifp->if_ioctl_lock));
 	KASSERT(mutex_owned(&ifv->ifv_lock));
 
 	omib = ifv->ifv_mib;
@@ -635,7 +650,7 @@ vlan_unconfig_locked(struct ifvlan *ifv,
 #endif
 
 	if ((ifp->if_flags & IFF_PROMISC) != 0)
-		vlan_safe_ifpromisc(ifp, 0);
+		vlan_safe_ifpromisc_locked(ifp, 0);
 	if_down(ifp);
 	ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
 	ifp->if_capabilities = 0;
@@ -806,6 +821,10 @@ vlan_ifdetach(struct ifnet *p)
 
 	i = 0;
 	LIST_FOREACH(ifv, &ifv_list.list, ifv_list) {
+		struct ifnet *ifp = &ifv->ifv_if;
+
+		/* Need if_ioctl_lock that must be held before ifv_lock. */
+		mutex_enter(ifp->if_ioctl_lock);
 		mutex_enter(&ifv->ifv_lock);
 		if (ifv->ifv_mib->ifvm_p == p) {
 			KASSERTMSG(i < cnt, "no memory for unconfig, parent=%s",
@@ -818,6 +837,7 @@ vlan_ifdetach(struct ifnet *p)
 
 		}
 		mutex_exit(&ifv->ifv_lock);
+		mutex_exit(ifp->if_ioctl_lock);
 	}
 
 	mutex_exit(&ifv_list.lock);

Reply via email to