diff options
author | rwatson <rwatson@FreeBSD.org> | 2009-06-23 20:19:09 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2009-06-23 20:19:09 +0000 |
commit | c9ef486fe1d7da6a2212a337eacc5ed5b40f85d9 (patch) | |
tree | 5ce1a7dad67026f119a839b3325454ebafa72c51 /sys/netipx/ipx_pcb.c | |
parent | f75c2385c686d82292982283b5f0a9c9988beda8 (diff) | |
download | FreeBSD-src-c9ef486fe1d7da6a2212a337eacc5ed5b40f85d9.zip FreeBSD-src-c9ef486fe1d7da6a2212a337eacc5ed5b40f85d9.tar.gz |
Modify most routines returning 'struct ifaddr *' to return references
rather than pointers, requiring callers to properly dispose of those
references. The following routines now return references:
ifaddr_byindex
ifa_ifwithaddr
ifa_ifwithbroadaddr
ifa_ifwithdstaddr
ifa_ifwithnet
ifaof_ifpforaddr
ifa_ifwithroute
ifa_ifwithroute_fib
rt_getifa
rt_getifa_fib
IFP_TO_IA
ip_rtaddr
in6_ifawithifp
in6ifa_ifpforlinklocal
in6ifa_ifpwithaddr
in6_ifadd
carp_iamatch6
ip6_getdstifaddr
Remove unused macro which didn't have required referencing:
IFP_TO_IA6
This closes many small races in which changes to interface
or address lists while an ifaddr was in use could lead to use of freed
memory (etc). In a few cases, add missing if_addr_list locking
required to safely acquire references.
Because of a lack of deep copying support, we accept a race in which
an in6_ifaddr pointed to by mbuf tags and extracted with
ip6_getdstifaddr() doesn't hold a reference while in transmit. Once
we have mbuf tag deep copy support, this can be fixed.
Reviewed by: bz
Obtained from: Apple, Inc. (portions)
MFC after: 6 weeks (portions)
Diffstat (limited to 'sys/netipx/ipx_pcb.c')
-rw-r--r-- | sys/netipx/ipx_pcb.c | 34 |
1 files changed, 27 insertions, 7 deletions
diff --git a/sys/netipx/ipx_pcb.c b/sys/netipx/ipx_pcb.c index 4c8eba0..77fbfe8 100644 --- a/sys/netipx/ipx_pcb.c +++ b/sys/netipx/ipx_pcb.c @@ -158,7 +158,6 @@ noname: int ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) { - struct ipx_ifaddr *ia; struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam; struct ipx_addr *dst; struct route *ro; @@ -167,8 +166,6 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) IPX_LIST_LOCK_ASSERT(); IPX_LOCK_ASSERT(ipxp); - ia = NULL; - if (sipx->sipx_family != AF_IPX) return (EAFNOSUPPORT); if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) @@ -213,6 +210,8 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) rtalloc_ign(ro, 0); } if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { + struct ipx_ifaddr *ia = NULL; + /* * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. @@ -225,8 +224,10 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) { IPX_IFADDR_RLOCK(); for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) - if (ia->ia_ifp == ifp) + if (ia->ia_ifp == ifp) { + ifa_ref(&ia->ia_ifa); break; + } IPX_IFADDR_RUNLOCK(); } if (ia == NULL) { @@ -235,16 +236,28 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) ia = (struct ipx_ifaddr *) ifa_ifwithdstaddr((struct sockaddr *)sipx); sipx->sipx_addr.x_port = fport; - if (ia == NULL) + if (ia == NULL) { + IPX_IFADDR_RLOCK(); ia = ipx_iaonnetof(&sipx->sipx_addr); - if (ia == NULL) + if (ia != NULL) + ifa_ref(&ia->ia_ifa); + IPX_IFADDR_RUNLOCK(); + } + if (ia == NULL) { + IPX_IFADDR_RLOCK(); ia = ipx_ifaddr; + if (ia != NULL) + ifa_ref(&ia->ia_ifa); + IPX_IFADDR_RUNLOCK(); + } if (ia == NULL) return (EADDRNOTAVAIL); } ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; + ifa_free(&ia->ia_ifa); } if (ipx_nullhost(ipxp->ipxp_laddr)) { + struct ipx_ifaddr *ia = NULL; /* * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. @@ -257,8 +270,10 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) { IPX_IFADDR_RLOCK(); for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) - if (ia->ia_ifp == ifp) + if (ia->ia_ifp == ifp) { + ifa_ref(&ia->ia_ifa); break; + } IPX_IFADDR_RUNLOCK(); } if (ia == NULL) { @@ -270,17 +285,22 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) if (ia == NULL) { IPX_IFADDR_RLOCK(); ia = ipx_iaonnetof(&sipx->sipx_addr); + if (ia != NULL) + ifa_ref(&ia->ia_ifa); IPX_IFADDR_RUNLOCK(); } if (ia == NULL) { IPX_IFADDR_RLOCK(); ia = ipx_ifaddr; + if (ia != NULL) + ifa_ref(&ia->ia_ifa); IPX_IFADDR_RUNLOCK(); } if (ia == NULL) return (EADDRNOTAVAIL); } ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host; + ifa_free(&ia->ia_ifa); } if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) return (EADDRINUSE); |