From 23a840e1f09867da2fa5c640b196d29db3b959d3 Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Fri, 17 Jan 2025 17:43:34 -0300 Subject: [PATCH] analysis: report rule state altered by other rule 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 | 30 +++++++++++++++- src/detect-engine-build.c | 4 ++- src/detect-flowbits.c | 66 +++++++++++++++++++++++++++++++++++- src/detect-parse.c | 7 +++- src/detect.h | 10 +++++- 5 files changed, 112 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index dae6f9f2f270..083c370dc0f0 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -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"); diff --git a/src/detect-engine-build.c b/src/detect-engine-build.c index 7c9b66013e35..37dfb3010795 100644 --- a/src/detect-engine-build.c +++ b/src/detect-engine-build.c @@ -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 @@ -2092,6 +2092,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; } diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 8efb93ed793f..5679bfa99e1c 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -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); } diff --git a/src/detect-parse.c b/src/detect-parse.c index 65719286bb25..8b84369b0a6f 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -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; } diff --git a/src/detect.h b/src/detect.h index 7408ec8edc4e..23e901dd6eba 100644 --- a/src/detect.h +++ b/src/detect.h @@ -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 @@ -602,6 +602,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 */