Module Name: src Committed By: martin Date: Thu Sep 27 15:07:35 UTC 2018
Modified Files: src/sys/netinet [netbsd-8]: ip_reass.c src/sys/netinet6 [netbsd-8]: frag6.c Log Message: 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). To generate a diff of this commit: cvs rdiff -u -r1.11.8.3 -r1.11.8.4 src/sys/netinet/ip_reass.c cvs rdiff -u -r1.60.6.4 -r1.60.6.5 src/sys/netinet6/frag6.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet/ip_reass.c diff -u src/sys/netinet/ip_reass.c:1.11.8.3 src/sys/netinet/ip_reass.c:1.11.8.4 --- src/sys/netinet/ip_reass.c:1.11.8.3 Mon Apr 9 16:40:07 2018 +++ src/sys/netinet/ip_reass.c Thu Sep 27 15:07:34 2018 @@ -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 @@ typedef struct ipfr_queue { 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 @@ ip_reass(ipfr_qent_t *ipqe, ipfr_queue_t 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 @@ ip_reass(ipfr_qent_t *ipqe, ipfr_queue_t 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 @@ ip_reass_packet(struct mbuf **m0, struct 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 @@ ip_reass_packet(struct mbuf **m0, struct 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; + } } /* Index: src/sys/netinet6/frag6.c diff -u src/sys/netinet6/frag6.c:1.60.6.4 src/sys/netinet6/frag6.c:1.60.6.5 --- src/sys/netinet6/frag6.c:1.60.6.4 Thu Apr 5 14:33:41 2018 +++ src/sys/netinet6/frag6.c Thu Sep 27 15:07:35 2018 @@ -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 @@ frag6_input(struct mbuf **mp, int *offp, 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 @@ frag6_input(struct mbuf **mp, int *offp, 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 @@ frag6_input(struct mbuf **mp, int *offp, 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; } /*