Source-Changes-HG archive

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

[src/trunk]: src/sys When reassembling IPv4/IPv6 packets, ensure...



details:   https://anonhg.NetBSD.org/src/rev/cfb717f3e6fb
branches:  trunk
changeset: 319079:cfb717f3e6fb
user:      maxv <maxv%NetBSD.org@localhost>
date:      Tue May 15 19:16:38 2018 +0000

description:
When reassembling IPv4/IPv6 packets, ensure each fragment has been subject
to the same IPsec processing. That is to say, that all fragments are ESP,
or AH, or AH+ESP, or none.

The reassembly mechanism can be used both on the wire and inside an IPsec
tunnel, so we need to make sure all fragments of a packet were received
on only one side.

Even though I haven't tried, I believe there are configurations where it
would be possible for an attacker to inject an unencrypted fragment into a
legitimate stream of already-decrypted-and-authenticated fragments.

Typically on IPsec gateways with ESP tunnels, where we can encapsulate
fragments (as opposed to the general case, where we fragment encapsulated
data).

Note, for the record: a funnier thing, under IPv4, would be to send a
zero-sized !MFF fragment at the head of the packet, and manage to trigger
an ICMP error; M_DECRYPTED gets lost by the reassembly, and ICMP will reply
with the packet in clear (not encrypted).

diffstat:

 sys/netinet/ip_reass.c |  29 +++++++++++++++++++++--------
 sys/netinet6/frag6.c   |  15 ++++++++++++---
 2 files changed, 33 insertions(+), 11 deletions(-)

diffs (136 lines):

diff -r 36588a0d34d6 -r cfb717f3e6fb sys/netinet/ip_reass.c
--- a/sys/netinet/ip_reass.c    Tue May 15 10:23:03 2018 +0000
+++ b/sys/netinet/ip_reass.c    Tue May 15 19:16:38 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_reass.c,v 1.16 2018/05/03 07:25:49 maxv Exp $       */
+/*     $NetBSD: ip_reass.c,v 1.17 2018/05/15 19:16:38 maxv Exp $       */
 
 /*
  * Copyright (c) 1982, 1986, 1988, 1993
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.16 2018/05/03 07:25:49 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.17 2018/05/15 19:16:38 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -93,7 +93,8 @@
        struct in_addr          ipq_src;
        struct in_addr          ipq_dst;
        uint16_t                ipq_nfrags;     /* frags in this queue entry */
-       uint8_t                 ipq_tos;        /* TOS of this fragment */
+       uint8_t                 ipq_tos;        /* TOS of this fragment */
+       int                     ipq_ipsec;      /* IPsec flags */
 } ipfr_queue_t;
 
 /*
@@ -217,6 +218,7 @@
        struct ip *ip = ipqe->ipqe_ip, *qip;
        const int hlen = ip->ip_hl << 2;
        struct mbuf *m = ipqe->ipqe_m, *t;
+       int ipsecflags = m->m_flags & (M_DECRYPTED|M_AUTHIPHDR);
        ipfr_qent_t *nq, *p, *q;
        int i, next;
 
@@ -269,6 +271,7 @@
                fp->ipq_p = ip->ip_p;
                fp->ipq_id = ip->ip_id;
                fp->ipq_tos = ip->ip_tos;
+               fp->ipq_ipsec = ipsecflags;
                fp->ipq_src = ip->ip_src;
                fp->ipq_dst = ip->ip_dst;
                LIST_INSERT_HEAD(&ip_frags[hash], fp, ipq_q);
@@ -614,6 +617,7 @@
        const int hlen = ip->ip_hl << 2;
        const int len = ntohs(ip->ip_len);
        struct mbuf *m = *m0;
+       int ipsecflags = m->m_flags & (M_DECRYPTED|M_AUTHIPHDR);
        ipfr_queue_t *fp;
        ipfr_qent_t *ipqe;
        u_int hash, off, flen;
@@ -669,11 +673,20 @@
                break;
        }
 
-       /* Make sure that TOS matches previous fragments. */
-       if (fp && fp->ipq_tos != ip->ip_tos) {
-               IP_STATINC(IP_STAT_BADFRAGS);
-               mutex_exit(&ipfr_lock);
-               return EINVAL;
+       if (fp) {
+               /* All fragments must have the same IPsec flags. */
+               if (fp->ipq_ipsec != ipsecflags) {
+                       IP_STATINC(IP_STAT_BADFRAGS);
+                       mutex_exit(&ipfr_lock);
+                       return EINVAL;
+               }
+
+               /* Make sure that TOS matches previous fragments. */
+               if (fp->ipq_tos != ip->ip_tos) {
+                       IP_STATINC(IP_STAT_BADFRAGS);
+                       mutex_exit(&ipfr_lock);
+                       return EINVAL;
+               }
        }
 
        /*
diff -r 36588a0d34d6 -r cfb717f3e6fb sys/netinet6/frag6.c
--- a/sys/netinet6/frag6.c      Tue May 15 10:23:03 2018 +0000
+++ b/sys/netinet6/frag6.c      Tue May 15 19:16:38 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: frag6.c,v 1.73 2018/05/03 07:25:49 maxv Exp $  */
+/*     $NetBSD: frag6.c,v 1.74 2018/05/15 19:16:38 maxv Exp $  */
 /*     $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $  */
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.73 2018/05/03 07:25:49 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.74 2018/05/15 19:16:38 maxv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -76,6 +76,7 @@
        struct ip6q     *ip6q_prev;
        int             ip6q_unfrglen;  /* len of unfragmentable part */
        int             ip6q_nfrag;     /* # of fragments */
+       int             ip6q_ipsec;     /* IPsec flags */
 };
 
 struct ip6asfrag {
@@ -162,6 +163,7 @@
        struct ip6q *q6;
        struct ip6asfrag *af6, *ip6af, *af6dwn;
        int offset = *offp, nxt, i, next;
+       int ipsecflags = m->m_flags & (M_DECRYPTED|M_AUTHIPHDR);
        int first_frag = 0;
        int fragoff, frgpartlen;        /* must be larger than u_int16_t */
        struct ifnet *dstifp;
@@ -247,6 +249,13 @@
                    IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst))
                        break;
 
+       if (q6 != &ip6q) {
+               /* All fragments must have the same IPsec flags. */
+               if (q6->ip6q_ipsec != ipsecflags) {
+                       goto dropfrag;
+               }
+       }
+
        if (q6 == &ip6q) {
                /*
                 * the first fragment to arrive, create a reassembly queue.
@@ -279,8 +288,8 @@
                q6->ip6q_src    = ip6->ip6_src;
                q6->ip6q_dst    = ip6->ip6_dst;
                q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */
-
                q6->ip6q_nfrag = 0;
+               q6->ip6q_ipsec = ipsecflags;
        }
 
        /*



Home | Main Index | Thread Index | Old Index