Source-Changes-HG archive

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

[src/netbsd-8]: src/sys Pull up following revision(s) (requested by maxv in t...



details:   https://anonhg.NetBSD.org/src/rev/c223658e792e
branches:  netbsd-8
changeset: 852016:c223658e792e
user:      martin <martin%NetBSD.org@localhost>
date:      Thu Sep 27 15:07:34 2018 +0000

description:
Pull up following revision(s) (requested by maxv in ticket #1041):

        sys/netinet/ip_reass.c: revision 1.17 (patch)
        sys/netinet6/frag6.c: revision 1.74 (patch)

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   |  14 +++++++++++---
 2 files changed, 32 insertions(+), 11 deletions(-)

diffs (128 lines):

diff -r a785aaa14b3e -r c223658e792e sys/netinet/ip_reass.c
--- a/sys/netinet/ip_reass.c    Thu Sep 27 15:02:26 2018 +0000
+++ b/sys/netinet/ip_reass.c    Thu Sep 27 15:07:34 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_reass.c,v 1.11.8.3 2018/04/09 16:40:07 martin Exp $ */
+/*     $NetBSD: ip_reass.c,v 1.11.8.4 2018/09/27 15:07:34 martin Exp $ */
 
 /*
  * Copyright (c) 1982, 1986, 1988, 1993
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.11.8.3 2018/04/09 16:40:07 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.11.8.4 2018/09/27 15:07:34 martin 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 a785aaa14b3e -r c223658e792e sys/netinet6/frag6.c
--- a/sys/netinet6/frag6.c      Thu Sep 27 15:02:26 2018 +0000
+++ b/sys/netinet6/frag6.c      Thu Sep 27 15:07:34 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: frag6.c,v 1.60.6.4 2018/04/05 14:33:41 martin Exp $    */
+/*     $NetBSD: frag6.c,v 1.60.6.5 2018/09/27 15:07:35 martin 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.60.6.4 2018/04/05 14:33:41 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.60.6.5 2018/09/27 15:07:35 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -124,6 +124,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;
@@ -205,6 +206,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.
@@ -241,8 +249,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