]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect/content: Consider distance in validation
authorJeff Lucovsky <jeff@lucovsky.org>
Sat, 13 Feb 2021 15:41:09 +0000 (10:41 -0500)
committerVictor Julien <vjulien@oisf.net>
Thu, 10 Nov 2022 13:42:44 +0000 (15:42 +0200)
Ticket: 2982

This commit validates that the content usage in a rule will not exceed
the dsize value.

Values of distance that cause the right edge to be exceeded are
considered an error and the signature will be rejected.

src/detect-content.c
src/detect-content.h
src/detect-dsize.c
src/detect-dsize.h

index f5229ab7bc2683859db35e1d8a0a22d58e05c27c..e3dbd853791c16b00075967f1ff31aa057327de9 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2019 Open Information Security Foundation
+/* Copyright (C) 2007-2022 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -392,9 +392,78 @@ void DetectContentFree(DetectEngineCtx *de_ctx, void *ptr)
     SCReturn;
 }
 
+/*
+ *  \brief Determine the size needed to accommodate the content
+ *  elements of a signature
+ *  \param s signature to get dsize value from
+ *  \param max_size Maximum buffer/data size allowed.
+ *  \param list signature match list.
+ *  \param len Maximum length required
+ *  \param offset Maximum offset encounted
+ *
+ *  Note that negated content does not contribute to the maximum
+ *  required size value. However, each negated content's values
+ *  must not exceed the size value.
+ *
+ *  Values from negated content blocks are used to determine if the
+ *  negated content block requires a value that exceeds "max_size". The
+ *  distance and within values from negated content blocks are added to
+ *  the running total of required content size to see if the max_size
+ *  would be exceeded.
+ *
+ *  - Non-negated content contributes to the required size (content length, distance)
+ *  - Negated content values are checked but not accumulated for the required size.
+ */
+void SigParseRequiredContentSize(
+        const Signature *s, const int max_size, int list, int *len, int *offset)
+{
+    if (list > (int)s->init_data->smlists_array_size) {
+        return;
+    }
+
+    SigMatch *sm = s->init_data->smlists[list];
+    int max_offset = 0, total_len = 0;
+    bool first = true;
+    for (; sm != NULL; sm = sm->next) {
+        if (sm->type != DETECT_CONTENT || sm->ctx == NULL) {
+            continue;
+        }
+
+        DetectContentData *cd = (DetectContentData *)sm->ctx;
+        SCLogDebug("content_len %d; negated: %s; distance: %d, offset: %d, depth: %d",
+                cd->content_len, cd->flags & DETECT_CONTENT_NEGATED ? "yes" : "no", cd->distance,
+                cd->offset, cd->depth);
+
+        if (!first) {
+            /* only count content with relative modifiers */
+            if (!((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN)))
+                continue;
+
+            if (cd->flags & DETECT_CONTENT_NEGATED) {
+                /* Check if distance/within cause max to be exceeded */
+                int check = total_len + cd->distance + cd->within;
+                if (max_size < check) {
+                    *len = check;
+                    return;
+                }
+
+                continue;
+            }
+        }
+        SCLogDebug("content_len %d; distance: %d, offset: %d, depth: %d", cd->content_len,
+                cd->distance, cd->offset, cd->depth);
+        total_len += cd->content_len + cd->distance;
+        max_offset = MAX(max_offset, cd->offset);
+        first = false;
+    }
+
+    *len = total_len;
+    *offset = max_offset;
+}
+
 /**
- *  \retval 1 valid
- *  \retval 0 invalid
+ *  \retval true valid
+ *  \retval false invalid
  */
 bool DetectContentPMATCHValidateCallback(const Signature *s)
 {
@@ -409,25 +478,17 @@ bool DetectContentPMATCHValidateCallback(const Signature *s)
 
     uint32_t max_right_edge = (uint32_t)max_right_edge_i;
 
-    const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH];
-    for ( ; sm != NULL; sm = sm->next) {
-        if (sm->type != DETECT_CONTENT)
-            continue;
-        const DetectContentData *cd = (const DetectContentData *)sm->ctx;
-        uint32_t right_edge = cd->content_len + cd->offset;
-        if (cd->content_len > max_right_edge) {
-            SCLogError(SC_ERR_INVALID_SIGNATURE,
-                    "signature can't match as content length %u is bigger than dsize %u.",
-                    cd->content_len, max_right_edge);
-            return false;
-        }
-        if (right_edge > max_right_edge) {
+    int min_dsize_required = SigParseMaxRequiredDsize(s);
+    if (min_dsize_required >= 0) {
+        SCLogDebug("min_dsize %d; max_right_edge %d", min_dsize_required, max_right_edge);
+        if ((uint32_t)min_dsize_required > max_right_edge) {
             SCLogError(SC_ERR_INVALID_SIGNATURE,
-                    "signature can't match as content length %u with offset %u (=%u) is bigger than dsize %u.",
-                    cd->content_len, cd->offset, right_edge, max_right_edge);
+                    "signature can't match as required content length %d exceeds dsize value %d",
+                    min_dsize_required, max_right_edge);
             return false;
         }
     }
+
     return true;
 }
 
@@ -2636,7 +2697,7 @@ static int SigTest42TestNegatedContent(void)
 /**
  * \test A negative test that checks that the content string doesn't contain
  *       the negated content within the specified depth, and also after the
- *       specified offset. Since the content is there, the match fails. 
+ *       specified offset. Since the content is there, the match fails.
  *
  *       Match is at offset:23, depth:34
  */
index 5959d6473fca343b331b9bb0370ee127312b993b..a99dc78462b90b9c9573dcbdee06f5f6bf338257 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2010 Open Information Security Foundation
+/* Copyright (C) 2007-2022 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -124,5 +124,7 @@ bool DetectContentPMATCHValidateCallback(const Signature *s);
 void DetectContentPropagateLimits(Signature *s);
 
 void DetectContentPatternPrettyPrint(const DetectContentData *cd, char *str, size_t str_len);
+void SigParseRequiredContentSize(
+        const Signature *s, const int max, int list, int *len, int *offset);
 
 #endif /* __DETECT_CONTENT_H__ */
index b86140e5c489ade92c3343525a55d3f3f1479de2..c0603c67eea66b550f1e283fdd02d810ca6a10e2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2021 Open Information Security Foundation
+/* Copyright (C) 2007-2022 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -289,6 +289,48 @@ void SigParseSetDsizePair(Signature *s)
     }
 }
 
+/**
+ *  \brief Determine the required dsize for the signature
+ *  \param s signature to get dsize value from
+ *
+ *  Note that negated content does not contribute to the maximum
+ *  required dsize value. However, each negated content's values
+ *  must not exceed the dsize value. See SigParseRequiredContentSize.
+ *
+ * \retval -1 Signature doesn't have a dsize keyword
+ * \retval >= 0 Dsize value required to not exclude content matches
+ */
+int SigParseMaxRequiredDsize(const Signature *s)
+{
+    SCEnter();
+
+    if (!(s->flags & SIG_FLAG_DSIZE)) {
+        SCReturnInt(-1);
+    }
+
+    const int dsize = SigParseGetMaxDsize(s);
+    if (dsize < 0) {
+        /* nothing to do */
+        SCReturnInt(-1);
+    }
+
+    int total_length, offset;
+    SigParseRequiredContentSize(s, dsize, DETECT_SM_LIST_PMATCH, &total_length, &offset);
+    SCLogDebug("dsize: %d  len: %d; offset: %d [%s]", dsize, total_length, offset, s->sig_str);
+
+    if (total_length > dsize) {
+        SCLogDebug("required_dsize: %d exceeds dsize: %d", total_length, dsize);
+        return total_length;
+    }
+
+    if ((total_length + offset) > dsize) {
+        SCLogDebug("length + offset: %d exceeds dsize: %d", total_length + offset, dsize);
+        return total_length + offset;
+    }
+
+    SCReturnInt(-1);
+}
+
 /**
  *  \brief Apply dsize as depth to content matches in the rule
  *  \param s signature to get dsize value from
index 71b16484e23ea351b1d7c209c141c62b261d80a0..c262a31186feea8f2806970e91d2a032bcbdc600 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2010 Open Information Security Foundation
+/* Copyright (C) 2007-2022 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -29,6 +29,7 @@
 /* prototypes */
 void DetectDsizeRegister (void);
 
+int SigParseMaxRequiredDsize(const Signature *s);
 int SigParseGetMaxDsize(const Signature *s);
 void SigParseSetDsizePair(Signature *s);
 void SigParseApplyDsizeToContent(Signature *s);