Skip to content

Commit

Permalink
detect/flowbits: implement prefilter support
Browse files Browse the repository at this point in the history
Allow for more efficient rules that 'prefilter' on flowbits with 'isset' logic.

This prefilter is enabled by default, which means that if no mpm is present or
no explicit prefilter is used, the flowbits prefilter will be set up for a rule.

flowbits 'isset' prefilter

For rules that have a 'flowbits:isset,<bit>' statement, a "regular" prefilter
facility is created. It means that the rules are removed from the normal
match list(s) and added to a prefilter engine that runs prior to the individual
rule inspection stage.

Implementation: the prefilter is implemented as an RB_TREE of flowbits, with the
rule id's they "enable" stored per tree node. The matching logic is walking the
list of bits set in the flow and looking each of them up in the RB_TREE, adding
the rule ids of each of the matching bits to the list of rule candidates.

The 'isset' prefilter has one important corner case, which is that bits can in
fact be set during the rule evaluation stage. This is different from all other
prefilter engines, that evaluate an immutable state (for the lifetime of the
packets inspection).

flowbits 'set' post-match prefilter

For flowbits 'set' action, special post-match 'prefilter' facilities deal with
this corner case. The high level logic is that these track which 'isset' sigs
depend on them, and add these dependencies to the candidates list when a 'set'
action occurs.

This is implemented in a few steps:

1. flowbits 'set' is flagged
2. when 'set' action occurs the flowbit is added to a "post rule
   match work queue"
3. when the rule evaluation ends, the post-match "prefilter" engine is run
   on each of the flowbits in the "post rule match work queue"
4. these engines ammend the candidates list with the rule id dependencies
   for the flowbit
5. the candidates list is sorted to make sure within the execution for that
   packet the inspection order is maintained

Ticket: #2486.
  • Loading branch information
victorjulien committed Jan 13, 2025
1 parent a811e19 commit eec47ef
Show file tree
Hide file tree
Showing 10 changed files with 968 additions and 163 deletions.
2 changes: 1 addition & 1 deletion src/detect-engine-build.c
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ static json_t *RulesGroupPrintSghStats(const DetectEngineCtx *de_ctx, const SigG
any5_cnt++;
}

prefilter_cnt += (s->init_data->prefilter_sm != 0);
prefilter_cnt += (s->init_data->prefilter_sm != NULL);
if (s->init_data->mpm_sm == NULL) {
nonmpm_cnt++;

Expand Down
117 changes: 117 additions & 0 deletions src/detect-engine-prefilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,35 @@ void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx,
}
}

/** \brief invoke post-rule match "prefilter" engines
*
* Invoke prefilter engines that depend on a rule match to run.
* e.g. the flowbits:set prefilter that adds sids that depend on
* a flowbit "set" to the match array.
*/
void PrefilterPostRuleMatch(
DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, Flow *f)
{
SCLogDebug("post-rule-match engines %p", sgh->post_rule_match_engines);
if (sgh->post_rule_match_engines) {
PrefilterEngine *engine = sgh->post_rule_match_engines;
do {
SCLogDebug("running post-rule-match engine");
PREFILTER_PROFILING_START(det_ctx);
engine->cb.PrefilterPostRule(det_ctx, engine->pectx, p, f);
PREFILTER_PROFILING_END(det_ctx, engine->gid);

if (engine->is_last)
break;
engine++;
} while (1);

if (det_ctx->pmq.rule_id_array_cnt > 1) {
QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt);
}
}
}

void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p,
const uint8_t flags, const SignatureMask mask)
{
Expand Down Expand Up @@ -342,6 +371,39 @@ int PrefilterAppendFrameEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
return 0;
}

int PrefilterAppendPostRuleEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
void (*PrefilterPostRuleFunc)(
DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f),
void *pectx, void (*FreeFunc)(void *pectx), const char *name)
{
if (sgh == NULL || PrefilterPostRuleFunc == NULL || pectx == NULL)
return -1;

PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
if (e == NULL)
return -1;
memset(e, 0x00, sizeof(*e));
e->PrefilterPostRule = PrefilterPostRuleFunc;
e->pectx = pectx;
e->Free = FreeFunc;

if (sgh->init->post_rule_match_engines == NULL) {
sgh->init->post_rule_match_engines = e;
} else {
PrefilterEngineList *t = sgh->init->post_rule_match_engines;
while (t->next != NULL) {
t = t->next;
}

t->next = e;
e->id = t->id + 1;
}

e->name = name;
e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free);
return 0;
}

static void PrefilterFreeEngineList(PrefilterEngineList *e)
{
if (e->Free && e->pectx) {
Expand Down Expand Up @@ -396,6 +458,10 @@ void PrefilterCleanupRuleGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
PrefilterFreeEngines(de_ctx, sgh->frame_engines);
sgh->frame_engines = NULL;
}
if (sgh->post_rule_match_engines) {
PrefilterFreeEngines(de_ctx, sgh->post_rule_match_engines);
sgh->post_rule_match_engines = NULL;
}
}

static int PrefilterSetupRuleGroupSortHelper(const void *a, const void *b)
Expand Down Expand Up @@ -589,6 +655,30 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
e++;
}
}
if (sgh->init->post_rule_match_engines != NULL) {
uint32_t cnt = 0;
for (el = sgh->init->post_rule_match_engines; el != NULL; el = el->next) {
cnt++;
}
sgh->post_rule_match_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS);
if (sgh->post_rule_match_engines == NULL) {
return;
}
memset(sgh->post_rule_match_engines, 0x00, (cnt * sizeof(PrefilterEngine)));

uint16_t local_id = 0;
PrefilterEngine *e = sgh->post_rule_match_engines;
for (el = sgh->init->post_rule_match_engines; el != NULL; el = el->next) {
e->local_id = local_id++;
e->cb.PrefilterPostRule = el->PrefilterPostRule;
e->pectx = el->pectx;
el->pectx = NULL; // e now owns the ctx
e->gid = el->gid;
e->is_last = (el->next == NULL);
e++;
}
SCLogDebug("sgh %p max local_id %u", sgh, local_id);
}
}

/* hash table for assigning a unique id to each engine type. */
Expand Down Expand Up @@ -889,3 +979,30 @@ int PrefilterGenericMpmPktRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, M
}
return r;
}

#define QUEUE_STEP 16

void PostRuleMatchWorkQueueAppend(
DetectEngineThreadCtx *det_ctx, const Signature *s, const int type, const uint32_t value)
{
if (det_ctx->post_rule_work_queue.q == NULL) {
det_ctx->post_rule_work_queue.q =
SCCalloc(1, sizeof(PostRuleMatchWorkQueueItem) * QUEUE_STEP);
BUG_ON(det_ctx->post_rule_work_queue.q == NULL);
det_ctx->post_rule_work_queue.size = QUEUE_STEP;
} else if (det_ctx->post_rule_work_queue.len == det_ctx->post_rule_work_queue.size) {
void *ptr = SCRealloc(
det_ctx->post_rule_work_queue.q, (det_ctx->post_rule_work_queue.size + QUEUE_STEP) *
sizeof(PostRuleMatchWorkQueueItem));
BUG_ON(ptr == NULL);
det_ctx->post_rule_work_queue.q = ptr;
det_ctx->post_rule_work_queue.size += QUEUE_STEP;
}
det_ctx->post_rule_work_queue.q[det_ctx->post_rule_work_queue.len].sm_type = type;
det_ctx->post_rule_work_queue.q[det_ctx->post_rule_work_queue.len].value = value;
#ifdef DEBUG
det_ctx->post_rule_work_queue.q[det_ctx->post_rule_work_queue.len].id = s->num;
#endif
det_ctx->post_rule_work_queue.len++;
SCLogDebug("det_ctx->post_rule_work_queue.len %u", det_ctx->post_rule_work_queue.len);
}
13 changes: 12 additions & 1 deletion src/detect-engine-prefilter.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2016 Open Information Security Foundation
/* Copyright (C) 2016-2020 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
Expand Down Expand Up @@ -52,6 +52,10 @@ void Prefilter(DetectEngineThreadCtx *, const SigGroupHead *, Packet *p, const u

int PrefilterAppendEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterPktFn PrefilterFunc,
SignatureMask mask, void *pectx, void (*FreeFunc)(void *pectx), const char *name);

void PrefilterPostRuleMatch(
DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, Flow *f);

int PrefilterAppendPayloadEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
PrefilterPktFn PrefilterFunc, void *pectx, void (*FreeFunc)(void *pectx), const char *name);
int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
Expand All @@ -60,6 +64,10 @@ int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
int PrefilterAppendFrameEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
PrefilterFrameFn PrefilterFrameFunc, AppProto alproto, uint8_t frame_type, void *pectx,
void (*FreeFunc)(void *pectx), const char *name);
int PrefilterAppendPostRuleEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
void (*PrefilterPostRuleFunc)(
DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f),
void *pectx, void (*FreeFunc)(void *pectx), const char *name);

void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx,
const SigGroupHead *sgh,
Expand Down Expand Up @@ -91,4 +99,7 @@ int PrefilterMultiGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
int PrefilterGenericMpmPktRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
const DetectBufferMpmRegistry *mpm_reg, int list_id);

void PostRuleMatchWorkQueueAppend(
DetectEngineThreadCtx *det_ctx, const Signature *s, const int type, const uint32_t value);

#endif
1 change: 1 addition & 0 deletions src/detect-engine-siggroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid)
PrefilterFreeEnginesList(sghid->pkt_engines);
PrefilterFreeEnginesList(sghid->payload_engines);
PrefilterFreeEnginesList(sghid->frame_engines);
PrefilterFreeEnginesList(sghid->post_rule_match_engines);

SCFree(sghid);
}
Expand Down
3 changes: 3 additions & 0 deletions src/detect-engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -3539,6 +3539,9 @@ static void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx)

AlertQueueFree(det_ctx);

if (det_ctx->post_rule_work_queue.q)
SCFree(det_ctx->post_rule_work_queue.q);

if (det_ctx->byte_values != NULL)
SCFree(det_ctx->byte_values);

Expand Down
Loading

0 comments on commit eec47ef

Please sign in to comment.