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);