]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
analysis: report rule state altered by other rule
authorJuliana Fajardini <jufajardini@gmail.com>
Fri, 17 Jan 2025 20:43:34 +0000 (17:43 -0300)
committerVictor Julien <victor@inliniac.net>
Wed, 19 Feb 2025 08:21:32 +0000 (09:21 +0100)
Flowbits can make a rule such as a packet rule be treated as a stateful
rule, without actually changing the rule type.

Add a flag to allow reporting such cases via engine analysis.

Task #7456

src/detect-engine-analyzer.c
src/detect-engine-build.c
src/detect-flowbits.c
src/detect-parse.c
src/detect.h

index dae6f9f2f27065a5b46fbac2168ddf10c547fa43..083c370dc0f0f295ba353bc3b850dcb4bd2731c9 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2023 Open Information Security Foundation
+/* Copyright (C) 2007-2025 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
@@ -1047,6 +1047,34 @@ void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
             break;
     }
 
+    // dependencies object and its subfields only logged if we have values
+    if (s->init_data->is_rule_state_dependant) {
+        jb_open_object(ctx.js, "dependencies");
+        jb_open_object(ctx.js, "flowbits");
+        jb_open_object(ctx.js, "upstream");
+        if (s->init_data->rule_state_dependant_sids_size > 0) {
+            jb_open_object(ctx.js, "state_modifying_rules");
+            jb_open_array(ctx.js, "sids");
+            for (uint32_t i = 0; i < s->init_data->rule_state_dependant_sids_idx; i++) {
+                jb_append_uint(ctx.js, s->init_data->rule_state_dependant_sids_array[i]);
+            }
+            jb_close(ctx.js); // sids
+            jb_open_array(ctx.js, "names");
+            for (uint32_t i = 0; i < s->init_data->rule_state_flowbits_ids_size - 1; i++) {
+                if (s->init_data->rule_state_flowbits_ids_array[i] != 0) {
+                    jb_append_string(ctx.js,
+                            VarNameStoreSetupLookup(s->init_data->rule_state_flowbits_ids_array[i],
+                                    VAR_TYPE_FLOW_BIT));
+                }
+            }
+            jb_close(ctx.js); // names
+            jb_close(ctx.js); // state_modifying_rules
+        }
+        jb_close(ctx.js); // upstream
+        jb_close(ctx.js); // flowbits
+        jb_close(ctx.js); // dependencies
+    }
+
     jb_open_array(ctx.js, "flags");
     if (s->flags & SIG_FLAG_SRC_ANY) {
         jb_append_string(ctx.js, "src_any");
index fd73520ba9c17f9782822edc7fe9c10217a678c1..e348103ce31b1836afbc0f28df7024fb9348f1f4 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2023 Open Information Security Foundation
+/* Copyright (C) 2007-2025 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
@@ -2091,6 +2091,8 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx)
             IPOnlyCIDRListFree(s->init_data->cidr_src);
 
         SCFree(s->init_data->buffers);
+        SCFree(s->init_data->rule_state_dependant_sids_array);
+        SCFree(s->init_data->rule_state_flowbits_ids_array);
         SCFree(s->init_data);
         s->init_data = NULL;
     }
index 8efb93ed793fac6a0b0d8e45dc4dfac665d6c51a..5679bfa99e1c82694edf048f2578b3e2e918c9e6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2022 Open Information Security Foundation
+/* Copyright (C) 2007-2025 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
@@ -630,6 +630,70 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
                 SCLogDebug("GET flowbit %s/%u: SID %u", varname, i, s->id);
 
                 s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH;
+                s->init_data->is_rule_state_dependant = true;
+
+                uint32_t sids_array_size = array[i].set_sids_idx;
+
+                // save information about flowbits that affect this rule's state
+                if (s->init_data->rule_state_dependant_sids_array == NULL) {
+                    s->init_data->rule_state_dependant_sids_array =
+                            SCCalloc(sids_array_size, sizeof(uint32_t));
+                    if (s->init_data->rule_state_dependant_sids_array == NULL) {
+                        SCLogError("Failed to allocate memory for rule_state_dependant_ids");
+                        goto end;
+                    }
+                    s->init_data->rule_state_flowbits_ids_size = 1;
+                    s->init_data->rule_state_flowbits_ids_array =
+                            SCCalloc(s->init_data->rule_state_flowbits_ids_size, sizeof(uint32_t));
+                    if (s->init_data->rule_state_flowbits_ids_array == NULL) {
+                        SCLogError("Failed to allocate memory for rule_state_variable_idx");
+                        goto end;
+                    }
+                    s->init_data->rule_state_dependant_sids_size = sids_array_size;
+                    SCLogDebug("alloc'ed array for rule dependency and fbs idx array, sid %u, "
+                               "sizes are %u and %u",
+                            s->id, s->init_data->rule_state_dependant_sids_size,
+                            s->init_data->rule_state_flowbits_ids_size);
+                } else {
+                    uint32_t new_array_size =
+                            s->init_data->rule_state_dependant_sids_size + sids_array_size;
+                    void *tmp_ptr = SCRealloc(s->init_data->rule_state_dependant_sids_array,
+                            new_array_size * sizeof(uint32_t));
+                    if (tmp_ptr == NULL) {
+                        SCLogError("Failed to allocate memory for rule_state_variable_idx");
+                        goto end;
+                    }
+                    s->init_data->rule_state_dependant_sids_array = tmp_ptr;
+                    s->init_data->rule_state_dependant_sids_size = new_array_size;
+                    SCLogDebug("realloc'ed array for rule dependency, sid %u, new size is %u",
+                            s->id, s->init_data->rule_state_dependant_sids_size);
+                    uint32_t new_fb_array_size = s->init_data->rule_state_flowbits_ids_size + 1;
+                    void *tmp_fb_ptr = SCRealloc(s->init_data->rule_state_flowbits_ids_array,
+                            new_fb_array_size * sizeof(uint32_t));
+                    s->init_data->rule_state_flowbits_ids_array = tmp_fb_ptr;
+                    if (s->init_data->rule_state_flowbits_ids_array == NULL) {
+                        SCLogError("Failed to reallocate memory for rule_state_variable_idx");
+                        goto end;
+                    }
+                    SCLogDebug(
+                            "realloc'ed array for flowbits ids, new size is %u", new_fb_array_size);
+                    s->init_data->rule_state_dependant_sids_size = new_array_size;
+                    s->init_data->rule_state_flowbits_ids_size = new_fb_array_size;
+                }
+                for (uint32_t idx = 0; idx < s->init_data->rule_state_dependant_sids_size; idx++) {
+                    if (idx < array[i].set_sids_idx) {
+                        s->init_data->rule_state_dependant_sids_array
+                                [s->init_data->rule_state_dependant_sids_idx] =
+                                de_ctx->sig_array[array[i].set_sids[idx]]->id;
+                        s->init_data->rule_state_dependant_sids_idx++;
+                    }
+                }
+                s->init_data
+                        ->rule_state_flowbits_ids_array[s->init_data->rule_state_flowbits_ids_size -
+                                                        1] = i;
+                s->init_data->rule_state_flowbits_ids_size += 1;
+                // flowbit info saving for rule made stateful rule work finished
+
                 SCLogDebug("made SID %u stateful because it depends on "
                         "stateful rules that set flowbit %s", s->id, varname);
             }
index ab3f43b11e5d5cb38eb7b0717df3a3566267c591..87519bb69bb2ae2d11dc1e3cc9c4775c23285985 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2021 Open Information Security Foundation
+/* Copyright (C) 2007-2025 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
@@ -1564,6 +1564,11 @@ Signature *SigAlloc (void)
      * overwritten, we can then assign the default value of 3 */
     sig->prio = -1;
 
+    /* rule interdepency is false, at start */
+    sig->init_data->is_rule_state_dependant = false;
+    /* first index is 0 */
+    sig->init_data->rule_state_dependant_sids_idx = 0;
+
     sig->init_data->list = DETECT_SM_LIST_NOTSET;
     return sig;
 }
index 2348c54e679dc9301fc6936d657d7f6be1ce680e..5231345288d222a333ab7bd1478a6e4102842740 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2023 Open Information Security Foundation
+/* Copyright (C) 2007-2025 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
@@ -600,6 +600,14 @@ typedef struct SignatureInitData_ {
 
     /* highest list/buffer id which holds a DETECT_CONTENT */
     uint32_t max_content_list_id;
+
+    /* inter-signature state dependency */
+    bool is_rule_state_dependant;
+    uint32_t *rule_state_dependant_sids_array;
+    uint32_t rule_state_dependant_sids_size;
+    uint32_t rule_state_dependant_sids_idx;
+    uint32_t *rule_state_flowbits_ids_array;
+    uint32_t rule_state_flowbits_ids_size;
 } SignatureInitData;
 
 /** \brief Signature container */