Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Ensure that packets are sent from a valid address.



details:   https://anonhg.NetBSD.org/src/rev/3ca0b203a118
branches:  trunk
changeset: 347761:3ca0b203a118
user:      roy <roy%NetBSD.org@localhost>
date:      Thu Sep 15 18:25:45 2016 +0000

description:
Ensure that packets are sent from a valid address.
If the packet is TCP and the address is detached or tentative then
it's just dropped, otherwise an error is returned.

This is needed because you can bind to a valid address and it can then
become invalid.

This satisfies RFC 4862 section 5.5.4.

diffstat:

 sys/netinet/ip_output.c   |  49 +++++++++++++++++++++++++++++++++++++---
 sys/netinet6/ip6_output.c |  57 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 100 insertions(+), 6 deletions(-)

diffs (183 lines):

diff -r 706ef574663d -r 3ca0b203a118 sys/netinet/ip_output.c
--- a/sys/netinet/ip_output.c   Thu Sep 15 18:17:29 2016 +0000
+++ b/sys/netinet/ip_output.c   Thu Sep 15 18:25:45 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_output.c,v 1.260 2016/08/01 03:15:30 ozaki-r Exp $  */
+/*     $NetBSD: ip_output.c,v 1.261 2016/09/15 18:25:45 roy Exp $      */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.260 2016/08/01 03:15:30 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.261 2016/09/15 18:25:45 roy Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -153,6 +153,7 @@
 static struct ifnet *ip_multicast_if(struct in_addr *, int *);
 static void ip_mloopback(struct ifnet *, struct mbuf *,
     const struct sockaddr_in *);
+static int ip_ifaddrvalid(const struct in_ifaddr *);
 
 extern pfil_head_t *inet_pfil_hook;                    /* XXX */
 
@@ -607,14 +608,31 @@
 
        m->m_pkthdr.csum_data |= hlen << 16;
 
-#if IFA_STATS
        /*
         * search for the source address structure to
         * maintain output statistics.
         */
        KASSERT(ia == NULL);
        ia = in_get_ia_psref(ip->ip_src, &psref_ia);
-#endif
+
+       /* Ensure we only sent from a valid address. */
+       if ((ia != NULL || (flags & IP_FORWARDING) == 0) &&
+           (error = ip_ifaddrvalid(ia)) != 0)
+       {
+               arplog(LOG_ERR,
+                   "refusing to send from invalid address %s (pid %d)\n",
+                   in_fmtaddr(ip->ip_src), curproc->p_pid);
+               IP_STATINC(IP_STAT_ODROPPED);
+               if (error == 1 && ip->ip_p == IPPROTO_TCP)
+                       /* Address exists, but is tentative or detached.
+                        * We can't send from it because it's invalid,
+                        * so we drop the packet and continue ...
+                        * TCP will timeout eventually. */
+                       error = 0;
+               else
+                       error = EADDRNOTAVAIL;
+               goto bad;
+       }
 
        /* Maybe skip checksums on loopback interfaces. */
        if (IN_NEED_CHECKSUM(ifp, M_CSUM_IPv4)) {
@@ -1850,3 +1868,26 @@
        KERNEL_UNLOCK_ONE(NULL);
 #endif
 }
+
+/*
+ * Ensure sending address is valid.
+ * Returns 0 on success, -1 if an error should be sent back or 1
+ * if the packet could be dropped without error (protocol dependent).
+ */
+static int
+ip_ifaddrvalid(const struct in_ifaddr *ia)
+{
+
+       if (ia == NULL)
+               return -1;
+
+       if (ia->ia_addr.sin_addr.s_addr == INADDR_ANY)
+               return 0;
+
+       if (ia->ia4_flags & IN_IFF_DUPLICATED)
+               return -1;
+       else if (ia->ia4_flags & (IN_IFF_TENTATIVE | IN_IFF_DETACHED))
+               return 1;
+
+       return 0;
+}
diff -r 706ef574663d -r 3ca0b203a118 sys/netinet6/ip6_output.c
--- a/sys/netinet6/ip6_output.c Thu Sep 15 18:17:29 2016 +0000
+++ b/sys/netinet6/ip6_output.c Thu Sep 15 18:25:45 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip6_output.c,v 1.173 2016/08/01 03:15:31 ozaki-r Exp $ */
+/*     $NetBSD: ip6_output.c,v 1.174 2016/09/15 18:25:45 roy Exp $     */
 /*     $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $    */
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.173 2016/08/01 03:15:31 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.174 2016/09/15 18:25:45 roy Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -77,6 +77,7 @@
 #include <sys/protosw.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
+#include <sys/syslog.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
 #include <sys/kauth.h>
@@ -135,6 +136,7 @@
 static int ip6_getpmtu(struct route *, struct route *, struct ifnet *,
     const struct in6_addr *, u_long *, int *);
 static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
+static int ip6_ifaddrvalid(const struct in6_addr *);
 
 #ifdef RFC2292
 static int ip6_pcbopts(struct ip6_pktopts **, struct socket *, struct sockopt *);
@@ -550,6 +552,22 @@
 
        /* scope check is done. */
 
+       /* Ensure we only sent from a valid address. */
+       if ((error = ip6_ifaddrvalid(&src0)) != 0) {
+               nd6log(LOG_ERR,
+                   "refusing to send from invalid address %s (pid %d)\n",
+                   ip6_sprintf(&src0), curproc->p_pid);
+               if (error == 1 && ip6->ip6_nxt == IPPROTO_TCP)
+                       /* Address exists, but is tentative or detached.
+                        * We can't send from it because it's invalid,
+                        * so we drop the packet and continue ...
+                        * TCP will timeout eventually. */
+                       error = 0;
+               else
+                       error = EADDRNOTAVAIL;
+               goto bad;
+       }
+
        if (rt == NULL || IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
                dst = satocsin6(rtcache_getdst(ro));
                KASSERT(dst != NULL);
@@ -3250,3 +3268,38 @@
        return len;
 #undef elen
 }
+
+/*
+ * Ensure sending address is valid.
+ * Returns 0 on success, -1 if an error should be sent back or 1
+ * if the packet could be dropped without error (protocol dependent).
+ */
+static int
+ip6_ifaddrvalid(const struct in6_addr *addr)
+{
+       struct sockaddr_in6 sin6;
+       int s, error;
+       struct ifaddr *ifa;
+       struct in6_ifaddr *ia6;
+
+       if (IN6_IS_ADDR_UNSPECIFIED(addr))
+               return 0;
+
+       memset(&sin6, 0, sizeof(sin6));
+       sin6.sin6_family = AF_INET6;
+       sin6.sin6_len = sizeof(sin6);
+       sin6.sin6_addr = *addr;
+
+       s = pserialize_read_enter();
+       ifa = ifa_ifwithaddr(sin6tosa(&sin6));
+       if ((ia6 = ifatoia6(ifa)) == NULL ||
+           ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED))
+               error = -1;
+       else if (ia6->ia6_flags & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED))
+               error = 1;
+       else
+               error = 0;
+       pserialize_read_exit(s);
+
+       return error;
+}



Home | Main Index | Thread Index | Old Index