aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet6/raw_ip6.c
diff options
context:
space:
mode:
authorRobert Watson <rwatson@FreeBSD.org>2009-06-23 20:19:09 +0000
committerRobert Watson <rwatson@FreeBSD.org>2009-06-23 20:19:09 +0000
commit8c0fec805f76bef04e007ca08552bd80ab64daf9 (patch)
tree5ce1a7dad67026f119a839b3325454ebafa72c51 /sys/netinet6/raw_ip6.c
parentabcd328be6335621a1152ed2ce08b4550ab4242c (diff)
downloadsrc-8c0fec805f76bef04e007ca08552bd80ab64daf9.tar.gz
src-8c0fec805f76bef04e007ca08552bd80ab64daf9.zip
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)
Notes
Notes: svn path=/head/; revision=194760
Diffstat (limited to 'sys/netinet6/raw_ip6.c')
-rw-r--r--sys/netinet6/raw_ip6.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 3c514d888259..cd7d8173de4f 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -714,7 +714,7 @@ rip6_bind(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 ifaddr *ia = NULL;
+ struct ifaddr *ifa = NULL;
int error = 0;
inp = sotoinpcb(so);
@@ -730,14 +730,17 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
return (error);
if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
- (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
+ (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL)
return (EADDRNOTAVAIL);
- if (ia &&
- ((struct in6_ifaddr *)ia)->ia6_flags &
+ if (ifa != NULL &&
+ ((struct in6_ifaddr *)ifa)->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
+ ifa_free(ifa);
return (EADDRNOTAVAIL);
}
+ if (ifa != NULL)
+ ifa_free(ifa);
INP_INFO_WLOCK(&V_ripcbinfo);
INP_WLOCK(inp);
inp->in6p_laddr = addr->sin6_addr;