diff options
author | bz <bz@FreeBSD.org> | 2009-06-23 22:08:55 +0000 |
---|---|---|
committer | bz <bz@FreeBSD.org> | 2009-06-23 22:08:55 +0000 |
commit | a8839212d25048d806814db571facbc74524f2ff (patch) | |
tree | 3a58d4c5cc129f8a6f67da930359091b3204e2b3 /sys | |
parent | 6438d166b7094064ec21ed778af3438294b17ed2 (diff) | |
download | FreeBSD-src-a8839212d25048d806814db571facbc74524f2ff.zip FreeBSD-src-a8839212d25048d806814db571facbc74524f2ff.tar.gz |
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
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 6 | ||||
-rw-r--r-- | sys/netinet6/icmp6.c | 15 | ||||
-rw-r--r-- | sys/netinet6/in6_pcb.c | 37 | ||||
-rw-r--r-- | sys/netinet6/in6_pcb.h | 3 | ||||
-rw-r--r-- | sys/netinet6/in6_src.c | 63 | ||||
-rw-r--r-- | sys/netinet6/ip6_var.h | 4 | ||||
-rw-r--r-- | sys/netinet6/nd6_nbr.c | 15 | ||||
-rw-r--r-- | sys/netinet6/raw_ip6.c | 27 | ||||
-rw-r--r-- | sys/netinet6/udp6_usrreq.c | 9 |
9 files changed, 87 insertions, 92 deletions
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index f9217b5..5fc2837 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1137,7 +1137,7 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) 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 sockaddr *nam, struct thread *td) 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 */ diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 786ddc2..3ecf386 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -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; diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 485efb9..d0fb235 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -289,13 +289,14 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam, */ 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, struct sockaddr *nam, 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 *inp, struct sockaddr *nam, 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 *inp, struct sockaddr *nam, if (error) return (error); } - inp->in6p_laddr = *addr6; + inp->in6p_laddr = addr6; } inp->in6p_faddr = sin6->sin6_addr; inp->inp_fport = sin6->sin6_port; diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h index b2cc724..c54a8cf 100644 --- a/sys/netinet6/in6_pcb.h +++ b/sys/netinet6/in6_pcb.h @@ -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, diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index 5443234..364b262 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -179,10 +179,10 @@ static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *); 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 *dstsock, struct ip6_pktopts *opts, 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 *dstsock, struct ip6_pktopts *opts, 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 *dstsock, struct ip6_pktopts *opts, 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 *dstsock, struct ip6_pktopts *opts, (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 *dstsock, struct ip6_pktopts *opts, */ 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 *dstsock, struct ip6_pktopts *opts, * 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 *dstsock, struct ip6_pktopts *opts, 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); } /* diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 74749f6..414880b 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -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 **)); diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 1e65927..8c5bf89 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -505,9 +505,9 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, 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 struct in6_addr *daddr6, error)); goto bad; } + src = &src_in; } } else { /* @@ -933,7 +934,7 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0, 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 struct in6_addr *daddr6_0, * 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; diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index cd7d817..73bb966 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -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 sockaddr *nam, struct thread *td) 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 sockaddr *nam, struct thread *td) 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 sockaddr *nam, struct thread *td) 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); diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 590e6d6..5eb4a47 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -552,7 +552,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, 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 mbuf *m, struct sockaddr *addr6, } 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) { |