]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
stream: add option to match on overlapping data
authorVictor Julien <victor@inliniac.net>
Thu, 11 Oct 2012 19:02:56 +0000 (21:02 +0200)
committerVictor Julien <victor@inliniac.net>
Mon, 15 Oct 2012 11:46:32 +0000 (13:46 +0200)
Set event on overlapping data segments that have different data.

Add stream-events option stream-event:reassembly_overlap_different_data and
add an example rule.

Issue 603.

rules/stream-events.rules
src/decode-events.h
src/detect-engine-event.c
src/detect-engine-event.h
src/stream-tcp-reassemble.c
src/stream-tcp.h

index 5d6f913b2efe6c5f55f521538d276c1c17433243..447885d8b4859047c32642c10d7d7ebe2164f04f 100644 (file)
@@ -56,5 +56,6 @@ alert tcp any any -> any any (msg:"SURICATA STREAM SHUTDOWN RST invalid ack"; st
 #alert tcp any any -> any any (msg:"SURICATA STREAM reassembly segment before base seq"; stream-event:reassembly_segment_before_base_seq; sid:2210047; rev:1;)
 # Sequence gap: missing data in the reassembly engine. Usually due to packet loss. Will be very noisy on a overloaded link / sensor.
 #alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; sid:2210048; rev:1;)
-# next sid 2210050
+alert tcp any any -> any any (msg:"SURICATA STREAM reassembly overlap with different data"; stream-event:reassembly_overlap_different_data; sid:2210050; rev:1;)
+# next sid 2210051
 
index 89f8422444dc12d4597529e67cd43a5fd203788c..2a1bb69f5c10e1ce94500112e46f300a653a67ec 100644 (file)
@@ -183,6 +183,8 @@ enum {
 
     STREAM_REASSEMBLY_SEQ_GAP,
 
+    STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA,
+
     /* SCTP EVENTS */
     SCTP_PKT_TOO_SMALL,              /**< sctp packet smaller than minimum size */
 
index d276313de8f583536bef455a1ce09effae7f84f4..3df86518372a0e530f77add0ad877ad922f4926e 100644 (file)
@@ -34,6 +34,9 @@
 
 #include "util-debug.h"
 
+#include "stream-tcp.h"
+
+
 /* Need to get the DEvents[] array */
 #define DETECT_EVENTS
 
@@ -172,6 +175,10 @@ DetectEngineEventData *DetectEngineEventParse (char *rawstr)
         goto error;
 
     de->event = DEvents[i].code;
+
+    if (de->event == STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA) {
+        StreamTcpReassembleConfigEnableOverlapCheck();
+    }
     return de;
 
 error:
index f8034f96f099500209c76c26c075cf74b8b7c999..b16d2138250176846ac1e01ea13f2b029d2ca2ea 100644 (file)
@@ -171,6 +171,7 @@ struct DetectEngineEvents_ {
     { "stream.reassembly_segment_before_base_seq", STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ, },
     { "stream.reassembly_no_segment", STREAM_REASSEMBLY_NO_SEGMENT, },
     { "stream.reassembly_seq_gap", STREAM_REASSEMBLY_SEQ_GAP, },
+    { "stream.reassembly_overlap_different_data", STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, },
     { NULL, 0 },
 };
 #endif /* DETECT_EVENTS */
index 78ae7b052e20057acde5f0f981fc6e992c3c3d5c..c267692fbee35da3f5df9c6ca6270f4fef722491 100644 (file)
@@ -92,6 +92,7 @@ static uint64_t segment_pool_cnt = 0;
 #endif
 /* index to the right pool for all packet sizes. */
 static uint16_t segment_pool_idx[65536]; /* O(1) lookups of the pool */
+static int check_overlap_different_data = 0;
 
 /* Memory use counter */
 SC_ATOMIC_DECLARE(uint64_t, ra_memuse);
@@ -108,6 +109,12 @@ void StreamTcpSegmentDataCopy(TcpSegment *, TcpSegment *);
 TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *, uint16_t);
 void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t);
 void StreamTcpReassemblePseudoPacketCreate(TcpStream *, Packet *, PacketQueue *);
+static int StreamTcpSegmentDataCompare(TcpSegment *dst_seg, TcpSegment *src_seg,
+                                 uint32_t start_point, uint16_t len);
+
+void StreamTcpReassembleConfigEnableOverlapCheck(void) {
+    check_overlap_different_data = 1;
+}
 
 /**
  *  \brief  Function to Increment the memory usage counter for the TCP reassembly
@@ -1067,6 +1074,12 @@ static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThr
             }
         }
 
+        if (check_overlap_different_data &&
+                !StreamTcpSegmentDataCompare(seg, list_seg, list_seg->seq, overlap)) {
+            /* interesting, overlap with different data */
+            StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
+        }
+
         if (StreamTcpInlineMode()) {
             if (StreamTcpInlineSegmentCompare(seg, list_seg) != 0) {
                 StreamTcpInlineSegmentReplacePacket(p, list_seg);
@@ -1259,6 +1272,12 @@ static int HandleSegmentStartsAtSameListSegment(ThreadVars *tv, TcpReassemblyThr
             }
         }
 
+        if (check_overlap_different_data &&
+                !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) {
+            /* interesting, overlap with different data */
+            StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
+        }
+
         if (StreamTcpInlineMode()) {
             if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) {
                 StreamTcpInlineSegmentReplacePacket(p, list_seg);
@@ -1460,6 +1479,12 @@ static int HandleSegmentStartsAfterListSegment(ThreadVars *tv, TcpReassemblyThre
             }
         }
 
+        if (check_overlap_different_data &&
+                !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) {
+            /* interesting, overlap with different data */
+            StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
+        }
+
         if (StreamTcpInlineMode()) {
             if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) {
                 StreamTcpInlineSegmentReplacePacket(p, list_seg);
@@ -3454,7 +3479,7 @@ void StreamTcpSegmentDataReplace(TcpSegment *dst_seg, TcpSegment *src_seg,
 
     if (SEQ_GT(start_point, dst_seg->seq)) {
         dst_pos = start_point - dst_seg->seq;
-    } else if (SEQ_LT(dst_seg->seq, start_point)) {
+    } else if (SEQ_LT(start_point, dst_seg->seq)) {
         dst_pos = dst_seg->seq - start_point;
     }
 
@@ -3480,6 +3505,60 @@ void StreamTcpSegmentDataReplace(TcpSegment *dst_seg, TcpSegment *src_seg,
             " dst_pos %"PRIu16, len, src_pos, dst_pos);
 }
 
+/**
+ *  \brief  Function to compare the data from a specific point up to given length.
+ *
+ *  \param  dst_seg     Destination segment to compare the data
+ *  \param  src_seg     Source segment of which data is to be compared to destination
+ *  \param  start_point Starting point to compare the data onwards
+ *  \param  len         Length up to which data is need to be compared
+ *
+ *  \retval 1 same
+ *  \retval 0 different
+ */
+static int StreamTcpSegmentDataCompare(TcpSegment *dst_seg, TcpSegment *src_seg,
+                                 uint32_t start_point, uint16_t len)
+{
+    uint32_t seq;
+    uint16_t src_pos = 0;
+    uint16_t dst_pos = 0;
+
+    SCLogDebug("start_point %u dst_seg %u src_seg %u", start_point, dst_seg->seq, src_seg->seq);
+
+    if (SEQ_GT(start_point, dst_seg->seq)) {
+        SCLogDebug("start_point %u > dst %u", start_point, dst_seg->seq);
+        dst_pos = start_point - dst_seg->seq;
+    } else if (SEQ_LT(start_point, dst_seg->seq)) {
+        SCLogDebug("start_point %u < dst %u", start_point, dst_seg->seq);
+        dst_pos = dst_seg->seq - start_point;
+    }
+
+    if (SCLogDebugEnabled()) {
+        BUG_ON(((len + dst_pos) - 1) > dst_seg->payload_len);
+    } else {
+        if (((len + dst_pos) - 1) > dst_seg->payload_len)
+            return 1;
+    }
+
+    src_pos = (uint16_t)(start_point - src_seg->seq);
+
+    SCLogDebug("Comparing data from dst_pos %"PRIu16", src_pos %u", dst_pos, src_pos);
+
+    for (seq = start_point; SEQ_LT(seq, (start_point + len)) &&
+            src_pos < src_seg->payload_len && dst_pos < dst_seg->payload_len;
+            seq++, dst_pos++, src_pos++)
+    {
+        if (dst_seg->payload[dst_pos] != src_seg->payload[src_pos]) {
+            SCLogDebug("data is different %02x != %02x, dst_pos %u, src_pos %u", dst_seg->payload[dst_pos], src_seg->payload[src_pos], dst_pos, src_pos);
+            return 0;
+        }
+    }
+
+    SCLogDebug("Compared data of size %"PRIu16" up to src_pos %"PRIu16
+            " dst_pos %"PRIu16, len, src_pos, dst_pos);
+    return 1;
+}
+
 /**
  *  \brief  Function to copy the data from src_seg to dst_seg.
  *
index 811fdcc8623a1d170e1e89929048aafd79780476..d346e2adc6c91d7676b63f5eb9dc7865d8dcc960 100644 (file)
@@ -57,6 +57,8 @@ typedef struct TcpStreamCnf_ {
     uint16_t reassembly_toserver_chunk_size;
     uint16_t reassembly_toclient_chunk_size;
 
+    int check_overlap_different_data;
+
     /** reassembly -- inline mode
      *
      *  sliding window size for raw stream reassembly
@@ -115,6 +117,7 @@ Packet *StreamTcpPseudoSetup(Packet *, uint8_t *, uint32_t);
 int StreamTcpSegmentForEach(Packet *p, uint8_t flag,
                         StreamSegmentCallback CallbackFunc,
                         void *data);
+void StreamTcpReassembleConfigEnableOverlapCheck(void);
 
 /** ------- Inline functions: ------ */