]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect/content: refactor limit propagation
authorVictor Julien <vjulien@oisf.net>
Sun, 19 Mar 2023 15:39:32 +0000 (16:39 +0100)
committerVictor Julien <vjulien@oisf.net>
Thu, 23 Mar 2023 10:33:48 +0000 (11:33 +0100)
src/detect-content.c

index e3d1cb478e5bf0b50bfb639d4eca85d37d67d37d..d22fbc8f89b3f8f27f7c5f792e24209bd601504a 100644 (file)
@@ -501,194 +501,190 @@ bool DetectContentPMATCHValidateCallback(const Signature *s)
  *  cannot set a depth, but we can set an offset of 'offset:1;'. This will
  *  make the mpm a bit more precise.
  */
-void DetectContentPropagateLimits(Signature *s)
+static void PropagateLimits(Signature *s, SigMatch *sm_head)
 {
 #define VALIDATE(e)                                                                                \
     if (!(e)) {                                                                                    \
         return;                                                                                    \
     }
-    BUG_ON(s == NULL || s->init_data == NULL);
-
-    uint32_t list = 0;
-    for (list = 0; list < s->init_data->smlists_array_size; list++) {
-        uint16_t offset = 0;
-        uint16_t offset_plus_pat = 0;
-        uint16_t depth = 0;
-        bool has_active_depth_chain = false;
-
-        bool has_depth = false;
-        bool has_ends_with = false;
-        uint16_t ends_with_depth = 0;
-
-        SigMatch *sm = s->init_data->smlists[list];
-        for ( ; sm != NULL; sm = sm->next) {
-            switch (sm->type) {
-                case DETECT_CONTENT: {
-                    DetectContentData *cd = (DetectContentData *)sm->ctx;
-                    if ((cd->flags & (DETECT_CONTENT_DEPTH|DETECT_CONTENT_OFFSET|DETECT_CONTENT_WITHIN|DETECT_CONTENT_DISTANCE)) == 0) {
-                        offset = depth = 0;
-                        offset_plus_pat = cd->content_len;
-                        SCLogDebug("reset");
-                        has_active_depth_chain = false;
-                        continue;
-                    }
-                    if (cd->flags & DETECT_CONTENT_NEGATED) {
-                        offset = depth = 0;
-                        offset_plus_pat = 0;
-                        SCLogDebug("reset because of negation");
-                        has_active_depth_chain = false;
-                        continue;
-                    }
+    uint16_t offset = 0;
+    uint16_t offset_plus_pat = 0;
+    uint16_t depth = 0;
+    bool has_active_depth_chain = false;
+
+    bool has_depth = false;
+    bool has_ends_with = false;
+    uint16_t ends_with_depth = 0;
+
+    for (SigMatch *sm = sm_head; sm != NULL; sm = sm->next) {
+        switch (sm->type) {
+            case DETECT_CONTENT: {
+                DetectContentData *cd = (DetectContentData *)sm->ctx;
+                if ((cd->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET |
+                                         DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) == 0) {
+                    offset = depth = 0;
+                    offset_plus_pat = cd->content_len;
+                    SCLogDebug("reset");
+                    has_active_depth_chain = false;
+                    continue;
+                }
+                if (cd->flags & DETECT_CONTENT_NEGATED) {
+                    offset = depth = 0;
+                    offset_plus_pat = 0;
+                    SCLogDebug("reset because of negation");
+                    has_active_depth_chain = false;
+                    continue;
+                }
 
-                    if (cd->depth) {
-                        has_depth = true;
-                        has_active_depth_chain = true;
-                    }
+                if (cd->depth) {
+                    has_depth = true;
+                    has_active_depth_chain = true;
+                }
 
-                    SCLogDebug("sm %p depth %u offset %u distance %d within %d", sm, cd->depth, cd->offset, cd->distance, cd->within);
-                    SCLogDebug("stored: offset %u depth %u offset_plus_pat %u", offset, depth, offset_plus_pat);
+                SCLogDebug("sm %p depth %u offset %u distance %d within %d", sm, cd->depth,
+                        cd->offset, cd->distance, cd->within);
+                SCLogDebug("stored: offset %u depth %u offset_plus_pat %u", offset, depth,
+                        offset_plus_pat);
 
-                    if ((cd->flags & (DETECT_DEPTH | DETECT_CONTENT_WITHIN)) == 0) {
-                        if (depth)
-                            SCLogDebug("no within, reset depth");
-                        depth = 0;
-                        has_active_depth_chain = false;
-                    }
-                    if ((cd->flags & DETECT_CONTENT_DISTANCE) == 0) {
-                        if (offset_plus_pat)
-                            SCLogDebug("no distance, reset offset_plus_pat & offset");
-                        offset_plus_pat = offset = 0;
-                    }
+                if ((cd->flags & (DETECT_DEPTH | DETECT_CONTENT_WITHIN)) == 0) {
+                    if (depth)
+                        SCLogDebug("no within, reset depth");
+                    depth = 0;
+                    has_active_depth_chain = false;
+                }
+                if ((cd->flags & DETECT_CONTENT_DISTANCE) == 0) {
+                    if (offset_plus_pat)
+                        SCLogDebug("no distance, reset offset_plus_pat & offset");
+                    offset_plus_pat = offset = 0;
+                }
 
-                    SCLogDebug("stored: offset %u depth %u offset_plus_pat %u "
-                               "has_active_depth_chain %s",
-                            offset, depth, offset_plus_pat,
-                            has_active_depth_chain ? "true" : "false");
-                    if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) {
-                        VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX);
-                        offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
-                        SCLogDebug("updated content to have offset %u", cd->offset);
-                    }
-                    if (has_active_depth_chain) {
-                        if (offset_plus_pat && cd->flags & DETECT_CONTENT_WITHIN &&
-                                cd->within >= 0) {
-                            if (depth && depth > offset_plus_pat) {
-                                int32_t dist = 0;
-                                if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance > 0) {
-                                    dist = cd->distance;
-                                    SCLogDebug("distance to add: %u. depth + dist %u", dist,
-                                            depth + dist);
+                SCLogDebug("stored: offset %u depth %u offset_plus_pat %u "
+                           "has_active_depth_chain %s",
+                        offset, depth, offset_plus_pat, has_active_depth_chain ? "true" : "false");
+                if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) {
+                    VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX);
+                    offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
+                    SCLogDebug("updated content to have offset %u", cd->offset);
+                }
+                if (has_active_depth_chain) {
+                    if (offset_plus_pat && cd->flags & DETECT_CONTENT_WITHIN && cd->within >= 0) {
+                        if (depth && depth > offset_plus_pat) {
+                            int32_t dist = 0;
+                            if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance > 0) {
+                                dist = cd->distance;
+                                SCLogDebug(
+                                        "distance to add: %u. depth + dist %u", dist, depth + dist);
+                            }
+                            SCLogDebug("depth %u + cd->within %u", depth, cd->within);
+                            VALIDATE(depth + cd->within + dist >= 0 &&
+                                     depth + cd->within + dist <= UINT16_MAX);
+                            depth = cd->depth = (uint16_t)(depth + cd->within + dist);
+                        } else {
+                            SCLogDebug("offset %u + cd->within %u", offset, cd->within);
+                            VALIDATE(depth + cd->within >= 0 && depth + cd->within <= UINT16_MAX);
+                            depth = cd->depth = (uint16_t)(offset + cd->within);
+                        }
+                        SCLogDebug("updated content to have depth %u", cd->depth);
+                    } else {
+                        if (cd->depth == 0 && depth != 0) {
+                            if (cd->within > 0) {
+                                SCLogDebug("within %d distance %d", cd->within, cd->distance);
+                                if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) {
+                                    VALIDATE(offset_plus_pat + cd->distance >= 0 &&
+                                             offset_plus_pat + cd->distance <= UINT16_MAX);
+                                    cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
+                                    SCLogDebug("updated content to have offset %u", cd->offset);
                                 }
-                                SCLogDebug("depth %u + cd->within %u", depth, cd->within);
-                                VALIDATE(depth + cd->within + dist >= 0 &&
-                                         depth + cd->within + dist <= UINT16_MAX);
-                                depth = cd->depth = (uint16_t)(depth + cd->within + dist);
-                            } else {
-                                SCLogDebug("offset %u + cd->within %u", offset, cd->within);
+
                                 VALIDATE(depth + cd->within >= 0 &&
                                          depth + cd->within <= UINT16_MAX);
-                                depth = cd->depth = (uint16_t)(offset + cd->within);
-                            }
-                            SCLogDebug("updated content to have depth %u", cd->depth);
-                        } else {
-                            if (cd->depth == 0 && depth != 0) {
-                                if (cd->within > 0) {
-                                    SCLogDebug("within %d distance %d", cd->within, cd->distance);
-                                    if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) {
-                                        VALIDATE(offset_plus_pat + cd->distance >= 0 &&
-                                                 offset_plus_pat + cd->distance <= UINT16_MAX);
-                                        cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
-                                        SCLogDebug("updated content to have offset %u", cd->offset);
-                                    }
-
-                                    VALIDATE(depth + cd->within >= 0 &&
-                                             depth + cd->within <= UINT16_MAX);
-                                    depth = cd->depth = (uint16_t)(cd->within + depth);
-                                    SCLogDebug("updated content to have depth %u", cd->depth);
-
-                                    if (cd->flags & DETECT_CONTENT_ENDS_WITH) {
-                                        has_ends_with = true;
-                                        if (ends_with_depth == 0)
-                                            ends_with_depth = depth;
-                                        ends_with_depth = MIN(ends_with_depth, depth);
-                                    }
+                                depth = cd->depth = (uint16_t)(cd->within + depth);
+                                SCLogDebug("updated content to have depth %u", cd->depth);
+
+                                if (cd->flags & DETECT_CONTENT_ENDS_WITH) {
+                                    has_ends_with = true;
+                                    if (ends_with_depth == 0)
+                                        ends_with_depth = depth;
+                                    ends_with_depth = MIN(ends_with_depth, depth);
                                 }
                             }
                         }
                     }
-                    if (cd->offset == 0) {// && offset != 0) {
-                        if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) {
-                            cd->offset = offset_plus_pat;
-                            SCLogDebug("update content to have offset %u", cd->offset);
-                        }
+                }
+                if (cd->offset == 0) { // && offset != 0) {
+                    if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) {
+                        cd->offset = offset_plus_pat;
+                        SCLogDebug("update content to have offset %u", cd->offset);
                     }
+                }
 
-                    if ((cd->flags & (DETECT_CONTENT_DEPTH|DETECT_CONTENT_OFFSET|DETECT_CONTENT_WITHIN|DETECT_CONTENT_DISTANCE)) == (DETECT_CONTENT_DISTANCE|DETECT_CONTENT_WITHIN) ||
-                            (cd->flags & (DETECT_CONTENT_DEPTH|DETECT_CONTENT_OFFSET|DETECT_CONTENT_WITHIN|DETECT_CONTENT_DISTANCE)) == (DETECT_CONTENT_DISTANCE)) {
-                        if (cd->distance >= 0) {
-                            // only distance
-                            VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX);
-                            offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
-                            offset_plus_pat = offset + cd->content_len;
-                            SCLogDebug("offset %u offset_plus_pat %u", offset, offset_plus_pat);
-                        }
-                    }
-                    if (cd->flags & DETECT_CONTENT_OFFSET) {
-                        offset = cd->offset;
-                        offset_plus_pat = offset + cd->content_len;
-                        SCLogDebug("stored offset %u offset_plus_pat %u", offset, offset_plus_pat);
-                    }
-                    if (cd->depth) {
-                        depth = cd->depth;
-                        SCLogDebug("stored depth now %u", depth);
+                if ((cd->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET |
+                                         DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) ==
+                                (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) ||
+                        (cd->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET |
+                                             DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) ==
+                                (DETECT_CONTENT_DISTANCE)) {
+                    if (cd->distance >= 0) {
+                        // only distance
+                        VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX);
+                        offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
                         offset_plus_pat = offset + cd->content_len;
-                        if (cd->flags & DETECT_CONTENT_ENDS_WITH) {
-                            has_ends_with = true;
-                            if (ends_with_depth == 0)
-                                ends_with_depth = depth;
-                            ends_with_depth = MIN(ends_with_depth, depth);
-                        }
+                        SCLogDebug("offset %u offset_plus_pat %u", offset, offset_plus_pat);
                     }
-                    if ((cd->flags & (DETECT_CONTENT_WITHIN|DETECT_CONTENT_DEPTH)) == 0) {
-                        has_active_depth_chain = false;
-                        depth = 0;
-                    }
-                    break;
                 }
-                case DETECT_PCRE: {
-                    // relative could leave offset_plus_pat set.
-                    const DetectPcreData *pd = (const DetectPcreData *)sm->ctx;
-                    if (pd->flags & DETECT_PCRE_RELATIVE) {
-                        depth = 0;
-                    } else {
-                        SCLogDebug("non-anchored PCRE not supported, reset offset_plus_pat & offset");
-                        offset_plus_pat = offset = depth = 0;
+                if (cd->flags & DETECT_CONTENT_OFFSET) {
+                    offset = cd->offset;
+                    offset_plus_pat = offset + cd->content_len;
+                    SCLogDebug("stored offset %u offset_plus_pat %u", offset, offset_plus_pat);
+                }
+                if (cd->depth) {
+                    depth = cd->depth;
+                    SCLogDebug("stored depth now %u", depth);
+                    offset_plus_pat = offset + cd->content_len;
+                    if (cd->flags & DETECT_CONTENT_ENDS_WITH) {
+                        has_ends_with = true;
+                        if (ends_with_depth == 0)
+                            ends_with_depth = depth;
+                        ends_with_depth = MIN(ends_with_depth, depth);
                     }
+                }
+                if ((cd->flags & (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DEPTH)) == 0) {
                     has_active_depth_chain = false;
-                    break;
+                    depth = 0;
                 }
-                default: {
-                    SCLogDebug("keyword not supported, reset offset_plus_pat & offset");
+                break;
+            }
+            case DETECT_PCRE: {
+                // relative could leave offset_plus_pat set.
+                const DetectPcreData *pd = (const DetectPcreData *)sm->ctx;
+                if (pd->flags & DETECT_PCRE_RELATIVE) {
+                    depth = 0;
+                } else {
+                    SCLogDebug("non-anchored PCRE not supported, reset offset_plus_pat & offset");
                     offset_plus_pat = offset = depth = 0;
-                    has_active_depth_chain = false;
-                    break;
                 }
+                has_active_depth_chain = false;
+                break;
             }
+            default:
+                SCLogDebug("keyword not supported, reset offset_plus_pat & offset");
+                offset_plus_pat = offset = depth = 0;
+                has_active_depth_chain = false;
+                break;
         }
-        /* apply anchored 'ends with' as depth to all patterns */
-        if (has_depth && has_ends_with) {
-            sm = s->init_data->smlists[list];
-            for ( ; sm != NULL; sm = sm->next) {
-                switch (sm->type) {
-                    case DETECT_CONTENT: {
-                        DetectContentData *cd = (DetectContentData *)sm->ctx;
-                        if (cd->depth == 0)
-                            cd->depth = ends_with_depth;
-                        cd->depth = MIN(ends_with_depth, cd->depth);
-                        if (cd->depth)
-                            cd->flags |= DETECT_CONTENT_DEPTH;
-                        break;
-                    }
+    }
+    /* apply anchored 'ends with' as depth to all patterns */
+    if (has_depth && has_ends_with) {
+        for (SigMatch *sm = sm_head; sm != NULL; sm = sm->next) {
+            switch (sm->type) {
+                case DETECT_CONTENT: {
+                    DetectContentData *cd = (DetectContentData *)sm->ctx;
+                    if (cd->depth == 0)
+                        cd->depth = ends_with_depth;
+                    cd->depth = MIN(ends_with_depth, cd->depth);
+                    if (cd->depth)
+                        cd->flags |= DETECT_CONTENT_DEPTH;
+                    break;
                 }
             }
         }
@@ -696,6 +692,14 @@ void DetectContentPropagateLimits(Signature *s)
 #undef VALIDATE
 }
 
+void DetectContentPropagateLimits(Signature *s)
+{
+    for (uint32_t list = 0; list < s->init_data->smlists_array_size; list++) {
+        SigMatch *sm = s->init_data->smlists[list];
+        PropagateLimits(s, sm);
+    }
+}
+
 static inline bool NeedsAsHex(uint8_t c)
 {
     if (!isprint(c))