On Mon, Apr 30, 2018 at 02:55:21PM +0200, Martin Pieuchot wrote:
> On 30/04/18(Mon) 12:00, Theo Buehler wrote:
> > With mpi's encouragement and guidance, here's a diff that reduces the
> > scope of the NET_LOCK() a bit.
> > 
> > in_control() is the only caller of mrt_ioctl() and the latter is a
> > simple function only requiring a read lock.
> > 
> > There are only a handful callers of in_ioctl(). The two switches create
> > relatively tangled codepaths, so this will need some refactoring before
> > we can push the lock further down and split the read and write cases.
> > For now, establish a single exit point, grab the netlock at the
> > beginning and release it at the end.
> 
> That makes sense, the same could be done for in6_ioctl().

Here's the corresponding diff for in6_control().

Push the diff down into mrt6_ioctl() and in6_ioctl(). Much like the IPv4
version, mrt6_ioctl() only needs a read lock.

in6_ioctl() is a bit messier. It starts off with a call to nd6_ioctl(),
which only needs a read lock. In the diff, I pushed the NET_RLOCK() down
into nd6_ioctl(), but perhaps it would be better to keep the locking
inside in6_ioctl(), like this:

        switch (cmd) {
        case SIOCGIFINFO_IN6:
        case SIOCGNBRINFO_IN6:
                NET_RLOCK();
                error = nd6_ioctl(cmd, data, ifp);
                NET_RUNLOCK();
                return error;
        }

I tested this as well as I could, but I don't usually use IPv6, so I
dabbled a bit with it on my home network and I tried to use the netinet6
regress tests, only with moderate success.

A test from people who actually use IPv6 would be welcome.

Index: sys/netinet6/in6.c
===================================================================
RCS file: /var/cvs/src/sys/netinet6/in6.c,v
retrieving revision 1.222
diff -u -p -r1.222 in6.c
--- sys/netinet6/in6.c  24 Apr 2018 19:53:38 -0000      1.222
+++ sys/netinet6/in6.c  1 May 2018 09:14:07 -0000
@@ -183,7 +183,6 @@ in6_control(struct socket *so, u_long cm
        int privileged;
        int error;
 
-       NET_LOCK();
        privileged = 0;
        if ((so->so_state & SS_PRIV) != 0)
                privileged++;
@@ -200,7 +199,6 @@ in6_control(struct socket *so, u_long cm
                break;
        }
 
-       NET_UNLOCK();
        return error;
 }
 
@@ -211,12 +209,11 @@ in6_ioctl(u_long cmd, caddr_t data, stru
        struct  in6_ifaddr *ia6 = NULL;
        struct  in6_aliasreq *ifra = (struct in6_aliasreq *)data;
        struct sockaddr_in6 *sa6;
+       int     error = 0;
 
        if (ifp == NULL)
                return (ENXIO);
 
-       NET_ASSERT_LOCKED();
-
        switch (cmd) {
        case SIOCGIFINFO_IN6:
        case SIOCGNBRINFO_IN6:
@@ -252,13 +249,16 @@ in6_ioctl(u_long cmd, caddr_t data, stru
        case SIOCSIFNETMASK:
                /*
                 * Do not pass those ioctl to driver handler since they are not
-                * properly setup. Instead just error out.
+                * properly set up. Instead just error out.
                 */
                return (EINVAL);
        default:
                sa6 = NULL;
                break;
        }
+
+       NET_LOCK();
+
        if (sa6 && sa6->sin6_family == AF_INET6) {
                if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
                        if (sa6->sin6_addr.s6_addr16[1] == 0) {
@@ -267,12 +267,15 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                                    htons(ifp->if_index);
                        } else if (sa6->sin6_addr.s6_addr16[1] !=
                            htons(ifp->if_index)) {
-                               return (EINVAL);        /* link ID contradicts 
*/
+                               error = EINVAL; /* link ID contradicts */
+                               goto err;
                        }
                        if (sa6->sin6_scope_id) {
                                if (sa6->sin6_scope_id !=
-                                   (u_int32_t)ifp->if_index)
-                                       return (EINVAL);
+                                   (u_int32_t)ifp->if_index) {
+                                       error = EINVAL;
+                                       goto err;
+                               }
                                sa6->sin6_scope_id = 0; /* XXX: good way? */
                        }
                }
@@ -289,8 +292,10 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                 * interface address from the day one, we consider "remove the
                 * first one" semantics to be not preferable.
                 */
-               if (ia6 == NULL)
-                       return (EADDRNOTAVAIL);
+               if (ia6 == NULL) {
+                       error = EADDRNOTAVAIL;
+                       goto err;
+               }
                /* FALLTHROUGH */
        case SIOCAIFADDR_IN6:
                /*
@@ -298,11 +303,14 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                 * the corresponding operation.
                 */
                if (ifra->ifra_addr.sin6_family != AF_INET6 ||
-                   ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6))
-                       return (EAFNOSUPPORT);
-               if (!privileged)
-                       return (EPERM);
-
+                   ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) {
+                       error = EAFNOSUPPORT;
+                       goto err;
+               }
+               if (!privileged) {
+                       error = EPERM;
+                       goto err;
+               }
                break;
 
        case SIOCGIFAFLAG_IN6:
@@ -310,15 +318,19 @@ in6_ioctl(u_long cmd, caddr_t data, stru
        case SIOCGIFDSTADDR_IN6:
        case SIOCGIFALIFETIME_IN6:
                /* must think again about its semantics */
-               if (ia6 == NULL)
-                       return (EADDRNOTAVAIL);
+               if (ia6 == NULL) {
+                       error = EADDRNOTAVAIL;
+                       goto err;
+               }
                break;
        }
 
        switch (cmd) {
        case SIOCGIFDSTADDR_IN6:
-               if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
-                       return (EINVAL);
+               if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
+                       error = EINVAL;
+                       break;
+               }
                /*
                 * XXX: should we check if ifa_dstaddr is NULL and return
                 * an error?
@@ -392,7 +404,8 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                if ((ifra->ifra_flags & IN6_IFF_DUPLICATED) != 0 ||
                    (ifra->ifra_flags & IN6_IFF_DETACHED) != 0 ||
                    (ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
-                       return (EINVAL);
+                       error = EINVAL;
+                       break;
                }
 
                if (ia6 == NULL)
@@ -413,10 +426,10 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                 */
                error = in6_ifattach(ifp);
                if (error != 0)
-                       return (error);
+                       break;
                error = in6_update_ifa(ifp, ifra, ia6);
                if (error != 0)
-                       return (error);
+                       break;
 
                ia6 = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
                if (ia6 == NULL) {
@@ -446,7 +459,7 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                    ia6->ia_ifa.ifa_addr);
                if (error) {
                        in6_purgeaddr(&ia6->ia_ifa);
-                       return (error);
+                       break;
                }
                dohooks(ifp->if_addrhooks, 0);
                break;
@@ -458,10 +471,13 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                break;
 
        default:
-               return (EOPNOTSUPP);
+               error = EOPNOTSUPP;
+               break;
        }
 
-       return (0);
+err:
+       NET_UNLOCK();
+       return (error);
 }
 
 /*
Index: sys/netinet6/ip6_mroute.c
===================================================================
RCS file: /var/cvs/src/sys/netinet6/ip6_mroute.c,v
retrieving revision 1.114
diff -u -p -r1.114 ip6_mroute.c
--- sys/netinet6/ip6_mroute.c   26 Jun 2017 09:32:32 -0000      1.114
+++ sys/netinet6/ip6_mroute.c   1 May 2018 08:42:18 -0000
@@ -242,17 +242,26 @@ int
 mrt6_ioctl(struct socket *so, u_long cmd, caddr_t data)
 {
        struct inpcb *inp = sotoinpcb(so);
+       int error;
 
        switch (cmd) {
        case SIOCGETSGCNT_IN6:
-               return (get_sg6_cnt((struct sioc_sg_req6 *)data,
-                   inp->inp_rtableid));
+               NET_RLOCK();
+               error = get_sg6_cnt((struct sioc_sg_req6 *)data,
+                   inp->inp_rtableid);
+               NET_RUNLOCK();
+               break;
        case SIOCGETMIFCNT_IN6:
-               return (get_mif6_cnt((struct sioc_mif_req6 *)data,
-                   inp->inp_rtableid));
+               NET_RLOCK();
+               error = get_mif6_cnt((struct sioc_mif_req6 *)data,
+                   inp->inp_rtableid);
+               NET_RUNLOCK();
+               break;
        default:
-               return (ENOTTY);
+               error = ENOTTY;
+               break;
        }
+       return error;
 }
 
 /*
Index: sys/netinet6/nd6.c
===================================================================
RCS file: /var/cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.223
diff -u -p -r1.223 nd6.c
--- sys/netinet6/nd6.c  15 Jan 2018 13:48:31 -0000      1.223
+++ sys/netinet6/nd6.c  30 Apr 2018 22:42:59 -0000
@@ -1014,20 +1014,20 @@ nd6_ioctl(u_long cmd, caddr_t data, stru
        struct in6_ndireq *ndi = (struct in6_ndireq *)data;
        struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data;
        struct rtentry *rt;
-       int error = 0;
-
-       NET_ASSERT_LOCKED();
 
        switch (cmd) {
        case SIOCGIFINFO_IN6:
+               NET_RLOCK();
                ndi->ndi = *ND_IFINFO(ifp);
-               break;
+               NET_RUNLOCK();
+               return (0);
        case SIOCGNBRINFO_IN6:
        {
                struct llinfo_nd6 *ln;
                struct in6_addr nb_addr = nbi->addr; /* make local for safety */
                time_t expire;
 
+               NET_RLOCK();
                /*
                 * XXX: KAME specific hack for scoped addresses
                 *      XXXX: for other scopes than link-local?
@@ -1043,9 +1043,9 @@ nd6_ioctl(u_long cmd, caddr_t data, stru
                rt = nd6_lookup(&nb_addr, 0, ifp, ifp->if_rdomain);
                if (rt == NULL ||
                    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) {
-                       error = EINVAL;
                        rtfree(rt);
-                       break;
+                       NET_RUNLOCK();
+                       return (EINVAL);
                }
                expire = ln->ln_rt->rt_expire;
                if (expire != 0) {
@@ -1057,12 +1057,13 @@ nd6_ioctl(u_long cmd, caddr_t data, stru
                nbi->asked = ln->ln_asked;
                nbi->isrouter = ln->ln_router;
                nbi->expire = expire;
-               rtfree(rt);
 
-               break;
+               rtfree(rt);
+               NET_RUNLOCK();
+               return (0);
        }
        }
-       return (error);
+       return (0);
 }
 
 /*

Reply via email to