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).
This commit is contained in:
parent
82b545a2e8
commit
fbb9ed35f8
|
@ -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 @@ 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 *fp, const u_int hash)
|
|||
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, const u_int hash)
|
|||
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 ip *ip)
|
|||
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 ip *ip)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 {
|
|||
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 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
|
|||
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 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
|
|||
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 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
|
|||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue