From 4e62c57bea27862e0e98ae40e96df2be73c718f2 Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Sat, 16 Mar 2024 08:58:11 -0400 Subject: [PATCH] profiling/rules: Improve dynamic rule handling Issue: 6861 Without this commit, disabling rule profiling via suricatasc's command 'ruleset-profile-stop' may crash because profiling_rules_entered becomes negative. This can happen because - There can be multiple rules evaluated for a single packet - Each rule is profiled individually. - Starting profiling is gated by a configuration setting and rule profiling being active - Ending profiling is gated by the same configuration setting and whether the packet was marked as profiling. The crash can occur when a rule is being profiled and rule profiling is then disabled after one at least one rule was profiled for the packet (which marks the packet as being profiled). In this scenario, the value of profiling_rules_entered was not incremented so the BUG_ON in the end profiling macro trips because it is 0. The changes to fix the problem are: - In the profiling end macro, gate the actions taken there by the same configuration setting and use the profiling_rues_entered (instead of the per-packet profiling flag). Since the start and end macros are tightly coupled, this will permit profiling to "finish" if started. - Modify SCProfileRuleStart to only check the sampling values if the packet hasn't been marked for profiling already. This change makes all rules for a packet (once selected) to be profiled (without this change sampling is applied to each *rule* that applies to the packet. --- src/util-profiling.c | 18 +++++++++++------- src/util-profiling.h | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/util-profiling.c b/src/util-profiling.c index a4f5bbef0ae7..e8a2dfa6330a 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1208,15 +1208,16 @@ int SCProfileRuleStart(Packet *p) p->flags |= PKT_PROFILE; return 1; } -#else +#endif + if (p->flags & PKT_PROFILE) { + return 1; + } + uint64_t sample = SC_ATOMIC_ADD(samples, 1); - if (sample % rate == 0) { + if ((sample % rate) == 0) { p->flags |= PKT_PROFILE; return 1; } -#endif - if (p->flags & PKT_PROFILE) - return 1; return 0; } @@ -1450,17 +1451,20 @@ void SCProfilingInit(void) /* see if we want to profile rules for this packet */ int SCProfileRuleStart(Packet *p) { + /* Move first so we'll always finish even if dynamically disabled */ + if (p->flags & PKT_PROFILE) + return 1; + if (!SC_ATOMIC_GET(profiling_rules_active)) { return 0; } + uint64_t sample = SC_ATOMIC_ADD(samples, 1); if ((sample & rate) == 0) { p->flags |= PKT_PROFILE; return 1; } - if (p->flags & PKT_PROFILE) - return 1; return 0; } diff --git a/src/util-profiling.h b/src/util-profiling.h index 21b60a3c1916..564f62b5c78f 100644 --- a/src/util-profiling.h +++ b/src/util-profiling.h @@ -417,7 +417,7 @@ void SCProfilingRuleThreatAggregate(DetectEngineThreadCtx *det_ctx); } #define RULE_PROFILING_END(ctx, r, m, p) \ - if (profiling_rules_enabled && ((p)->flags & PKT_PROFILE)) { \ + if (profiling_rules_enabled && profiling_rules_entered) { \ profile_rule_end_ = UtilCpuGetTicks(); \ SCProfilingRuleUpdateCounter( \ ctx, r->profiling_id, profile_rule_end_ - profile_rule_start_, m); \