Author: bz
Date: Tue Jun 23 22:08:55 2009
New Revision: 194777
URL: http://svn.freebsd.org/changeset/base/194777

Log:
  Make callers to in6_selectsrc() and in6_pcbladdr() pass in memory
  to save the selected source address rather than returning an
  unreferenced copy to a pointer that might long be gone by the
  time we use the pointer for anything meaningful.
  
  Asked for by: rwatson
  Reviewed by:  rwatson

Modified:
  head/sys/netinet/tcp_usrreq.c
  head/sys/netinet6/icmp6.c
  head/sys/netinet6/in6_pcb.c
  head/sys/netinet6/in6_pcb.h
  head/sys/netinet6/in6_src.c
  head/sys/netinet6/ip6_var.h
  head/sys/netinet6/nd6_nbr.c
  head/sys/netinet6/raw_ip6.c
  head/sys/netinet6/udp6_usrreq.c

Modified: head/sys/netinet/tcp_usrreq.c
==============================================================================
--- head/sys/netinet/tcp_usrreq.c       Tue Jun 23 22:08:25 2009        
(r194776)
+++ head/sys/netinet/tcp_usrreq.c       Tue Jun 23 22:08:55 2009        
(r194777)
@@ -1137,7 +1137,7 @@ tcp6_connect(struct tcpcb *tp, struct so
        struct socket *so = inp->inp_socket;
        INIT_VNET_INET(so->so_vnet);
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
-       struct in6_addr *addr6;
+       struct in6_addr addr6;
        int error;
 
        INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
@@ -1161,13 +1161,13 @@ tcp6_connect(struct tcpcb *tp, struct so
        oinp = in6_pcblookup_hash(inp->inp_pcbinfo,
                                  &sin6->sin6_addr, sin6->sin6_port,
                                  IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
-                                 ? addr6
+                                 ? &addr6
                                  : &inp->in6p_laddr,
                                  inp->inp_lport,  0, NULL);
        if (oinp)
                return EADDRINUSE;
        if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
-               inp->in6p_laddr = *addr6;
+               inp->in6p_laddr = addr6;
        inp->in6p_faddr = sin6->sin6_addr;
        inp->inp_fport = sin6->sin6_port;
        /* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */

Modified: head/sys/netinet6/icmp6.c
==============================================================================
--- head/sys/netinet6/icmp6.c   Tue Jun 23 22:08:25 2009        (r194776)
+++ head/sys/netinet6/icmp6.c   Tue Jun 23 22:08:55 2009        (r194777)
@@ -2080,7 +2080,7 @@ icmp6_reflect(struct mbuf *m, size_t off
        int plen;
        int type, code;
        struct ifnet *outif = NULL;
-       struct in6_addr origdst, *src = NULL;
+       struct in6_addr origdst, src, *srcp = NULL;
 
        /* too short to reflect */
        if (off < sizeof(struct ip6_hdr)) {
@@ -2148,7 +2148,7 @@ icmp6_reflect(struct mbuf *m, size_t off
                if ((ia = ip6_getdstifaddr(m))) {
                        if (!(ia->ia6_flags &
                            (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)))
-                               src = &ia->ia_addr.sin6_addr;
+                               srcp = &ia->ia_addr.sin6_addr;
                } else {
                        struct sockaddr_in6 d;
 
@@ -2161,12 +2161,12 @@ icmp6_reflect(struct mbuf *m, size_t off
                        if (ia &&
                            !(ia->ia6_flags &
                            (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) {
-                               src = &ia->ia_addr.sin6_addr;
+                               srcp = &ia->ia_addr.sin6_addr;
                        }
                }
        }
 
-       if (src == NULL) {
+       if (srcp == NULL) {
                int e;
                struct sockaddr_in6 sin6;
                struct route_in6 ro;
@@ -2182,10 +2182,10 @@ icmp6_reflect(struct mbuf *m, size_t off
                sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */
 
                bzero(&ro, sizeof(ro));
-               src = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, &outif, &e);
+               e = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, &outif, &src);
                if (ro.ro_rt)
                        RTFREE(ro.ro_rt); /* XXX: we could use this */
-               if (src == NULL) {
+               if (e) {
                        char ip6buf[INET6_ADDRSTRLEN];
                        nd6log((LOG_DEBUG,
                            "icmp6_reflect: source can't be determined: "
@@ -2193,9 +2193,10 @@ icmp6_reflect(struct mbuf *m, size_t off
                            ip6_sprintf(ip6buf, &sin6.sin6_addr), e));
                        goto bad;
                }
+               srcp = &src;
        }
 
-       ip6->ip6_src = *src;
+       ip6->ip6_src = *srcp;
        ip6->ip6_flow = 0;
        ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
        ip6->ip6_vfc |= IPV6_VERSION;

Modified: head/sys/netinet6/in6_pcb.c
==============================================================================
--- head/sys/netinet6/in6_pcb.c Tue Jun 23 22:08:25 2009        (r194776)
+++ head/sys/netinet6/in6_pcb.c Tue Jun 23 22:08:55 2009        (r194777)
@@ -289,13 +289,14 @@ in6_pcbbind(register struct inpcb *inp, 
  */
 int
 in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
-    struct in6_addr **plocal_addr6)
+    struct in6_addr *plocal_addr6)
 {
        INIT_VNET_INET6(inp->inp_vnet);
        register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
        int error = 0;
        struct ifnet *ifp = NULL;
        int scope_ambiguous = 0;
+       struct in6_addr in6a;
 
        INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
        INP_WLOCK_ASSERT(inp);
@@ -323,25 +324,25 @@ in6_pcbladdr(register struct inpcb *inp,
        if ((error = prison_remote_ip6(inp->inp_cred, &sin6->sin6_addr)) != 0)
                return (error);
 
-       /*
-        * XXX: in6_selectsrc might replace the bound local address
-        * with the address specified by setsockopt(IPV6_PKTINFO).
-        * Is it the intended behavior?
-        */
-       *plocal_addr6 = in6_selectsrc(sin6, inp->in6p_outputopts,
-                                     inp, NULL,
-                                     inp->inp_cred,
-                                     &ifp, &error);
+       error = in6_selectsrc(sin6, inp->in6p_outputopts,
+           inp, NULL, inp->inp_cred, &ifp, &in6a);
+       if (error)
+               return (error);
+
        if (ifp && scope_ambiguous &&
            (error = in6_setscope(&sin6->sin6_addr, ifp, NULL)) != 0) {
                return(error);
        }
 
-       if (*plocal_addr6 == NULL) {
-               if (error == 0)
-                       error = EADDRNOTAVAIL;
-               return (error);
-       }
+       /*
+        * Do not update this earlier, in case we return with an error.
+        *
+        * XXX: this in6_selectsrc result might replace the bound local
+        * aaddress with the address specified by setsockopt(IPV6_PKTINFO).
+        * Is it the intended behavior?
+        */
+       *plocal_addr6 = in6a;
+
        /*
         * Don't do pcblookup call here; return interface in
         * plocal_addr6
@@ -362,8 +363,8 @@ int
 in6_pcbconnect(register struct inpcb *inp, struct sockaddr *nam,
     struct ucred *cred)
 {
-       struct in6_addr *addr6;
        register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
+       struct in6_addr addr6;
        int error;
 
        INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
@@ -379,7 +380,7 @@ in6_pcbconnect(register struct inpcb *in
        if (in6_pcblookup_hash(inp->inp_pcbinfo, &sin6->sin6_addr,
                               sin6->sin6_port,
                              IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
-                             ? addr6 : &inp->in6p_laddr,
+                             ? &addr6 : &inp->in6p_laddr,
                              inp->inp_lport, 0, NULL) != NULL) {
                return (EADDRINUSE);
        }
@@ -389,7 +390,7 @@ in6_pcbconnect(register struct inpcb *in
                        if (error)
                                return (error);
                }
-               inp->in6p_laddr = *addr6;
+               inp->in6p_laddr = addr6;
        }
        inp->in6p_faddr = sin6->sin6_addr;
        inp->inp_fport = sin6->sin6_port;

Modified: head/sys/netinet6/in6_pcb.h
==============================================================================
--- head/sys/netinet6/in6_pcb.h Tue Jun 23 22:08:25 2009        (r194776)
+++ head/sys/netinet6/in6_pcb.h Tue Jun 23 22:08:55 2009        (r194777)
@@ -74,8 +74,7 @@ void  in6_losing __P((struct inpcb *));
 int    in6_pcbbind __P((struct inpcb *, struct sockaddr *, struct ucred *));
 int    in6_pcbconnect __P((struct inpcb *, struct sockaddr *, struct ucred *));
 void   in6_pcbdisconnect __P((struct inpcb *));
-int    in6_pcbladdr __P((struct inpcb *, struct sockaddr *,
-                         struct in6_addr **));
+int    in6_pcbladdr(struct inpcb *, struct sockaddr *, struct in6_addr *);
 struct inpcb *
        in6_pcblookup_local __P((struct inpcbinfo *,
                                 struct in6_addr *, u_short, int,

Modified: head/sys/netinet6/in6_src.c
==============================================================================
--- head/sys/netinet6/in6_src.c Tue Jun 23 22:08:25 2009        (r194776)
+++ head/sys/netinet6/in6_src.c Tue Jun 23 22:08:55 2009        (r194777)
@@ -179,10 +179,10 @@ static struct in6_addrpolicy *match_addr
        goto out;               /* XXX: we can't use 'break' here */ \
 } while(0)
 
-struct in6_addr *
+int
 in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
     struct inpcb *inp, struct route_in6 *ro, struct ucred *cred,
-    struct ifnet **ifpp, int *errorp)
+    struct ifnet **ifpp, struct in6_addr *srcp)
 {
        INIT_VNET_INET6(curvnet);
        struct in6_addr dst;
@@ -193,10 +193,12 @@ in6_selectsrc(struct sockaddr_in6 *dstso
        struct in6_addrpolicy *dst_policy = NULL, *best_policy = NULL;
        u_int32_t odstzone;
        int prefer_tempaddr;
+       int error;
        struct ip6_moptions *mopts;
 
+       KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__));
+
        dst = dstsock->sin6_addr; /* make a copy for local operation */
-       *errorp = 0;
        if (ifpp)
                *ifpp = NULL;
 
@@ -219,10 +221,8 @@ in6_selectsrc(struct sockaddr_in6 *dstso
                struct in6_ifaddr *ia6;
 
                /* get the outgoing interface */
-               if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp))
-                   != 0) {
-                       return (NULL);
-               }
+               if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
+                       return (error);
 
                /*
                 * determine the appropriate zone id of the source based on
@@ -236,14 +236,14 @@ in6_selectsrc(struct sockaddr_in6 *dstso
                srcsock.sin6_len = sizeof(srcsock);
                srcsock.sin6_addr = pi->ipi6_addr;
                if (ifp) {
-                       *errorp = in6_setscope(&srcsock.sin6_addr, ifp, NULL);
-                       if (*errorp != 0)
-                               return (NULL);
+                       error = in6_setscope(&srcsock.sin6_addr, ifp, NULL);
+                       if (error)
+                               return (error);
                }
-               if (cred != NULL && (*errorp = prison_local_ip6(cred,
+               if (cred != NULL && (error = prison_local_ip6(cred,
                    &srcsock.sin6_addr, (inp != NULL &&
                    (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0)
-                       return (NULL);
+                       return (error);
 
                ia6 = (struct in6_ifaddr *)ifa_ifwithaddr(
                    (struct sockaddr *)&srcsock);
@@ -251,21 +251,14 @@ in6_selectsrc(struct sockaddr_in6 *dstso
                    (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
                        if (ia6 != NULL)
                                ifa_free(&ia6->ia_ifa);
-                       *errorp = EADDRNOTAVAIL;
-                       return (NULL);
+                       return (EADDRNOTAVAIL);
                }
                pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */
                if (ifpp)
                        *ifpp = ifp;
-
-               /*
-                * XXXRW: This returns a pointer into a structure with no
-                * refcount.  in6_selectsrc() should return it to caller-
-                * provided memory using call-by-reference rather than
-                * returning pointers into other memory.
-                */
+               bcopy(&ia6->ia_addr.sin6_addr, srcp, sizeof(*srcp));
                ifa_free(&ia6->ia_ifa);
-               return (&ia6->ia_addr.sin6_addr);
+               return (0);
        }
 
        /*
@@ -273,10 +266,11 @@ in6_selectsrc(struct sockaddr_in6 *dstso
         */
        if (inp != NULL && !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
                if (cred != NULL &&
-                   (*errorp = prison_local_ip6(cred, &inp->in6p_laddr,
+                   (error = prison_local_ip6(cred, &inp->in6p_laddr,
                    ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0)
-                       return (NULL);
-               return (&inp->in6p_laddr);
+                       return (error);
+               bcopy(&inp->in6p_laddr, srcp, sizeof(*srcp));
+               return (0);
        }
 
        /*
@@ -284,16 +278,16 @@ in6_selectsrc(struct sockaddr_in6 *dstso
         * the outgoing interface and the destination address.
         */
        /* get the outgoing interface */
-       if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
-               return (NULL);
+       if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
+               return (error);
 
 #ifdef DIAGNOSTIC
        if (ifp == NULL)        /* this should not happen */
                panic("in6_selectsrc: NULL ifp");
 #endif
-       *errorp = in6_setscope(&dst, ifp, &odstzone);
-       if (*errorp != 0)
-               return (NULL);
+       error = in6_setscope(&dst, ifp, &odstzone);
+       if (error)
+               return (error);
 
        for (ia = V_in6_ifaddr; ia; ia = ia->ia_next) {
                int new_scope = -1, new_matchlen = -1;
@@ -472,15 +466,14 @@ in6_selectsrc(struct sockaddr_in6 *dstso
                break;
        }
 
-       if ((ia = ia_best) == NULL) {
-               *errorp = EADDRNOTAVAIL;
-               return (NULL);
-       }
+       if ((ia = ia_best) == NULL)
+               return (EADDRNOTAVAIL);
 
        if (ifpp)
                *ifpp = ifp;
 
-       return (&ia->ia_addr.sin6_addr);
+       bcopy(&ia->ia_addr.sin6_addr, srcp, sizeof(*srcp));
+       return (0);
 }
 
 /*

Modified: head/sys/netinet6/ip6_var.h
==============================================================================
--- head/sys/netinet6/ip6_var.h Tue Jun 23 22:08:25 2009        (r194776)
+++ head/sys/netinet6/ip6_var.h Tue Jun 23 22:08:55 2009        (r194777)
@@ -402,9 +402,9 @@ int rip6_usrreq __P((struct socket *,
 int    dest6_input __P((struct mbuf **, int *, int));
 int    none_input __P((struct mbuf **, int *, int));
 
-struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *, struct ip6_pktopts 
*,
+int    in6_selectsrc(struct sockaddr_in6 *, struct ip6_pktopts *,
        struct inpcb *inp, struct route_in6 *, struct ucred *cred,
-       struct ifnet **, int *));
+       struct ifnet **, struct in6_addr *);
 int in6_selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
        struct ip6_moptions *, struct route_in6 *, struct ifnet **,
        struct rtentry **));

Modified: head/sys/netinet6/nd6_nbr.c
==============================================================================
--- head/sys/netinet6/nd6_nbr.c Tue Jun 23 22:08:25 2009        (r194776)
+++ head/sys/netinet6/nd6_nbr.c Tue Jun 23 22:08:55 2009        (r194777)
@@ -505,9 +505,9 @@ nd6_ns_output(struct ifnet *ifp, const s
                        dst_sa.sin6_len = sizeof(dst_sa);
                        dst_sa.sin6_addr = ip6->ip6_dst;
 
-                       src = in6_selectsrc(&dst_sa, NULL,
-                           NULL, &ro, NULL, NULL, &error);
-                       if (src == NULL) {
+                       error = in6_selectsrc(&dst_sa, NULL,
+                           NULL, &ro, NULL, NULL, &src_in);
+                       if (error) {
                                char ip6buf[INET6_ADDRSTRLEN];
                                nd6log((LOG_DEBUG,
                                    "nd6_ns_output: source can't be "
@@ -516,6 +516,7 @@ nd6_ns_output(struct ifnet *ifp, const s
                                    error));
                                goto bad;
                        }
+                       src = &src_in;
                }
        } else {
                /*
@@ -933,7 +934,7 @@ nd6_na_output(struct ifnet *ifp, const s
        struct ip6_hdr *ip6;
        struct nd_neighbor_advert *nd_na;
        struct ip6_moptions im6o;
-       struct in6_addr *src, daddr6;
+       struct in6_addr src, daddr6;
        struct sockaddr_in6 dst_sa;
        int icmp6len, maxlen, error;
        caddr_t mac = NULL;
@@ -1006,15 +1007,15 @@ nd6_na_output(struct ifnet *ifp, const s
         * Select a source whose scope is the same as that of the dest.
         */
        bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa));
-       src = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, NULL, &error);
-       if (src == NULL) {
+       error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, NULL, &src);
+       if (error) {
                char ip6buf[INET6_ADDRSTRLEN];
                nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
                    "determined: dst=%s, error=%d\n",
                    ip6_sprintf(ip6buf, &dst_sa.sin6_addr), error));
                goto bad;
        }
-       ip6->ip6_src = *src;
+       ip6->ip6_src = src;
        nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
        nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
        nd_na->nd_na_code = 0;

Modified: head/sys/netinet6/raw_ip6.c
==============================================================================
--- head/sys/netinet6/raw_ip6.c Tue Jun 23 22:08:25 2009        (r194776)
+++ head/sys/netinet6/raw_ip6.c Tue Jun 23 22:08:55 2009        (r194777)
@@ -389,7 +389,7 @@ rip6_output(m, va_alist)
        struct ifnet *oifp = NULL;
        int type = 0, code = 0;         /* for ICMPv6 output statistics only */
        int scope_ambiguous = 0;
-       struct in6_addr *in6a;
+       struct in6_addr in6a;
        va_list ap;
 
        va_start(ap, m);
@@ -450,16 +450,14 @@ rip6_output(m, va_alist)
        /*
         * Source address selection.
         */
-       if ((in6a = in6_selectsrc(dstsock, optp, in6p, NULL, so->so_cred,
-           &oifp, &error)) == NULL) {
-               if (error == 0)
-                       error = EADDRNOTAVAIL;
+       error = in6_selectsrc(dstsock, optp, in6p, NULL, so->so_cred,
+           &oifp, &in6a);
+       if (error)
                goto bad;
-       }
-       error = prison_get_ip6(in6p->inp_cred, in6a);
+       error = prison_get_ip6(in6p->inp_cred, &in6a);
        if (error != 0)
                goto bad;
-       ip6->ip6_src = *in6a;
+       ip6->ip6_src = in6a;
 
        if (oifp && scope_ambiguous) {
                /*
@@ -757,7 +755,7 @@ rip6_connect(struct socket *so, struct s
        INIT_VNET_INET6(so->so_vnet);
        struct inpcb *inp;
        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
-       struct in6_addr *in6a = NULL;
+       struct in6_addr in6a;
        struct ifnet *ifp = NULL;
        int error = 0, scope_ambiguous = 0;
 
@@ -787,13 +785,12 @@ rip6_connect(struct socket *so, struct s
        INP_INFO_WLOCK(&V_ripcbinfo);
        INP_WLOCK(inp);
        /* Source address selection. XXX: need pcblookup? */
-       in6a = in6_selectsrc(addr, inp->in6p_outputopts,
-                            inp, NULL, so->so_cred,
-                            &ifp, &error);
-       if (in6a == NULL) {
+       error = in6_selectsrc(addr, inp->in6p_outputopts,
+           inp, NULL, so->so_cred, &ifp, &in6a);
+       if (error) {
                INP_WUNLOCK(inp);
                INP_INFO_WUNLOCK(&V_ripcbinfo);
-               return (error ? error : EADDRNOTAVAIL);
+               return (error);
        }
 
        /* XXX: see above */
@@ -804,7 +801,7 @@ rip6_connect(struct socket *so, struct s
                return (error);
        }
        inp->in6p_faddr = addr->sin6_addr;
-       inp->in6p_laddr = *in6a;
+       inp->in6p_laddr = in6a;
        soisconnected(so);
        INP_WUNLOCK(inp);
        INP_INFO_WUNLOCK(&V_ripcbinfo);

Modified: head/sys/netinet6/udp6_usrreq.c
==============================================================================
--- head/sys/netinet6/udp6_usrreq.c     Tue Jun 23 22:08:25 2009        
(r194776)
+++ head/sys/netinet6/udp6_usrreq.c     Tue Jun 23 22:08:55 2009        
(r194777)
@@ -552,7 +552,7 @@ udp6_output(struct inpcb *inp, struct mb
        u_int32_t plen = sizeof(struct udphdr) + ulen;
        struct ip6_hdr *ip6;
        struct udphdr *udp6;
-       struct in6_addr *laddr, *faddr;
+       struct in6_addr *laddr, *faddr, in6a;
        struct sockaddr_in6 *sin6 = NULL;
        struct ifnet *oifp = NULL;
        int scope_ambiguous = 0;
@@ -650,13 +650,16 @@ udp6_output(struct inpcb *inp, struct mb
                }
 
                if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
-                       laddr = in6_selectsrc(sin6, optp, inp, NULL,
-                           td->td_ucred, &oifp, &error);
+                       error = in6_selectsrc(sin6, optp, inp, NULL,
+                           td->td_ucred, &oifp, &in6a);
+                       if (error)
+                               goto release;
                        if (oifp && scope_ambiguous &&
                            (error = in6_setscope(&sin6->sin6_addr,
                            oifp, NULL))) {
                                goto release;
                        }
+                       laddr = &in6a;
                } else
                        laddr = &inp->in6p_laddr;       /* XXX */
                if (laddr == NULL) {
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to