From: Hasso Tepper Date: Fri, 3 Oct 2008 08:02:23 +0000 (+0000) Subject: If a neighbor solictation or neighbor advertisement isn't from the X-Git-Url: https://repo.or.cz/w/dragonfly.git/commitdiff_plain/1b9aa0f4f3dc08dd63da6465ccfb0e82f398a54e If a neighbor solictation or neighbor advertisement isn't from the unspecified address, make sure that the source address matches one of the interfaces address prefixes. CVE-2008-2476 Obtained-from: NetBSD with modifications --- diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index c29085b845..a048cf5859 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1,5 +1,5 @@ /* $FreeBSD: src/sys/netinet6/in6.c,v 1.7.2.9 2002/04/28 05:40:26 suz Exp $ */ -/* $DragonFly: src/sys/netinet6/in6.c,v 1.29 2008/04/20 13:44:26 swildner Exp $ */ +/* $DragonFly: src/sys/netinet6/in6.c,v 1.29.2.1 2008/10/03 08:02:23 hasso Exp $ */ /* $KAME: in6.c,v 1.259 2002/01/21 11:37:50 keiichi Exp $ */ /* @@ -1784,6 +1784,34 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr) } /* + * find the internet address on a given interface corresponding to a neighbor's + * address. + */ +struct in6_ifaddr * +in6ifa_ifplocaladdr(const struct ifnet *ifp, const struct in6_addr *addr) +{ + struct ifaddr *ifa; + struct in6_ifaddr *ia; + struct ifaddr_container *ifac; + + TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) { + ifa = ifac->ifa; + + if (ifa->ifa_addr == NULL) + continue; /* just for safety */ + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ia = (struct in6_ifaddr *)ifa; + if (IN6_ARE_MASKED_ADDR_EQUAL(addr, + &ia->ia_addr.sin6_addr, + &ia->ia_prefixmask.sin6_addr)) + return ia; + } + + return NULL; +} + +/* * Convert IP6 address to printable (loggable) representation. */ static char digits[] = "0123456789abcdef"; diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index ee47cf8c1a..6df87dec8c 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -1,5 +1,5 @@ /* $FreeBSD: src/sys/netinet6/in6_var.h,v 1.3.2.3 2002/04/28 05:40:27 suz Exp $ */ -/* $DragonFly: src/sys/netinet6/in6_var.h,v 1.9 2008/03/07 11:34:21 sephe Exp $ */ +/* $DragonFly: src/sys/netinet6/in6_var.h,v 1.9.2.1 2008/10/03 08:02:23 hasso Exp $ */ /* $KAME: in6_var.h,v 1.56 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -607,6 +607,8 @@ void in6_purgemkludge (struct ifnet *); struct in6_ifaddr *in6ifa_ifpforlinklocal (struct ifnet *, int); struct in6_ifaddr *in6ifa_ifpwithaddr (struct ifnet *, struct in6_addr *); +struct in6_ifaddr *in6ifa_ifplocaladdr(const struct ifnet *, + const struct in6_addr *); char *ip6_sprintf (const struct in6_addr *); int in6_addr2scopeid (struct ifnet *, struct in6_addr *); int in6_matchlen (struct in6_addr *, struct in6_addr *); diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 5aff021ce7..64a66ecde6 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -1,5 +1,5 @@ /* $FreeBSD: src/sys/netinet6/nd6_nbr.c,v 1.4.2.6 2003/01/23 21:06:47 sam Exp $ */ -/* $DragonFly: src/sys/netinet6/nd6_nbr.c,v 1.23 2008/03/07 11:34:21 sephe Exp $ */ +/* $DragonFly: src/sys/netinet6/nd6_nbr.c,v 1.23.2.1 2008/10/03 08:02:23 hasso Exp $ */ /* $KAME: nd6_nbr.c,v 1.86 2002/01/21 02:33:04 jinmei Exp $ */ /* @@ -149,6 +149,15 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) "(wrong ip6 dst)\n")); goto bad; } + } else { + /* + * Make sure the source address is from a neighbor's address. + */ + if (in6ifa_ifplocaladdr(ifp, &saddr6) == NULL) { + nd6log((LOG_INFO, "nd6_ns_input: " + "NS packet from non-neighbor\n")); + goto bad; + } } if (IN6_IS_ADDR_MULTICAST(&taddr6)) { @@ -532,9 +541,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) struct ifnet *ifp = m->m_pkthdr.rcvif; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_neighbor_advert *nd_na; -#if 0 struct in6_addr saddr6 = ip6->ip6_src; -#endif struct in6_addr daddr6 = ip6->ip6_dst; struct in6_addr taddr6; int flags; @@ -628,6 +635,15 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) goto freeit; } + /* + * Make sure the source address is from a neighbor's address. + */ + if (in6ifa_ifplocaladdr(ifp, &saddr6) == NULL) { + nd6log((LOG_INFO, "nd6_na_input: " + "NA packet from non-neighbor\n")); + goto bad; + } + if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s "