Hi,

Implement RFC 5722 and drop all IPv6 fragments that belong to a
packet with overlapping fragments.

ok?

bluhm


Index: netinet6/frag6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/frag6.c,v
retrieving revision 1.39
diff -u -p -r1.39 frag6.c
--- netinet6/frag6.c    10 Jan 2012 12:50:32 -0000      1.39
+++ netinet6/frag6.c    10 Jan 2012 16:15:46 -0000
@@ -284,8 +284,15 @@ 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_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,
                        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,
                            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,
                            i, ip6_sprintf(&q6->ip6q_src));
 #endif
                        free(ip6af, M_FTABLE);
-                       goto dropfrag;
+                       goto flushfrags;
                }
        }
 
@@ -534,6 +540,17 @@ frag6_input(struct mbuf **mp, int *offp,
 
        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);

Reply via email to