]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
defrag: check minimum size of reassembled packet
authorJason Ish <jason.ish@gmail.com>
Tue, 17 Sep 2019 10:08:15 +0000 (12:08 +0200)
committerVictor Julien <victor@inliniac.net>
Mon, 23 Sep 2019 13:42:13 +0000 (15:42 +0200)
Before re-assembling, check that the first fragment is large
enough to contain the IPv4 or IPv6 header to prevent
an out of bounds read (IPv4) or write (IPv6).

Reported-by: Sirko Höer -- Code Intelligence for DCSO.
Bug #3171.

src/defrag.c

index 95c12422fe4220c59413914e953b92cccda30789..d38843838501a50f1f016438d367f8f23c9f0264 100644 (file)
@@ -260,11 +260,23 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
         return NULL;
     }
 
+    /* Check that we have the first fragment and its of a valid size. */
+    Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
+    if (first == NULL) {
+        goto done;
+    } else if (first->offset != 0) {
+        /* Still waiting for the first fragment. */
+        goto done;
+    } else if (first->len < sizeof(IPV4Hdr)) {
+        /* First fragment isn't enough for an IPv6 header. */
+        goto error_remove_tracker;
+    }
+
     /* Check that we have all the data. Relies on the fact that
      * fragments are inserted if frag_offset order. */
     Frag *frag = NULL;
-    int len = 0;
-    RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
+    size_t len = 0;
+    RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
         if (frag->offset > len) {
             /* This fragment starts after the end of the previous
              * fragment.  We have a hole. */
@@ -374,10 +386,21 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
     if (!tracker->seen_last)
         return NULL;
 
+    /* Check that we have the first fragment and its of a valid size. */
+    Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
+    if (first == NULL) {
+        goto done;
+    } else if (first->offset != 0) {
+        /* Still waiting for the first fragment. */
+        goto done;
+    } else if (first->len < sizeof(IPV6Hdr)) {
+        /* First fragment isn't enough for an IPv6 header. */
+        goto error_remove_tracker;
+    }
+
     /* Check that we have all the data. Relies on the fact that
      * fragments are inserted if frag_offset order. */
-    int len = 0;
-    Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
+    size_t len = 0;
     Frag *frag = NULL;
     RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
         if (frag->skip) {