Hi, I have seen spl softnet assert failures like this.
splassert: sowwakeup: want 1 have 0 Starting stack trace... sowwakeup(1,0,d09d8bd7,d03ba9f9,40) at sowwakeup+0x3f sowwakeup(db549818,d6dc850e,f54d9be8,0,dae674d4) at sowwakeup+0x3f soisdisconnected(db549818,0,db549818,2,f54d9c00) at soisdisconnected+0x2c tcp_close(dae674d4,35,ff94,bc51bc0a,a88c) at tcp_close+0x97 tcp_ident(0,f54d9ef8,cf7e2a50,20c,1) at tcp_ident+0x302 tcp_sysctl(f54d9ed4,1,0,f54d9ef8,cf7e2a50) at tcp_sysctl+0x28b sys_sysctl(d9f0188c,f54d9f5c,f54d9f7c,0,f54d9fa8) at sys_sysctl+0x20e syscall() at syscall+0x250 Obviosly a NET_LOCK() is missing in tcp_sysctl(). I think it is better to place the lock into net_sysctl() where all the protocol sysctls are called via pr_sysctl. Then we don't have to decide each case individually. As calling sysctl(2) is in the slow path, doing fine grained locking has no benefit. Many sysctl cases copy out a struct. Having a lock around that keeps the struct consistent. ok? bluhm Index: kern/uipc_domain.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_domain.c,v retrieving revision 1.46 diff -u -p -r1.46 uipc_domain.c --- kern/uipc_domain.c 22 Nov 2016 10:32:31 -0000 1.46 +++ kern/uipc_domain.c 20 Dec 2016 14:57:26 -0000 @@ -165,7 +165,7 @@ net_sysctl(int *name, u_int namelen, voi { struct domain *dp; struct protosw *pr; - int family, protocol; + int s, error, family, protocol; /* * All sysctl names at this level are nonterminal. @@ -199,18 +199,26 @@ net_sysctl(int *name, u_int namelen, voi #ifdef MPLS /* XXX WARNING: big fat ugly hack */ /* stupid net.mpls is special as it does not have a protocol */ - if (family == PF_MPLS) - return (dp->dom_protosw[0].pr_sysctl(name + 1, namelen - 1, - oldp, oldlenp, newp, newlen)); + if (family == PF_MPLS) { + NET_LOCK(s); + error = (dp->dom_protosw[0].pr_sysctl)(name + 1, namelen - 1, + oldp, oldlenp, newp, newlen); + NET_UNLOCK(s); + return (error); + } #endif if (namelen < 3) return (EISDIR); /* overloaded */ protocol = name[1]; for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) - if (pr->pr_protocol == protocol && pr->pr_sysctl) - return ((*pr->pr_sysctl)(name + 2, namelen - 2, - oldp, oldlenp, newp, newlen)); + if (pr->pr_protocol == protocol && pr->pr_sysctl) { + NET_LOCK(s); + error = (*pr->pr_sysctl)(name + 2, namelen - 2, + oldp, oldlenp, newp, newlen); + NET_UNLOCK(s); + return (error); + } return (ENOPROTOOPT); } Index: net/rtsock.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/rtsock.c,v retrieving revision 1.211 diff -u -p -r1.211 rtsock.c --- net/rtsock.c 19 Dec 2016 08:36:49 -0000 1.211 +++ net/rtsock.c 20 Dec 2016 15:12:06 -0000 @@ -1563,12 +1563,14 @@ int sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new, size_t newlen) { - int i, s, error = EINVAL; + int i, error = EINVAL; u_char af; struct walkarg w; struct rt_tableinfo tableinfo; u_int tableid = 0; + NET_ASSERT_LOCKED(); + if (new) return (EPERM); if (namelen < 3 || namelen > 4) @@ -1588,7 +1590,6 @@ sysctl_rtable(int *name, u_int namelen, } else tableid = curproc->p_p->ps_rtableid; - s = splsoftnet(); switch (w.w_op) { case NET_RT_DUMP: case NET_RT_FLAGS: @@ -1611,25 +1612,20 @@ sysctl_rtable(int *name, u_int namelen, case NET_RT_STATS: error = sysctl_rdstruct(where, given, new, &rtstat, sizeof(rtstat)); - splx(s); return (error); case NET_RT_TABLE: tableid = w.w_arg; - if (!rtable_exists(tableid)) { - splx(s); + if (!rtable_exists(tableid)) return (ENOENT); - } tableinfo.rti_tableid = tableid; tableinfo.rti_domainid = rtable_l2(tableid); error = sysctl_rdstruct(where, given, new, &tableinfo, sizeof(tableinfo)); - splx(s); return (error); case NET_RT_IFNAMES: error = sysctl_ifnames(&w); break; } - splx(s); free(w.w_tmem, M_RTABLE, 0); w.w_needed += w.w_given; if (where) { Index: netinet/ip_icmp.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_icmp.c,v retrieving revision 1.158 diff -u -p -r1.158 ip_icmp.c --- netinet/ip_icmp.c 19 Dec 2016 08:36:49 -0000 1.158 +++ netinet/ip_icmp.c 20 Dec 2016 16:46:17 -0000 @@ -878,13 +878,14 @@ int icmp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - int s, error; + int error; + + NET_ASSERT_LOCKED(); /* All sysctl names at this level are terminal. */ if (namelen != 1) return (ENOTDIR); - NET_LOCK(s); switch (name[0]) { case ICMPCTL_REDIRTIMEOUT: @@ -921,7 +922,6 @@ icmp_sysctl(int *name, u_int namelen, vo error = ENOPROTOOPT; break; } - NET_UNLOCK(s); return (error); } Index: netinet/ip_input.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_input.c,v retrieving revision 1.290 diff -u -p -r1.290 ip_input.c --- netinet/ip_input.c 19 Dec 2016 09:22:24 -0000 1.290 +++ netinet/ip_input.c 20 Dec 2016 16:59:59 -0000 @@ -1557,12 +1557,14 @@ int ip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - int s, error; + int error; #ifdef MROUTING extern int ip_mrtproto; extern struct mrtstat mrtstat; #endif + NET_ASSERT_LOCKED(); + /* Almost all sysctl names at this level are terminal. */ if (namelen != 1 && name[0] != IPCTL_IFQUEUE) return (ENOTDIR); @@ -1587,21 +1589,16 @@ ip_sysctl(int *name, u_int namelen, void ip_mtudisc_timeout_q = rt_timer_queue_create(ip_mtudisc_timeout); } else if (ip_mtudisc == 0 && ip_mtudisc_timeout_q != NULL) { - NET_LOCK(s); rt_timer_queue_destroy(ip_mtudisc_timeout_q); ip_mtudisc_timeout_q = NULL; - NET_UNLOCK(s); } return error; case IPCTL_MTUDISCTIMEOUT: error = sysctl_int(oldp, oldlenp, newp, newlen, &ip_mtudisc_timeout); - if (ip_mtudisc_timeout_q != NULL) { - NET_LOCK(s); + if (ip_mtudisc_timeout_q != NULL) rt_timer_queue_change(ip_mtudisc_timeout_q, ip_mtudisc_timeout); - NET_UNLOCK(s); - } return (error); case IPCTL_IPSEC_ENC_ALGORITHM: return (sysctl_tstring(oldp, oldlenp, newp, newlen, Index: netinet/tcp_usrreq.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_usrreq.c,v retrieving revision 1.137 diff -u -p -r1.137 tcp_usrreq.c --- netinet/tcp_usrreq.c 19 Dec 2016 08:36:49 -0000 1.137 +++ netinet/tcp_usrreq.c 20 Dec 2016 17:04:18 -0000 @@ -850,6 +850,8 @@ tcp_sysctl(int *name, u_int namelen, voi { int error, nval; + NET_ASSERT_LOCKED(); + /* All sysctl names at this level are terminal. */ if (namelen != 1) return (ENOTDIR); Index: netinet6/ip6_input.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_input.c,v retrieving revision 1.171 diff -u -p -r1.171 ip6_input.c --- netinet6/ip6_input.c 19 Dec 2016 08:36:50 -0000 1.171 +++ netinet6/ip6_input.c 20 Dec 2016 16:50:10 -0000 @@ -1369,7 +1369,9 @@ ip6_sysctl(int *name, u_int namelen, voi extern int ip6_mrtproto; extern struct mrt6stat mrt6stat; #endif - int error, s; + int error; + + NET_ASSERT_LOCKED(); /* Almost all sysctl names at this level are terminal. */ if (namelen != 1 && name[0] != IPV6CTL_IFQUEUE) @@ -1409,12 +1411,9 @@ ip6_sysctl(int *name, u_int namelen, voi case IPV6CTL_MTUDISCTIMEOUT: error = sysctl_int(oldp, oldlenp, newp, newlen, &ip6_mtudisc_timeout); - if (icmp6_mtudisc_timeout_q != NULL) { - s = splsoftnet(); + if (icmp6_mtudisc_timeout_q != NULL) rt_timer_queue_change(icmp6_mtudisc_timeout_q, ip6_mtudisc_timeout); - splx(s); - } return (error); case IPV6CTL_IFQUEUE: return (sysctl_niq(name + 1, namelen - 1, Index: netinet6/nd6.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6.c,v retrieving revision 1.198 diff -u -p -r1.198 nd6.c --- netinet6/nd6.c 19 Dec 2016 08:36:50 -0000 1.198 +++ netinet6/nd6.c 20 Dec 2016 16:22:01 -0000 @@ -1639,6 +1639,8 @@ nd6_sysctl(int name, void *oldp, size_t size_t ol; int error; + NET_ASSERT_LOCKED(); + error = 0; if (newp) @@ -1678,14 +1680,12 @@ nd6_sysctl(int name, void *oldp, size_t int fill_drlist(void *oldp, size_t *oldlenp, size_t ol) { - int error = 0, s; + int error = 0; struct in6_defrouter *d = NULL, *de = NULL; struct nd_defrouter *dr; time_t expire; size_t l; - s = splsoftnet(); - if (oldp) { d = (struct in6_defrouter *)oldp; de = (struct in6_defrouter *)((caddr_t)oldp + *oldlenp); @@ -1721,22 +1721,18 @@ fill_drlist(void *oldp, size_t *oldlenp, } else *oldlenp = l; - splx(s); - return (error); } int fill_prlist(void *oldp, size_t *oldlenp, size_t ol) { - int error = 0, s; + int error = 0; struct nd_prefix *pr; char *p = NULL, *ps = NULL; char *pe = NULL; size_t l; - s = splsoftnet(); - if (oldp) { ps = p = (char *)oldp; pe = (char *)oldp + *oldlenp; @@ -1816,8 +1812,6 @@ fill_prlist(void *oldp, size_t *oldlenp, error = ENOMEM; } else *oldlenp = l; - - splx(s); return (error); }