Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Make sure returning ifp from in6_select* functions psref-ed



details:   https://anonhg.NetBSD.org/src/rev/eb988d3d7d64
branches:  trunk
changeset: 346061:eb988d3d7d64
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Tue Jun 21 10:25:27 2016 +0000

description:
Make sure returning ifp from in6_select* functions psref-ed

To this end, callers need to pass struct psref to the functions
and the fuctions acquire a reference of ifp with it. In some cases,
we can simply use if_get_byindex, however, in other cases
(say rt->rt_ifp and ia->ifa_ifp), we have no MP-safe way for now.
In order to take a reference anyway we use non MP-safe function
if_acquire_NOMPSAFE for the latter cases. They should be fixed in
the future somehow.

diffstat:

 sys/net/if.c               |  14 ++++--
 sys/net/if.h               |   4 +-
 sys/netinet6/icmp6.c       |   6 +-
 sys/netinet6/in6_pcb.c     |  19 ++++++--
 sys/netinet6/in6_src.c     |  94 ++++++++++++++++++++++++++++++++-------------
 sys/netinet6/ip6_output.c  |  22 +++++++--
 sys/netinet6/ip6_var.h     |   6 +-
 sys/netinet6/nd6_nbr.c     |   8 +-
 sys/netinet6/raw_ip6.c     |  18 ++++++-
 sys/netinet6/udp6_output.c |  13 ++++-
 10 files changed, 141 insertions(+), 63 deletions(-)

diffs (truncated from 687 to 300 lines):

diff -r ca96e3dbc508 -r eb988d3d7d64 sys/net/if.c
--- a/sys/net/if.c      Tue Jun 21 10:21:04 2016 +0000
+++ b/sys/net/if.c      Tue Jun 21 10:25:27 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if.c,v 1.343 2016/06/20 08:30:58 knakahara Exp $       */
+/*     $NetBSD: if.c,v 1.344 2016/06/21 10:25:27 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.343 2016/06/20 08:30:58 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.344 2016/06/21 10:25:27 ozaki-r Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -2193,6 +2193,9 @@
 if_put(const struct ifnet *ifp, struct psref *psref)
 {
 
+       if (ifp == NULL)
+               return;
+
        psref_release(psref, &ifp->if_psref, ifnet_psref_class);
 }
 
@@ -2223,14 +2226,15 @@
 }
 
 /*
- * XXX unsafe
+ * XXX it's safe only if the passed ifp is guaranteed to not be freed,
+ * for example the ifp is already held or some other object is held which
+ * guarantes the ifp to not be freed indirectly.
  */
 void
-if_acquire_unsafe(struct ifnet *ifp, struct psref *psref)
+if_acquire_NOMPSAFE(struct ifnet *ifp, struct psref *psref)
 {
 
        KASSERT(ifp->if_index != 0);
-       KASSERT(if_byindex(ifp->if_index) != NULL);
        psref_acquire(psref, &ifp->if_psref, ifnet_psref_class);
 }
 
diff -r ca96e3dbc508 -r eb988d3d7d64 sys/net/if.h
--- a/sys/net/if.h      Tue Jun 21 10:21:04 2016 +0000
+++ b/sys/net/if.h      Tue Jun 21 10:25:27 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if.h,v 1.213 2016/06/21 03:28:27 ozaki-r Exp $ */
+/*     $NetBSD: if.h,v 1.214 2016/06/21 10:25:27 ozaki-r Exp $ */
 
 /*-
  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -952,7 +952,7 @@
 ifnet_t *if_byindex(u_int);
 ifnet_t *if_get_byindex(u_int, struct psref *);
 void   if_put(const struct ifnet *, struct psref *);
-void   if_acquire_unsafe(struct ifnet *, struct psref *);
+void   if_acquire_NOMPSAFE(struct ifnet *, struct psref *);
 
 static inline if_index_t
 if_get_index(const struct ifnet *ifp)
diff -r ca96e3dbc508 -r eb988d3d7d64 sys/netinet6/icmp6.c
--- a/sys/netinet6/icmp6.c      Tue Jun 21 10:21:04 2016 +0000
+++ b/sys/netinet6/icmp6.c      Tue Jun 21 10:25:27 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: icmp6.c,v 1.188 2016/06/10 13:31:44 ozaki-r Exp $      */
+/*     $NetBSD: icmp6.c,v 1.189 2016/06/21 10:25:27 ozaki-r Exp $      */
 /*     $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.188 2016/06/10 13:31:44 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.189 2016/06/21 10:25:27 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -2091,7 +2091,7 @@
                sockaddr_in6_init(&sin6, &ip6->ip6_dst, 0, 0, 0);
 
                memset(&ro, 0, sizeof(ro));
-               src = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, NULL, &e);
+               src = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, NULL, NULL, &e);
                rtcache_free(&ro);
                if (src == NULL) {
                        nd6log(LOG_DEBUG,
diff -r ca96e3dbc508 -r eb988d3d7d64 sys/netinet6/in6_pcb.c
--- a/sys/netinet6/in6_pcb.c    Tue Jun 21 10:21:04 2016 +0000
+++ b/sys/netinet6/in6_pcb.c    Tue Jun 21 10:25:27 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: in6_pcb.c,v 1.144 2016/06/21 03:28:27 ozaki-r Exp $    */
+/*     $NetBSD: in6_pcb.c,v 1.145 2016/06/21 10:25:27 ozaki-r Exp $    */
 /*     $KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $        */
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.144 2016/06/21 03:28:27 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.145 2016/06/21 10:25:27 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -438,6 +438,8 @@
 #endif
        struct sockaddr_in6 tmp;
        struct vestigial_inpcb vestige;
+       struct psref psref;
+       int bound;
 
        (void)&in6a;                            /* XXX fool gcc */
 
@@ -478,6 +480,7 @@
        tmp = *sin6;
        sin6 = &tmp;
 
+       bound = curlwp_bind();
        /* Source address selection. */
        if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr) &&
            in6p->in6p_laddr.s6_addr32[3] == 0) {
@@ -512,23 +515,29 @@
                in6a = in6_selectsrc(sin6, in6p->in6p_outputopts,
                                     in6p->in6p_moptions,
                                     &in6p->in6p_route,
-                                    &in6p->in6p_laddr, &ifp, &error);
+                                    &in6p->in6p_laddr, &ifp, &psref, &error);
                if (ifp && scope_ambiguous &&
                    (error = in6_setscope(&sin6->sin6_addr, ifp, NULL)) != 0) {
+                       if_put(ifp, &psref);
+                       curlwp_bindx(bound);
                        return(error);
                }
 
                if (in6a == NULL) {
+                       if_put(ifp, &psref);
+                       curlwp_bindx(bound);
                        if (error == 0)
                                error = EADDRNOTAVAIL;
                        return (error);
                }
        }
 
-       if (ifp != NULL)
+       if (ifp != NULL) {
                in6p->in6p_ip6.ip6_hlim = (u_int8_t)in6_selecthlim(in6p, ifp);
-       else
+               if_put(ifp, &psref);
+       } else
                in6p->in6p_ip6.ip6_hlim = (u_int8_t)in6_selecthlim_rt(in6p);
+       curlwp_bindx(bound);
 
        if (in6_pcblookup_connect(in6p->in6p_table, &sin6->sin6_addr,
            sin6->sin6_port,
diff -r ca96e3dbc508 -r eb988d3d7d64 sys/netinet6/in6_src.c
--- a/sys/netinet6/in6_src.c    Tue Jun 21 10:21:04 2016 +0000
+++ b/sys/netinet6/in6_src.c    Tue Jun 21 10:25:27 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: in6_src.c,v 1.61 2016/06/21 03:28:27 ozaki-r Exp $     */
+/*     $NetBSD: in6_src.c,v 1.62 2016/06/21 10:25:27 ozaki-r Exp $     */
 /*     $KAME: in6_src.c,v 1.159 2005/10/19 01:40:32 t-momose Exp $     */
 
 /*
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_src.c,v 1.61 2016/06/21 03:28:27 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_src.c,v 1.62 2016/06/21 10:25:27 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -123,10 +123,10 @@
 int ip6_prefer_tempaddr = 0;
 
 static int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
-       struct ip6_moptions *, struct route *, struct ifnet **,
+       struct ip6_moptions *, struct route *, struct ifnet **, struct psref *,
        struct rtentry **, int, int);
 static int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
-       struct ip6_moptions *, struct route *, struct ifnet **);
+       struct ip6_moptions *, struct route *, struct ifnet **, struct psref *);
 
 static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *);
 
@@ -174,7 +174,7 @@
 struct in6_addr *
 in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, 
        struct ip6_moptions *mopts, struct route *ro, struct in6_addr *laddr, 
-       struct ifnet **ifpp, int *errorp)
+       struct ifnet **ifpp, struct psref *psref, int *errorp)
 {
        struct in6_addr dst;
        struct ifnet *ifp = NULL;
@@ -188,6 +188,13 @@
 #if defined(MIP6) && NMIP > 0
        u_int8_t ip6po_usecoa = 0;
 #endif /* MIP6 && NMIP > 0 */
+       struct psref local_psref;
+       struct in6_addr *ret_ia = NULL;
+       int bound = curlwp_bind();
+#define PSREF (psref == NULL) ? &local_psref : psref
+
+       KASSERT((ifpp != NULL && psref != NULL) ||
+               (ifpp == NULL && psref == NULL));
 
        dst = dstsock->sin6_addr; /* make a copy for local operation */
        *errorp = 0;
@@ -201,8 +208,8 @@
         * to this function (e.g., for identifying the appropriate scope zone
         * ID).
         */
-       error = in6_selectif(dstsock, opts, mopts, ro, &ifp);
-       if (ifpp)
+       error = in6_selectif(dstsock, opts, mopts, ro, &ifp, PSREF);
+       if (ifpp != NULL)
                *ifpp = ifp;
 
        /*
@@ -230,19 +237,20 @@
                if (ifp) {
                        *errorp = in6_setscope(&srcsock.sin6_addr, ifp, NULL);
                        if (*errorp != 0)
-                               return (NULL);
+                               goto exit;
                }
 
                ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)(&srcsock));
                if (ia6 == NULL ||
                    (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
                        *errorp = EADDRNOTAVAIL;
-                       return (NULL);
+                       goto exit;
                }
                pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */
                if (ifpp)
                        *ifpp = ifp;
-               return (&ia6->ia_addr.sin6_addr);
+               ret_ia = &ia6->ia_addr.sin6_addr;
+               goto exit;
        }
 
        /*
@@ -250,8 +258,10 @@
         * care at the moment whether in6_selectif() succeeded above, even
         * though it would eventually cause an error.
         */
-       if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
-               return (laddr);
+       if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) {
+               ret_ia = laddr;
+               goto exit;
+       }
 
        /*
         * The outgoing interface is crucial in the general selection procedure
@@ -259,7 +269,7 @@
         */
        if (ifp == NULL) {
                *errorp = error;
-               return (NULL);
+               goto exit;
        }
 
        /*
@@ -281,7 +291,7 @@
 
        *errorp = in6_setscope(&dst, ifp, &odstzone);
        if (*errorp != 0)
-               return (NULL);
+               goto exit;
 
        for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
                int new_scope = -1, new_matchlen = -1;
@@ -544,10 +554,16 @@
 
        if ((ia = ia_best) == NULL) {
                *errorp = EADDRNOTAVAIL;
-               return (NULL);
+               goto exit;
        }
 
-       return (&ia->ia_addr.sin6_addr);
+       ret_ia = &ia->ia_addr.sin6_addr;
+exit:
+       if (ifpp == NULL)
+               if_put(ifp, PSREF);
+       curlwp_bindx(bound);
+       return ret_ia;
+#undef PSREF
 }
 #undef REPLACE
 #undef BREAK
@@ -556,7 +572,7 @@



Home | Main Index | Thread Index | Old Index