From 100c1c44df3cd909c8b593d49b33038001210b40 Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Fri, 3 Oct 2008 07:59:20 +0000 Subject: [PATCH] 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 --- sys/netinet6/in6.c | 30 +++++++++++++++++++++++++++++- sys/netinet6/in6_var.h | 4 +++- sys/netinet6/nd6_nbr.c | 22 +++++++++++++++++++--- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index c29085b845..71316a30db 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.30 2008/10/03 07:59:20 hasso Exp $ */ /* $KAME: in6.c,v 1.259 2002/01/21 11:37:50 keiichi Exp $ */ /* @@ -1783,6 +1783,34 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr) return (NULL); } +/* + * 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. */ diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index ee47cf8c1a..68ca18d33c 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.10 2008/10/03 07:59:20 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..2c4a8e301b 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.24 2008/10/03 07:59:20 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 " -- 2.41.0