summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2012-01-10 17:09:03 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2012-01-10 17:09:03 +0000
commit30934d0bf3ba08c4af68407d9c14505a351b67dc (patch)
tree53f75a30f77f06c6a3a20bd649acf33df463c159 /sys
parent819a8c17b408d72423a4265321955fa34c3bac53 (diff)
Implement RFC 5722 and drop all IPv6 fragments that belong to a
packet with overlapping fragments. ok henning@
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet6/frag6.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c
index 0293f673a0c..779740399ed 100644
--- a/sys/netinet6/frag6.c
+++ b/sys/netinet6/frag6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: frag6.c,v 1.39 2012/01/10 12:50:32 bluhm Exp $ */
+/* $OpenBSD: frag6.c,v 1.40 2012/01/10 17:09:02 bluhm Exp $ */
/* $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $ */
/*
@@ -284,8 +284,15 @@ 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;
+ } else if (LIST_EMPTY(&q6->ip6q_asfrag)) {
+ /*
+ * Overlapping fragments have been detected. Do not
+ * reassemble packet but also drop future fragments.
+ * This will be done for this ident/src/dst combination
+ * until fragment queue timeout.
+ */
+ goto dropfrag;
}
/*
@@ -402,11 +409,10 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
break;
/*
- * If the incoming fragment overlaps some existing fragments in
- * the reassembly queue, drop it, since it is dangerous to override
- * existing fragments from a security point of view.
- * We don't know which fragment is the bad guy - here we trust
- * fragment that came in earlier, with no real reason.
+ * RFC5722: When reassembling an IPv6 datagram, if one or more its
+ * constituent fragments is determined to be an overlapping fragment,
+ * the entire datagram (and any constituent fragments, including those
+ * not yet received) MUST be silently discarded.
*/
if (paf6 != LIST_END(&q6->ip6q_asfrag)) {
i = (paf6->ip6af_off + paf6->ip6af_frglen) - ip6af->ip6af_off;
@@ -417,7 +423,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
i, ip6_sprintf(&q6->ip6q_src));
#endif
free(ip6af, M_FTABLE);
- goto dropfrag;
+ goto flushfrags;
}
}
if (af6 != LIST_END(&q6->ip6q_asfrag)) {
@@ -429,7 +435,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
i, ip6_sprintf(&q6->ip6q_src));
#endif
free(ip6af, M_FTABLE);
- goto dropfrag;
+ goto flushfrags;
}
}
@@ -535,6 +541,17 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
IP6Q_UNLOCK();
return nxt;
+ flushfrags:
+ while ((af6 = LIST_FIRST(&q6->ip6q_asfrag)) !=
+ LIST_END(&q6->ip6q_asfrag)) {
+ LIST_REMOVE(af6, ip6af_list);
+ m_freem(IP6_REASS_MBUF(af6));
+ free(af6, M_FTABLE);
+ }
+ ip6stat.ip6s_fragdropped += q6->ip6q_nfrag;
+ frag6_nfrags -= q6->ip6q_nfrag;
+ q6->ip6q_nfrag = 0;
+
dropfrag:
in6_ifstat_inc(dstifp, ifs6_reass_fail);
ip6stat.ip6s_fragdropped++;