If a neighbor solictation or neighbor advertisement isn't from the
authorHasso Tepper <hasso@dragonflybsd.org>
Fri, 3 Oct 2008 08:02:23 +0000 (3 08:02 +0000)
committerHasso Tepper <hasso@dragonflybsd.org>
Fri, 3 Oct 2008 08:02:23 +0000 (3 08:02 +0000)
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
sys/netinet6/in6_var.h
sys/netinet6/nd6_nbr.c

index c29085b..a048cf5 100644 (file)
@@ -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";
index ee47cf8..6df87de 100644 (file)
@@ -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 *);
index 5aff021..64a66ec 100644 (file)
@@ -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 "