]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
defrag: fix check for complete packet
authorJason Ish <jason.ish@oisf.net>
Fri, 12 Jan 2024 17:09:59 +0000 (11:09 -0600)
committerVictor Julien <vjulien@oisf.net>
Sun, 21 Apr 2024 07:37:13 +0000 (09:37 +0200)
The list of fragments may still contain overlaps, so adding up the
fragment lengths is flawed. Instead track the largest size of
contiguous data that can be re-assembled.

Bug: #6675

src/defrag.c

index 594c9d0dd942d8e128909f63d414d11190c5be8c..fede1b927a0cebd3552b141fceb0013ad528a8d9 100644 (file)
@@ -256,7 +256,8 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
             goto done;
         }
         else {
-            len += frag->data_len;
+            /* Update the packet length to the largest known data offset. */
+            len = MAX(len, frag->offset + frag->data_len);
         }
     }
 
@@ -414,7 +415,7 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
                 goto done;
             }
             else {
-                len += frag->data_len;
+                len = MAX(len, frag->offset + frag->data_len);
             }
         }
     }
@@ -3057,6 +3058,116 @@ static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test(void)
     PASS;
 }
 
+/**
+ * Reassembly should fail.
+ *
+ * |0       |8       |16      |24      |32      |40      |48      |
+ * |========|========|========|========|========|========|========|
+ * |        |        |AABBCCDD|AABBDDCC|        |        |        |
+ * |        |        |        |        |        |AACCBBDD|        |
+ * |        |AACCDDBB|AADDBBCC|        |        |        |        |
+ * |ZZZZZZZZ|        |        |        |        |        |        |
+ * |        |        |        |        |        |        |DDCCBBAA|
+ */
+static int DefragBsdMissingFragmentIpv4Test(void)
+{
+    DefragInit();
+    default_policy = DEFRAG_POLICY_BSD;
+    Packet *packets[5];
+
+    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
+            &packets[0], IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16));
+
+    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
+            &packets[1], IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8));
+
+    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
+            &packets[2], IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16));
+
+    /* ICMP header. */
+    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
+            &packets[3], IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8));
+
+    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
+            &packets[4], IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8));
+
+    Packet *r = Defrag(NULL, NULL, packets[0]);
+    FAIL_IF_NOT_NULL(r);
+
+    r = Defrag(NULL, NULL, packets[1]);
+    FAIL_IF_NOT_NULL(r);
+
+    r = Defrag(NULL, NULL, packets[2]);
+    FAIL_IF_NOT_NULL(r);
+
+    r = Defrag(NULL, NULL, packets[3]);
+    FAIL_IF_NOT_NULL(r);
+
+    r = Defrag(NULL, NULL, packets[4]);
+    FAIL_IF_NOT_NULL(r);
+
+#if 0
+    PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
+#endif
+
+    for (int i = 0; i < 5; i++) {
+        SCFree(packets[i]);
+    }
+
+    DefragDestroy();
+
+    PASS;
+}
+
+static int DefragBsdMissingFragmentIpv6Test(void)
+{
+    DefragInit();
+    default_policy = DEFRAG_POLICY_BSD;
+    Packet *packets[5];
+
+    packets[0] = BuildIpv6TestPacketWithContent(
+            IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
+
+    packets[1] =
+            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
+
+    packets[2] = BuildIpv6TestPacketWithContent(
+            IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
+
+    /* ICMP header. */
+    packets[3] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
+
+    packets[4] =
+            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
+
+    Packet *r = Defrag(NULL, NULL, packets[0]);
+    FAIL_IF_NOT_NULL(r);
+
+    r = Defrag(NULL, NULL, packets[1]);
+    FAIL_IF_NOT_NULL(r);
+
+    r = Defrag(NULL, NULL, packets[2]);
+    FAIL_IF_NOT_NULL(r);
+
+    r = Defrag(NULL, NULL, packets[3]);
+    FAIL_IF_NOT_NULL(r);
+
+    r = Defrag(NULL, NULL, packets[4]);
+    FAIL_IF_NOT_NULL(r);
+
+#if 0
+    PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
+#endif
+
+    for (int i = 0; i < 5; i++) {
+        SCFree(packets[i]);
+    }
+
+    DefragDestroy();
+
+    PASS;
+}
+
 #endif /* UNITTESTS */
 
 void DefragRegisterTests(void)
@@ -3107,5 +3218,7 @@ void DefragRegisterTests(void)
             DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2);
     UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2",
             DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2);
+    UtRegisterTest("DefragBsdMissingFragmentIpv4Test", DefragBsdMissingFragmentIpv4Test);
+    UtRegisterTest("DefragBsdMissingFragmentIpv6Test", DefragBsdMissingFragmentIpv6Test);
 #endif /* UNITTESTS */
 }