diff options
author | bz <bz@FreeBSD.org> | 2010-04-27 15:05:03 +0000 |
---|---|---|
committer | bz <bz@FreeBSD.org> | 2010-04-27 15:05:03 +0000 |
commit | e66b2bd00b8aeff7786ee941efdd1b5c067e459c (patch) | |
tree | e8f5f7bbdb45d9497a7945fa48e9b2d9619a71fa /sys/netinet6/in6_src.c | |
parent | 6def960c90c238bc5be3dd59b7704373f0b3989c (diff) | |
download | FreeBSD-src-e66b2bd00b8aeff7786ee941efdd1b5c067e459c.zip FreeBSD-src-e66b2bd00b8aeff7786ee941efdd1b5c067e459c.tar.gz |
Make sure IPv6 source address selection does not change interface
addresses while walking the IPv6 address list if in the jail case
something is connecting to ::1.
Reported by: Pieter de Boer (pieter thedarkside.nl)
Tested by: Pieter de Boer (pieter thedarkside.nl)
MFC after: 4 days
Diffstat (limited to 'sys/netinet6/in6_src.c')
-rw-r--r-- | sys/netinet6/in6_src.c | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index ea302a5..e6c2cd8 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -182,7 +182,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, struct inpcb *inp, struct route_in6 *ro, struct ucred *cred, struct ifnet **ifpp, struct in6_addr *srcp) { - struct in6_addr dst; + struct in6_addr dst, tmp; struct ifnet *ifp = NULL; struct in6_ifaddr *ia = NULL, *ia_best = NULL; struct in6_pktinfo *pi = NULL; @@ -326,10 +326,9 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, if (!V_ip6_use_deprecated && IFA6_IS_DEPRECATED(ia)) continue; + /* If jailed only take addresses of the jail into account. */ if (cred != NULL && - prison_local_ip6(cred, &ia->ia_addr.sin6_addr, - (inp != NULL && - (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0) + prison_check_ip6(cred, &ia->ia_addr.sin6_addr) != 0) continue; /* Rule 1: Prefer same address */ @@ -476,10 +475,26 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, return (EADDRNOTAVAIL); } + /* + * At this point at least one of the addresses belonged to the jail + * but it could still be, that we want to further restrict it, e.g. + * theoratically IN6_IS_ADDR_LOOPBACK. + * It must not be IN6_IS_ADDR_UNSPECIFIED anymore. + * prison_local_ip6() will fix an IN6_IS_ADDR_LOOPBACK but should + * let all others previously selected pass. + * Use tmp to not change ::1 on lo0 to the primary jail address. + */ + tmp = ia->ia_addr.sin6_addr; + if (cred != NULL && prison_local_ip6(cred, &tmp, (inp != NULL && + (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0) { + IN6_IFADDR_RUNLOCK(); + return (EADDRNOTAVAIL); + } + if (ifpp) *ifpp = ifp; - bcopy(&ia->ia_addr.sin6_addr, srcp, sizeof(*srcp)); + bcopy(&tmp, srcp, sizeof(*srcp)); IN6_IFADDR_RUNLOCK(); return (0); } |