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

Reply via email to