From: Juliana Fajardini Date: Fri, 17 Jan 2025 20:43:34 +0000 (-0300) Subject: analysis: report rule state altered by other rule X-Git-Tag: suricata-8.0.0-beta1~420 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=06b506e2cd0bdba184b439430489a336d41b72a4;p=thirdparty%2Fsuricata.git 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 --- diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index dae6f9f2f2..083c370dc0 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 fd73520ba9..e348103ce3 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 @@ -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; } diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 8efb93ed79..5679bfa99e 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 ab3f43b11e..87519bb69b 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 2348c54e67..5231345288 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 @@ -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 */