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