detect: support multi buffer matching

Multi buffer matching is implemented as a way for a rule to match
on multiple buffers within the same transaction.

Before this patch a rule like:

    dns.query; content:"example"; dns.query; content:".com";

would be equivalent to:

    dns.query; content:"example"; content:".com";

If a DNS query would request more than one name, e.g.:

    DNS: [example.net][something.com]

Eeach would be inspected to have both patterns present. Otherwise,
it would not be a match. So the rule above would not match, as neither
example.net and somthing.com satisfy both conditions at the same time.

This patch changes this behavior. Instead of the above, each time the
sticky buffer is specified, it creates a separate detection unit. Each
buffer is a "multi buffer" sticky buffer will now be evaluated against
each "instance" of the sticky buffer.

To continue with the above example:

    DNS: [example.net] <- matches 'dns.query; content:"example";'
    DNS: [something.com] <- matches 'dns.query; content:".com"'

So this would now be a match.

To make sure both patterns match in a single query string, the expression
'dns.query; content:"example"; content:".com";' still works for this.

This patch doesn't yet enable the behavior for the keywords. That is
done in a follow up patch.

To be able to implement this the internal storage of parsed rules
is changed. Until this patch and array of lists was used, where the
index was the buffer id (e.g. http_uri, dns_query). Therefore there
was only one list of matches per buffer id. As a side effect this
array was always very sparsely populated as many buffers could not
be mixed.

This patch changes the internal representation. The new array is densely
packed:

    dns.query; content:"1"; dns.query; bsize:1; content:"2";

    [type: dns_query][list: content:"1";]
    [type: dns_query][list: bsize:1; content:"2";]

The new scheme allows for multiple instances of the same buffer.
These lists are then translated into multiple inspection engines
during the final setup of the rule.

Ticket: #5784.
pull/8792/head
Victor Julien 3 years ago
parent 1c6644ef4e
commit ad88efc2d8

@ -45,11 +45,11 @@ static int SigParseGetMaxBsize(DetectU64Data *bsz);
static void DetectBsizeRegisterTests (void);
#endif
bool DetectBsizeValidateContentCallback(Signature *s, int list)
bool DetectBsizeValidateContentCallback(Signature *s, const SignatureInitDataBuffer *b)
{
int bsize = -1;
DetectU64Data *bsz;
for (const SigMatch *sm = s->init_data->smlists[list]; sm != NULL; sm = sm->next) {
for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_BSIZE) {
bsz = (DetectU64Data *)sm->ctx;
bsize = SigParseGetMaxBsize(bsz);
@ -64,7 +64,7 @@ bool DetectBsizeValidateContentCallback(Signature *s, int list)
uint64_t needed;
if (bsize >= 0) {
int len, offset;
SigParseRequiredContentSize(s, bsize, s->init_data->smlists[list], &len, &offset);
SigParseRequiredContentSize(s, bsize, b->head, &len, &offset);
SCLogDebug("bsize: %d; len: %d; offset: %d [%s]", bsize, len, offset, s->sig_str);
needed = len;
if (len > bsize) {

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Open Information Security Foundation
/* Copyright (C) 2017-2023 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
@ -26,6 +26,6 @@
void DetectBsizeRegister(void);
int DetectBsizeMatch(const SigMatchCtx *ctx, const uint64_t buffer_size, bool eof);
bool DetectBsizeValidateContentCallback(Signature *s, int list);
bool DetectBsizeValidateContentCallback(Signature *s, const SignatureInitDataBuffer *);
#endif /* __DETECT_URILEN_H__ */

@ -665,8 +665,20 @@ static void DetectByteExtractFree(DetectEngineCtx *de_ctx, void *ptr)
*/
SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, const Signature *s)
{
const int nlists = s->init_data->smlists_array_size;
for (int list = 0; list < nlists; list++) {
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
SigMatch *sm = s->init_data->buffers[x].head;
while (sm != NULL) {
if (sm->type == DETECT_BYTE_EXTRACT) {
const DetectByteExtractData *bed = (const DetectByteExtractData *)sm->ctx;
if (strcmp(bed->name, arg) == 0) {
return sm;
}
}
sm = sm->next;
}
}
for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
SigMatch *sm = s->init_data->smlists[list];
while (sm != NULL) {
if (sm->type == DETECT_BYTE_EXTRACT) {

@ -410,8 +410,21 @@ static void DetectByteMathFree(DetectEngineCtx *de_ctx, void *ptr)
*/
SigMatch *DetectByteMathRetrieveSMVar(const char *arg, const Signature *s)
{
const int nlists = s->init_data->smlists_array_size;
for (int list = 0; list < nlists; list++) {
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
SigMatch *sm = s->init_data->buffers[x].head;
while (sm != NULL) {
if (sm->type == DETECT_BYTEMATH) {
const DetectByteMathData *bmd = (const DetectByteMathData *)sm->ctx;
if (strcmp(bmd->result, arg) == 0) {
SCLogDebug("Retrieved SM for \"%s\"", arg);
return sm;
}
}
sm = sm->next;
}
}
for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
SigMatch *sm = s->init_data->smlists[list];
while (sm != NULL) {
if (sm->type == DETECT_BYTEMATH) {

@ -710,9 +710,9 @@ static void PropagateLimits(Signature *s, SigMatch *sm_head)
void DetectContentPropagateLimits(Signature *s)
{
for (uint32_t list = 0; list < s->init_data->smlists_array_size; list++) {
SigMatch *sm = s->init_data->smlists[list];
PropagateLimits(s, sm);
PropagateLimits(s, s->init_data->smlists[DETECT_SM_LIST_PMATCH]);
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
PropagateLimits(s, s->init_data->buffers[x].head);
}
}

@ -1321,7 +1321,7 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx,
rule_ipv6_only += 1;
}
for (list_id = 0; list_id < (int)s->init_data->smlists_array_size; list_id++) {
for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) {
SigMatch *sm = NULL;
for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) {
int16_t item_slot = analyzer_item_map[list_id];
@ -1385,11 +1385,10 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx,
rule_flags = 1;
}
}
} /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
} /* for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) */
} /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
if (file_store && !RequiresFeature("output::file-store")) {
rule_warning += 1;
warn_file_store_not_present = 1;

@ -185,6 +185,11 @@ int SignatureIsFilesizeInspecting(const Signature *s)
return 0;
}
static bool SignatureInspectsBuffers(const Signature *s)
{
return (s->init_data->buffer_index > 0);
}
/** \brief Test is a initialized signature is IP only
* \param de_ctx detection engine ctx
* \param s the signature
@ -211,13 +216,7 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s)
return 0;
/* for now assume that all registered buffer types are incompatible */
const int nlists = s->init_data->smlists_array_size;
for (int i = 0; i < nlists; i++) {
if (s->init_data->smlists[i] == NULL)
continue;
if (!(DetectEngineBufferTypeGetNameById(de_ctx, i)))
continue;
if (SignatureInspectsBuffers(s)) {
SCReturnInt(0);
}
@ -275,13 +274,7 @@ static int SignatureIsPDOnly(const DetectEngineCtx *de_ctx, const Signature *s)
return 0;
/* for now assume that all registered buffer types are incompatible */
const int nlists = s->init_data->smlists_array_size;
for (int i = 0; i < nlists; i++) {
if (s->init_data->smlists[i] == NULL)
continue;
if (!(DetectEngineBufferTypeGetNameById(de_ctx, i)))
continue;
if (SignatureInspectsBuffers(s)) {
SCReturnInt(0);
}
@ -362,13 +355,7 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s)
}
/* for now assume that all registered buffer types are incompatible */
const int nlists = s->init_data->smlists_array_size;
for (int i = 0; i < nlists; i++) {
if (s->init_data->smlists[i] == NULL)
continue;
if (!(DetectEngineBufferTypeGetNameById(de_ctx, i)))
continue;
if (SignatureInspectsBuffers(s)) {
SCReturnInt(0);
}
@ -461,16 +448,11 @@ static bool SignatureNeedsDCERPCMask(const Signature *s)
SCLogDebug("g_dce_stub_data_buffer_id %d", g_dce_stub_data_buffer_id);
}
if (g_dce_generic_list_id >= 0 &&
s->init_data->smlists[g_dce_generic_list_id] != NULL)
{
return true;
}
if (g_dce_stub_data_buffer_id >= 0 &&
s->init_data->smlists[g_dce_stub_data_buffer_id] != NULL)
{
if (DetectBufferIsPresent(s, g_dce_generic_list_id) ||
DetectBufferIsPresent(s, g_dce_stub_data_buffer_id)) {
return true;
}
return false;
}
@ -1430,8 +1412,10 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx)
{
int prefilter_list = DETECT_TBLSIZE;
// TODO buffers?
/* get the keyword supporting prefilter with the lowest type */
for (int i = 0; i < (int)s->init_data->smlists_array_size; i++) {
for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
if (sigmatch_table[sm->type].SupportsPrefilter != NULL) {
if (sigmatch_table[sm->type].SupportsPrefilter(s)) {
@ -1443,7 +1427,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx)
/* apply that keyword as prefilter */
if (prefilter_list != DETECT_TBLSIZE) {
for (int i = 0; i < (int)s->init_data->smlists_array_size; i++) {
for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
if (sm->type == prefilter_list) {
s->init_data->prefilter_sm = sm;
@ -1457,10 +1441,13 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx)
}
/* run buffer type callbacks if any */
for (int x = 0; x < (int)s->init_data->smlists_array_size; x++) {
for (int x = 0; x < DETECT_SM_LIST_MAX; x++) {
if (s->init_data->smlists[x])
DetectEngineBufferRunSetupCallback(de_ctx, x, s);
}
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
DetectEngineBufferRunSetupCallback(de_ctx, s->init_data->buffers[x].id, s);
}
de_ctx->sig_cnt++;
}
@ -1902,7 +1889,7 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx)
}
/* free lists. Ctx' are xferred to sm_arrays so won't get freed */
uint32_t i;
for (i = 0; i < s->init_data->smlists_array_size; i++) {
for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
SigMatch *sm = s->init_data->smlists[i];
while (sm != NULL) {
SigMatch *nsm = sm->next;
@ -1910,8 +1897,6 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx)
sm = nsm;
}
}
SCFree(s->init_data->smlists);
SCFree(s->init_data->smlists_tail);
for (i = 0; i < (uint32_t)s->init_data->transforms.cnt; i++) {
if (s->init_data->transforms.transforms[i].options) {
int transform = s->init_data->transforms.transforms[i].transform;
@ -1920,6 +1905,15 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx)
s->init_data->transforms.transforms[i].options = NULL;
}
}
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
SigMatch *sm = s->init_data->buffers[x].head;
while (sm != NULL) {
SigMatch *nsm = sm->next;
SigMatchFree(de_ctx, sm);
sm = nsm;
}
}
SCFree(s->init_data->buffers);
SCFree(s->init_data);
s->init_data = NULL;
}

@ -1033,10 +1033,10 @@ static void SetMpm(Signature *s, SigMatch *mpm_sm, const int mpm_sm_list)
return;
}
static SigMatch *GetMpmForList(const Signature *s, const int list, SigMatch *mpm_sm,
uint16_t max_len, bool skip_negated_content)
static SigMatch *GetMpmForList(const Signature *s, SigMatch *list, SigMatch *mpm_sm,
uint16_t max_len, bool skip_negated_content)
{
for (SigMatch *sm = s->init_data->smlists[list]; sm != NULL; sm = sm->next) {
for (SigMatch *sm = list; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
@ -1045,9 +1045,10 @@ static SigMatch *GetMpmForList(const Signature *s, const int list, SigMatch *mpm
* non-negated content present in the sig */
if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
continue;
if (cd->content_len != max_len)
if (cd->content_len != max_len) {
SCLogDebug("content_len %u != max_len %u", cd->content_len, max_len);
continue;
}
if (mpm_sm == NULL) {
mpm_sm = sm;
} else {
@ -1074,7 +1075,7 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
if (s->init_data->mpm_sm != NULL)
return;
const int nlists = s->init_data->smlists_array_size;
const int nlists = s->init_data->max_content_list_id + 1;
int pos_sm_list[nlists];
int neg_sm_list[nlists];
memset(pos_sm_list, 0, nlists * sizeof(int));
@ -1084,18 +1085,42 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
/* inspect rule to see if we have the fast_pattern reg to
* force using a sig, otherwise keep stats about the patterns */
for (int list_id = DETECT_SM_LIST_PMATCH; list_id < nlists; list_id++) {
if (s->init_data->smlists[list_id] == NULL)
continue;
if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) {
if (FastPatternSupportEnabledForSigMatchList(de_ctx, DETECT_SM_LIST_PMATCH)) {
for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
if (list_id == DETECT_SM_LIST_POSTMATCH || list_id == DETECT_SM_LIST_TMATCH ||
list_id == DETECT_SM_LIST_SUPPRESS || list_id == DETECT_SM_LIST_THRESHOLD)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
/* fast_pattern set in rule, so using this pattern */
if ((cd->flags & DETECT_CONTENT_FAST_PATTERN)) {
SetMpm(s, sm, DETECT_SM_LIST_PMATCH);
return;
}
if (!FastPatternSupportEnabledForSigMatchList(de_ctx, list_id))
if (cd->flags & DETECT_CONTENT_NEGATED) {
neg_sm_list[DETECT_SM_LIST_PMATCH] = 1;
neg_sm_list_cnt++;
} else {
pos_sm_list[DETECT_SM_LIST_PMATCH] = 1;
pos_sm_list_cnt++;
}
}
}
}
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
const int list_id = s->init_data->buffers[x].id;
SCLogDebug("%u: list_id %d: %s", s->id, list_id,
DetectEngineBufferTypeGetNameById(de_ctx, list_id));
if (!FastPatternSupportEnabledForSigMatchList(de_ctx, list_id)) {
SCLogDebug("skip");
continue;
}
for (SigMatch *sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) {
for (SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
@ -1112,10 +1137,14 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
} else {
pos_sm_list[list_id] = 1;
pos_sm_list_cnt++;
SCLogDebug("pos added for %d", list_id);
}
}
SCLogDebug("ok");
}
SCLogDebug("neg_sm_list_cnt %d pos_sm_list_cnt %d", neg_sm_list_cnt, pos_sm_list_cnt);
/* prefer normal not-negated over negated */
int *curr_sm_list = NULL;
int skip_negated_content = 1;
@ -1146,43 +1175,86 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
if (curr_sm_list[tmp->list_id] == 0)
continue;
final_sm_list[count_final_sm_list++] = tmp->list_id;
SCLogDebug("tmp->list_id %d", tmp->list_id);
}
if (count_final_sm_list != 0)
break;
}
BUG_ON(count_final_sm_list == 0);
SCLogDebug("count_final_sm_list %d skip_negated_content %d", count_final_sm_list,
skip_negated_content);
uint16_t max_len = 0;
for (int i = 0; i < count_final_sm_list; i++) {
if (final_sm_list[i] >= (int)s->init_data->smlists_array_size)
continue;
SCLogDebug("i %d final_sm_list[i] %d", i, final_sm_list[i]);
for (SigMatch *sm = s->init_data->smlists[final_sm_list[i]]; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
if (final_sm_list[i] == DETECT_SM_LIST_PMATCH) {
for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
/* skip_negated_content is only set if there's absolutely no
* non-negated content present in the sig */
if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
continue;
if (max_len < cd->content_len)
max_len = cd->content_len;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
/* skip_negated_content is only set if there's absolutely no
* non-negated content present in the sig */
if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
continue;
max_len = MAX(max_len, cd->content_len);
}
} else {
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
const int list_id = s->init_data->buffers[x].id;
if (final_sm_list[i] == list_id) {
SCLogDebug("%u: list_id %d: %s", s->id, list_id,
DetectEngineBufferTypeGetNameById(de_ctx, list_id));
for (SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
/* skip_negated_content is only set if there's absolutely no
* non-negated content present in the sig */
if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
continue;
max_len = MAX(max_len, cd->content_len);
}
}
}
}
}
SigMatch *mpm_sm = NULL;
int mpm_sm_list = -1;
for (int i = 0; i < count_final_sm_list; i++) {
if (final_sm_list[i] >= (int)s->init_data->smlists_array_size)
continue;
/* GetMpmForList may keep `mpm_sm` the same, so track if it changed */
SigMatch *prev_mpm_sm = mpm_sm;
mpm_sm = GetMpmForList(s, final_sm_list[i], mpm_sm, max_len, skip_negated_content);
if (mpm_sm != prev_mpm_sm) {
mpm_sm_list = final_sm_list[i];
SCLogDebug("i %d", i);
if (final_sm_list[i] == DETECT_SM_LIST_PMATCH) {
/* GetMpmForList may keep `mpm_sm` the same, so track if it changed */
SigMatch *prev_mpm_sm = mpm_sm;
mpm_sm = GetMpmForList(s, s->init_data->smlists[DETECT_SM_LIST_PMATCH], mpm_sm, max_len,
skip_negated_content);
if (mpm_sm != prev_mpm_sm) {
mpm_sm_list = final_sm_list[i];
}
} else {
SCLogDebug(
"%u: %s", s->id, DetectEngineBufferTypeGetNameById(de_ctx, final_sm_list[i]));
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
const int list_id = s->init_data->buffers[x].id;
if (final_sm_list[i] == list_id) {
SCLogDebug("%u: list_id %d: %s", s->id, list_id,
DetectEngineBufferTypeGetNameById(de_ctx, list_id));
/* GetMpmForList may keep `mpm_sm` the same, so track if it changed */
SigMatch *prev_mpm_sm = mpm_sm;
mpm_sm = GetMpmForList(s, s->init_data->buffers[x].head, mpm_sm, max_len,
skip_negated_content);
SCLogDebug("mpm_sm %p from %p", mpm_sm, s->init_data->buffers[x].head);
if (mpm_sm != prev_mpm_sm) {
mpm_sm_list = list_id;
}
}
}
}
}
@ -2444,6 +2516,7 @@ void EngineAnalysisAddAllRulePatterns(DetectEngineCtx *de_ctx, const Signature *
const DetectEngineAppInspectionEngine *app = s->app_inspect;
for (; app != NULL; app = app->next) {
DEBUG_VALIDATE_BUG_ON(app->smd == NULL);
SigMatchData *smd = app->smd;
do {
switch (smd->type) {

@ -622,7 +622,7 @@ static int DeStateSigTest02(void)
FAIL_IF_NULL(tx_de_state);
FAIL_IF(tx_de_state->dir_state[0].cnt != 1);
/* http_header(mpm): 5, uri: 3, method: 6, cookie: 7 */
uint32_t expected_flags = (BIT_U32(5) | BIT_U32(3) | BIT_U32(6) |BIT_U32(7));
uint32_t expected_flags = (BIT_U32(5) | BIT_U32(3) | BIT_U32(6) | BIT_U32(4));
FAIL_IF(tx_de_state->dir_state[0].head->store[0].flags != expected_flags);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4);

@ -233,6 +233,7 @@ void DetectAppLayerInspectEngineRegister2(const char *name,
if (sm_list == -1) {
FatalError("failed to register inspect engine %s", name);
}
SCLogDebug("name %s id %d", name, sm_list);
if ((alproto >= ALPROTO_FAILED) ||
(!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) ||
@ -574,222 +575,237 @@ static void AppendStreamInspectEngine(
SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
}
/**
* \note for the file inspect engine, the id DE_STATE_ID_FILE_INSPECT
* is assigned.
*/
int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature *s)
static void AppendFrameInspectEngine(DetectEngineCtx *de_ctx,
const DetectEngineFrameInspectionEngine *u, Signature *s, SigMatchData *smd,
const int mpm_list)
{
const int nlists = s->init_data->smlists_array_size;
SigMatchData *ptrs[nlists];
memset(&ptrs, 0, (nlists * sizeof(SigMatchData *)));
bool prepend = false;
const int mpm_list = s->init_data->mpm_sm ? s->init_data->mpm_sm_list : -1;
if (u->alproto == ALPROTO_UNKNOWN) {
/* special case, inspect engine applies to all protocols */
} else if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, u->alproto))
return;
const int files_id = DetectBufferTypeGetByName("files");
if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
if (u->dir == 1)
return;
} else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
if (u->dir == 0)
return;
}
/* convert lists to SigMatchData arrays */
int i = 0;
for (i = DETECT_SM_LIST_DYNAMIC_START; i < nlists; i++) {
if (s->init_data->smlists[i] == NULL)
continue;
DetectEngineFrameInspectionEngine *new_engine =
SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
if (unlikely(new_engine == NULL)) {
exit(EXIT_FAILURE);
}
if (mpm_list == u->sm_list) {
SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, u->sm_list));
prepend = true;
new_engine->mpm = true;
}
ptrs[i] = SigMatchList2DataArray(s->init_data->smlists[i]);
SCLogDebug("ptrs[%d] is set", i);
}
/* set up inspect engines */
const DetectEngineFrameInspectionEngine *u = de_ctx->frame_inspect_engines;
while (u != NULL) {
SCLogDebug("u %p sm_list %u nlists %u ptrs[] %p", u, u->sm_list, nlists,
u->sm_list < nlists ? ptrs[u->sm_list] : NULL);
if (u->sm_list < nlists && ptrs[u->sm_list] != NULL) {
bool prepend = false;
if (u->alproto == ALPROTO_UNKNOWN) {
/* special case, inspect engine applies to all protocols */
} else if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, u->alproto))
goto next_engine;
if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
if (u->dir == 1)
goto next_engine;
} else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
if (u->dir == 0)
goto next_engine;
}
DetectEngineFrameInspectionEngine *new_engine =
SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
if (unlikely(new_engine == NULL)) {
exit(EXIT_FAILURE);
}
if (mpm_list == u->sm_list) {
SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, u->sm_list));
prepend = true;
new_engine->mpm = true;
}
new_engine->type = u->type;
new_engine->sm_list = u->sm_list;
new_engine->sm_list_base = u->sm_list_base;
new_engine->smd = smd;
new_engine->v1 = u->v1;
SCLogDebug("sm_list %d new_engine->v1 %p/%p", new_engine->sm_list, new_engine->v1.Callback,
new_engine->v1.transforms);
new_engine->type = u->type;
new_engine->sm_list = u->sm_list;
new_engine->sm_list_base = u->sm_list_base;
new_engine->smd = ptrs[new_engine->sm_list];
new_engine->v1 = u->v1;
SCLogDebug("sm_list %d new_engine->v1 %p/%p", new_engine->sm_list,
new_engine->v1.Callback, new_engine->v1.transforms);
if (s->frame_inspect == NULL) {
s->frame_inspect = new_engine;
} else if (prepend) {
new_engine->next = s->frame_inspect;
s->frame_inspect = new_engine;
} else {
DetectEngineFrameInspectionEngine *a = s->frame_inspect;
while (a->next != NULL) {
a = a->next;
}
new_engine->next = a->next;
a->next = new_engine;
}
if (s->frame_inspect == NULL) {
s->frame_inspect = new_engine;
} else if (prepend) {
new_engine->next = s->frame_inspect;
s->frame_inspect = new_engine;
} else {
DetectEngineFrameInspectionEngine *a = s->frame_inspect;
while (a->next != NULL) {
a = a->next;
}
next_engine:
u = u->next;
new_engine->next = a->next;
a->next = new_engine;
}
}
/* set up pkt inspect engines */
const DetectEnginePktInspectionEngine *e = de_ctx->pkt_inspect_engines;
while (e != NULL) {
SCLogDebug("e %p sm_list %u nlists %u ptrs[] %p", e, e->sm_list, nlists, e->sm_list < nlists ? ptrs[e->sm_list] : NULL);
if (e->sm_list < nlists && ptrs[e->sm_list] != NULL) {
bool prepend = false;
static void AppendPacketInspectEngine(DetectEngineCtx *de_ctx,
const DetectEnginePktInspectionEngine *e, Signature *s, SigMatchData *smd,
const int mpm_list)
{
bool prepend = false;
DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
if (unlikely(new_engine == NULL)) {
exit(EXIT_FAILURE);
}
if (mpm_list == e->sm_list) {
SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, e->sm_list));
prepend = true;
new_engine->mpm = true;
}
DetectEnginePktInspectionEngine *new_engine =
SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
if (unlikely(new_engine == NULL)) {
exit(EXIT_FAILURE);
}
if (mpm_list == e->sm_list) {
SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, e->sm_list));
prepend = true;
new_engine->mpm = true;
}
new_engine->sm_list = e->sm_list;
new_engine->sm_list_base = e->sm_list_base;
new_engine->smd = ptrs[new_engine->sm_list];
new_engine->v1 = e->v1;
SCLogDebug("sm_list %d new_engine->v1 %p/%p/%p",
new_engine->sm_list, new_engine->v1.Callback,
new_engine->v1.GetData, new_engine->v1.transforms);
if (s->pkt_inspect == NULL) {
s->pkt_inspect = new_engine;
} else if (prepend) {
new_engine->next = s->pkt_inspect;
s->pkt_inspect = new_engine;
} else {
DetectEnginePktInspectionEngine *a = s->pkt_inspect;
while (a->next != NULL) {
a = a->next;
}
new_engine->next = a->next;
a->next = new_engine;
}
new_engine->sm_list = e->sm_list;
new_engine->sm_list_base = e->sm_list_base;
new_engine->smd = smd;
new_engine->v1 = e->v1;
SCLogDebug("sm_list %d new_engine->v1 %p/%p/%p", new_engine->sm_list, new_engine->v1.Callback,
new_engine->v1.GetData, new_engine->v1.transforms);
if (s->pkt_inspect == NULL) {
s->pkt_inspect = new_engine;
} else if (prepend) {
new_engine->next = s->pkt_inspect;
s->pkt_inspect = new_engine;
} else {
DetectEnginePktInspectionEngine *a = s->pkt_inspect;
while (a->next != NULL) {
a = a->next;
}
e = e->next;
new_engine->next = a->next;
a->next = new_engine;
}
}
bool head_is_mpm = false;
uint8_t last_id = DE_STATE_FLAG_BASE;
const DetectEngineAppInspectionEngine *t = de_ctx->app_inspect_engines;
while (t != NULL) {
bool prepend = false;
static void AppendAppInspectEngine(DetectEngineCtx *de_ctx,
const DetectEngineAppInspectionEngine *t, Signature *s, SigMatchData *smd,
const int mpm_list, const int files_id, uint8_t *last_id, bool *head_is_mpm)
{
if (t->alproto == ALPROTO_UNKNOWN) {
/* special case, inspect engine applies to all protocols */
} else if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, t->alproto))
return;
if (t->sm_list >= nlists)
goto next;
if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
if (t->dir == 1)
return;
} else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
if (t->dir == 0)
return;
}
SCLogDebug("app engine: t %p t->id %u => alproto:%s files:%s", t, t->id,
AppProtoToString(t->alproto), BOOL2STR(t->sm_list == files_id));
if (ptrs[t->sm_list] == NULL)
goto next;
DetectEngineAppInspectionEngine *new_engine =
SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
if (unlikely(new_engine == NULL)) {
exit(EXIT_FAILURE);
}
bool prepend = false;
if (mpm_list == t->sm_list) {
SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, t->sm_list));
prepend = true;
*head_is_mpm = true;
new_engine->mpm = true;
}
SCLogDebug("ptrs[%d] is set", t->sm_list);
new_engine->alproto = t->alproto;
new_engine->dir = t->dir;
new_engine->sm_list = t->sm_list;
new_engine->sm_list_base = t->sm_list_base;
new_engine->smd = smd;
new_engine->progress = t->progress;
new_engine->v2 = t->v2;
SCLogDebug("sm_list %d new_engine->v2 %p/%p/%p", new_engine->sm_list, new_engine->v2.Callback,
new_engine->v2.GetData, new_engine->v2.transforms);
if (t->alproto == ALPROTO_UNKNOWN) {
/* special case, inspect engine applies to all protocols */
} else if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, t->alproto))
goto next;
if (s->app_inspect == NULL) {
s->app_inspect = new_engine;
if (new_engine->sm_list == files_id) {
new_engine->id = DE_STATE_ID_FILE_INSPECT;
SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
} else {
new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */
SCLogDebug("sid %u: engine %p/%u %s", s->id, new_engine, new_engine->id,
DetectEngineBufferTypeGetNameById(de_ctx, t->sm_list));
}
if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
if (t->dir == 1)
goto next;
} else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
if (t->dir == 0)
goto next;
/* prepend engine if forced or if our engine has a lower progress. */
} else if (prepend || (!(*head_is_mpm) && s->app_inspect->progress > new_engine->progress)) {
new_engine->next = s->app_inspect;
s->app_inspect = new_engine;
if (new_engine->sm_list == files_id) {
new_engine->id = DE_STATE_ID_FILE_INSPECT;
SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
} else {
new_engine->id = ++(*last_id);
SCLogDebug("sid %u: engine %p/%u %s", s->id, new_engine, new_engine->id,
DetectEngineBufferTypeGetNameById(de_ctx, t->sm_list));
}
DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
if (unlikely(new_engine == NULL)) {
exit(EXIT_FAILURE);
} else {
DetectEngineAppInspectionEngine *a = s->app_inspect;
while (a->next != NULL) {
if (a->next && a->next->progress > new_engine->progress) {
break;
}
a = a->next;
}
if (mpm_list == t->sm_list) {
SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, t->sm_list));
prepend = true;
head_is_mpm = true;
new_engine->mpm = true;
new_engine->next = a->next;
a->next = new_engine;
if (new_engine->sm_list == files_id) {
new_engine->id = DE_STATE_ID_FILE_INSPECT;
SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
} else {
new_engine->id = ++(*last_id);
SCLogDebug("sid %u: engine %p/%u %s", s->id, new_engine, new_engine->id,
DetectEngineBufferTypeGetNameById(de_ctx, t->sm_list));
}
}
new_engine->alproto = t->alproto;
new_engine->dir = t->dir;
new_engine->sm_list = t->sm_list;
new_engine->sm_list_base = t->sm_list_base;
new_engine->smd = ptrs[new_engine->sm_list];
new_engine->progress = t->progress;
new_engine->v2 = t->v2;
SCLogDebug("sm_list %d new_engine->v2 %p/%p/%p",
new_engine->sm_list, new_engine->v2.Callback,
new_engine->v2.GetData, new_engine->v2.transforms);
if (s->app_inspect == NULL) {
s->app_inspect = new_engine;
if (new_engine->sm_list == files_id) {
SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
new_engine->id = DE_STATE_ID_FILE_INSPECT;
} else {
new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */
}
SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
/* prepend engine if forced or if our engine has a lower progress. */
} else if (prepend || (!head_is_mpm && s->app_inspect->progress > new_engine->progress)) {
new_engine->next = s->app_inspect;
s->app_inspect = new_engine;
if (new_engine->sm_list == files_id) {
SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
new_engine->id = DE_STATE_ID_FILE_INSPECT;
} else {
new_engine->id = ++last_id;
}
s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH;
}
} else {
DetectEngineAppInspectionEngine *a = s->app_inspect;
while (a->next != NULL) {
if (a->next && a->next->progress > new_engine->progress) {
break;
}
/**
* \note for the file inspect engine, the id DE_STATE_ID_FILE_INSPECT
* is assigned.
*/
int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature *s)
{
const int mpm_list = s->init_data->mpm_sm ? s->init_data->mpm_sm_list : -1;
const int files_id = DetectBufferTypeGetByName("files");
bool head_is_mpm = false;
uint8_t last_id = DE_STATE_FLAG_BASE;
a = a->next;
}
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
SigMatchData *smd = SigMatchList2DataArray(s->init_data->buffers[x].head);
SCLogDebug("smd %p, id %u", smd, s->init_data->buffers[x].id);
new_engine->next = a->next;
a->next = new_engine;
if (new_engine->sm_list == files_id) {
SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
new_engine->id = DE_STATE_ID_FILE_INSPECT;
} else {
new_engine->id = ++last_id;
const DetectBufferType *b =
DetectEngineBufferTypeGetById(de_ctx, s->init_data->buffers[x].id);
if (b == NULL)
FatalError("unknown buffer");
if (b->frame) {
for (const DetectEngineFrameInspectionEngine *u = de_ctx->frame_inspect_engines;
u != NULL; u = u->next) {
if (u->sm_list == s->init_data->buffers[x].id) {
AppendFrameInspectEngine(de_ctx, u, s, smd, mpm_list);
}
}
} else if (b->packet) {
/* set up pkt inspect engines */
for (const DetectEnginePktInspectionEngine *e = de_ctx->pkt_inspect_engines; e != NULL;
e = e->next) {
SCLogDebug("e %p sm_list %u", e, e->sm_list);
if (e->sm_list == s->init_data->buffers[x].id) {
AppendPacketInspectEngine(de_ctx, e, s, smd, mpm_list);
}
}
} else {
SCLogDebug("app %s id %u parent %u rule %u xforms %u", b->name, b->id, b->parent_id,
s->init_data->buffers[x].id, b->transforms.cnt);
for (const DetectEngineAppInspectionEngine *t = de_ctx->app_inspect_engines; t != NULL;
t = t->next) {
if (t->sm_list == s->init_data->buffers[x].id) {
AppendAppInspectEngine(
de_ctx, t, s, smd, mpm_list, files_id, &last_id, &head_is_mpm);
}
}
}
SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH;
next:
t = t->next;
}
if ((s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) &&
@ -836,64 +852,91 @@ next:
*/
void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signature *s)
{
int nlists = 0;
int engines = 0;
DetectEngineAppInspectionEngine *ie = s->app_inspect;
while (ie) {
nlists = MAX(ie->sm_list + 1, nlists);
ie = ie->next;
engines++;
}
DetectEnginePktInspectionEngine *e = s->pkt_inspect;
while (e) {
nlists = MAX(e->sm_list + 1, nlists);
e = e->next;
engines++;
}
DetectEngineFrameInspectionEngine *u = s->frame_inspect;
while (u) {
nlists = MAX(u->sm_list + 1, nlists);
u = u->next;
engines++;
}
if (nlists == 0) {
if (engines == 0) {
BUG_ON(s->pkt_inspect);
BUG_ON(s->frame_inspect);
return;
}
SigMatchData *ptrs[nlists];
memset(&ptrs, 0, (nlists * sizeof(SigMatchData *)));
SigMatchData *bufs[engines];
memset(&bufs, 0, (engines * sizeof(SigMatchData *)));
int arrays = 0;
/* free engines and put smd in the array */
ie = s->app_inspect;
while (ie) {
DetectEngineAppInspectionEngine *next = ie->next;
BUG_ON(ptrs[ie->sm_list] != NULL && ptrs[ie->sm_list] != ie->smd);
ptrs[ie->sm_list] = ie->smd;
bool skip = false;
for (int i = 0; i < arrays; i++) {
if (bufs[i] == ie->smd) {
skip = true;
break;
}
}
if (!skip) {
bufs[arrays++] = ie->smd;
}
SCFree(ie);
ie = next;
}
e = s->pkt_inspect;
while (e) {
DetectEnginePktInspectionEngine *next = e->next;
ptrs[e->sm_list] = e->smd;
bool skip = false;
for (int i = 0; i < arrays; i++) {
if (bufs[i] == e->smd) {
skip = true;
break;
}
}
if (!skip) {
bufs[arrays++] = e->smd;
}
SCFree(e);
e = next;
}
u = s->frame_inspect;
while (u) {
DetectEngineFrameInspectionEngine *next = u->next;
ptrs[u->sm_list] = u->smd;
bool skip = false;
for (int i = 0; i < arrays; i++) {
if (bufs[i] == u->smd) {
skip = true;
break;
}
}
if (!skip) {
bufs[arrays++] = u->smd;
}
SCFree(u);
u = next;
}
/* free the smds */
for (int i = 0; i < nlists; i++)
{
if (ptrs[i] == NULL)
for (int i = 0; i < engines; i++) {
if (bufs[i] == NULL)
continue;
SigMatchData *smd = ptrs[i];
while(1) {
SigMatchData *smd = bufs[i];
while (1) {
if (sigmatch_table[smd->type].Free != NULL) {
sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
}
@ -901,7 +944,7 @@ void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signa
break;
smd++;
}
SCFree(ptrs[i]);
SCFree(bufs[i]);
}
}
@ -1036,6 +1079,16 @@ int DetectBufferTypeRegister(const char *name)
}
}
void DetectBufferTypeSupportsMultiInstance(const char *name)
{
BUG_ON(g_buffer_type_reg_closed);
DetectBufferTypeRegister(name);
DetectBufferType *exists = DetectBufferTypeLookupByName(name);
BUG_ON(!exists);
exists->multi_instance = true;
SCLogDebug("%p %s -- %d supports multi instance", exists, name, exists->id);
}
void DetectBufferTypeSupportsFrames(const char *name)
{
BUG_ON(g_buffer_type_reg_closed);
@ -1234,6 +1287,15 @@ void DetectEngineBufferTypeSupportsTransformations(DetectEngineCtx *de_ctx, cons
SCLogDebug("%p %s -- %d supports transformations", exists, name, exists->id);
}
bool DetectEngineBufferTypeSupportsMultiInstanceGetById(const DetectEngineCtx *de_ctx, const int id)
{
const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
if (map == NULL)
return false;
SCLogDebug("map %p id %d multi_instance? %s", map, id, BOOL2STR(map->multi_instance));
return map->multi_instance;
}
bool DetectEngineBufferTypeSupportsPacketGetById(const DetectEngineCtx *de_ctx, const int id)
{
const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
@ -1292,27 +1354,31 @@ bool DetectEngineBufferRunValidateCallback(
SigMatch *DetectBufferGetFirstSigMatch(const Signature *s, const uint32_t buf_id)
{
const uint32_t nlists = s->init_data->smlists_array_size;
if (buf_id < nlists) {
return s->init_data->smlists[buf_id];
for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
if (buf_id == s->init_data->buffers[i].id) {
return s->init_data->buffers[i].head;
}
}
return NULL;
}
SigMatch *DetectBufferGetLastSigMatch(const Signature *s, const uint32_t buf_id)
{
const uint32_t nlists = s->init_data->smlists_array_size;
if (buf_id < nlists) {
return s->init_data->smlists_tail[buf_id];
SigMatch *last = NULL;
for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
if (buf_id == s->init_data->buffers[i].id) {
last = s->init_data->buffers[i].tail;
}
}
return NULL;
return last;
}
bool DetectBufferIsPresent(const Signature *s, const uint32_t buf_id)
{
const uint32_t nlists = s->init_data->smlists_array_size;
if (buf_id < nlists) {
return s->init_data->smlists_tail[buf_id] != NULL;
for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
if (buf_id == s->init_data->buffers[i].id) {
return true;
}
}
return false;
}
@ -1321,6 +1387,11 @@ int DetectBufferSetActiveList(DetectEngineCtx *de_ctx, Signature *s, const int l
{
BUG_ON(s->init_data == NULL);
if (s->init_data->list == DETECT_SM_LIST_BASE64_DATA) {
SCLogError("Rule buffer cannot be reset after base64_data.");
return -1;
}
if (s->init_data->list && s->init_data->transforms.cnt) {
SCLogError("no matches following transform(s)");
return -1;
@ -1328,6 +1399,53 @@ int DetectBufferSetActiveList(DetectEngineCtx *de_ctx, Signature *s, const int l
s->init_data->list = list;
s->init_data->list_set = true;
// check if last has matches -> if no, error
if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
SCLogError("previous sticky buffer has no matches");
return -1;
}
for (uint32_t x = 0; x < s->init_data->buffers_size; x++) {
SignatureInitDataBuffer *b = &s->init_data->buffers[x];
for (SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
SCLogDebug(
"buf:%p: id:%u: '%s' pos %u", b, b->id, sigmatch_table[sm->type].name, sm->idx);
}
if ((uint32_t)list == b->id) {
SCLogDebug("found buffer %p for list %d", b, list);
if (s->init_data->buffers[x].sm_init) {
s->init_data->buffers[x].sm_init = false;
SCLogDebug("sm_init was true for %p list %d", b, list);
s->init_data->curbuf = b;
return 0;
} else if (DetectEngineBufferTypeSupportsMultiInstanceGetById(de_ctx, list)) {
// fall through
} else {
SCLogWarning("duplicate instance for %s in '%s'",
DetectEngineBufferTypeGetNameById(de_ctx, list), s->sig_str);
s->init_data->curbuf = b;
return 0;
}
}
}
if (list < DETECT_SM_LIST_MAX)
return 0;
if (SignatureInitDataBufferCheckExpand(s) < 0) {
SCLogError("failed to expand rule buffer array");
return -1;
}
/* initialize new buffer */
s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++];
s->init_data->curbuf->id = list;
s->init_data->curbuf->head = NULL;
s->init_data->curbuf->tail = NULL;
SCLogDebug("new: idx %u list %d set up curbuf %p", s->init_data->buffer_index - 1, list,
s->init_data->curbuf);
return 0;
}
@ -1356,6 +1474,21 @@ int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
s->init_data->list_set = false;
// reset transforms now that we've set up the list
s->init_data->transforms.cnt = 0;
if (s->init_data->curbuf && s->init_data->curbuf->head != NULL) {
if (SignatureInitDataBufferCheckExpand(s) < 0) {
SCLogError("failed to expand rule buffer array");
return -1;
}
s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++];
}
if (s->init_data->curbuf == NULL) {
SCLogError("failed to setup buffer");
DEBUG_VALIDATE_BUG_ON(1);
SCReturnInt(-1);
}
s->init_data->curbuf->id = new_list;
SCLogDebug("new list after applying transforms: %u", new_list);
}
SCReturnInt(0);

@ -51,6 +51,7 @@ void DetectBufferTypeSupportsMpm(const char *name);
void DetectBufferTypeSupportsPacket(const char *name);
void DetectBufferTypeSupportsFrames(const char *name);
void DetectBufferTypeSupportsTransformations(const char *name);
void DetectBufferTypeSupportsMultiInstance(const char *name);
int DetectBufferTypeMaxId(void);
void DetectBufferTypeCloseRegistration(void);
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc);
@ -69,6 +70,8 @@ const char *DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, con
const DetectBufferType *DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id);
bool DetectEngineBufferTypeSupportsMpmGetById(const DetectEngineCtx *de_ctx, const int id);
bool DetectEngineBufferTypeSupportsPacketGetById(const DetectEngineCtx *de_ctx, const int id);
bool DetectEngineBufferTypeSupportsMultiInstanceGetById(
const DetectEngineCtx *de_ctx, const int id);
const char *DetectEngineBufferTypeGetDescriptionById(const DetectEngineCtx *de_ctx, const int id);
const DetectBufferType *DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id);
int DetectEngineBufferTypeGetByIdTransforms(
@ -192,7 +195,6 @@ int WARN_UNUSED DetectBufferSetActiveList(DetectEngineCtx *de_ctx, Signature *s,
int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s);
SigMatch *DetectBufferGetFirstSigMatch(const Signature *s, const uint32_t buf_id);
SigMatch *DetectBufferGetLastSigMatch(const Signature *s, const uint32_t buf_id);
bool DetectBufferIsPresent(const Signature *s, const uint32_t buf_id);
DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt);

@ -53,7 +53,7 @@ static void DetectFastPatternRegisterTests(void);
static SCFPSupportSMList *g_fp_support_smlist_list = NULL;
/**
* \brief Checks if a particular list(Signature->sm_lists[]) is in the list
* \brief Checks if a particular buffer is in the list
* of lists that need to be searched for a keyword that has fp support.
*
* \param list_id The list id.
@ -259,8 +259,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c
goto error;
}
else { /*allow only one content to have fast_pattern modifier*/
uint32_t list_id = 0;
for (list_id = 0; list_id < s->init_data->smlists_array_size; list_id++) {
for (uint32_t list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) {
SigMatch *sm = NULL;
for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_CONTENT) {
@ -271,7 +270,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c
goto error;
}
}
} /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
}
}
}
cd->flags |= DETECT_CONTENT_FAST_PATTERN;

@ -430,15 +430,9 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
/* fill flowbit array, updating counters per sig */
for (uint32_t i = 0; i < de_ctx->sig_array_len; i++) {
const Signature *s = de_ctx->sig_array[i];
bool has_state = false;
/* see if the signature uses stateful matching */
for (uint32_t x = DETECT_SM_LIST_DYNAMIC_START; x < s->init_data->smlists_array_size; x++) {
if (s->init_data->smlists[x] == NULL)
continue;
has_state = true;
break;
}
bool has_state = (s->init_data->buffer_index != 0);
for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
switch (sm->type) {

@ -179,31 +179,35 @@ static int DetectHttpHHSetup(DetectEngineCtx *de_ctx, Signature *s, const char *
static bool DetectHttpHostValidateCallback(const Signature *s, const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_http_host_buffer_id];
for ( ; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_CONTENT) {
DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "http.host keyword "
"specified along with \"nocase\". "
"The hostname buffer is normalized "
"to lowercase, specifying "
"nocase is redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
} else {
uint32_t u;
for (u = 0; u < cd->content_len; u++) {
if (isupper(cd->content[u]))
break;
}
if (u != cd->content_len) {
*sigerror = "A pattern with "
"uppercase characters detected for http.host. "
"The hostname buffer is normalized to lowercase, "
"please specify a lowercase pattern.";
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_http_host_buffer_id)
continue;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_CONTENT) {
DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "http.host keyword "
"specified along with \"nocase\". "
"The hostname buffer is normalized "
"to lowercase, specifying "
"nocase is redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
} else {
uint32_t u;
for (u = 0; u < cd->content_len; u++) {
if (isupper(cd->content[u]))
break;
}
if (u != cd->content_len) {
*sigerror = "A pattern with "
"uppercase characters detected for http.host. "
"The hostname buffer is normalized to lowercase, "
"please specify a lowercase pattern.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
}
}
}

@ -163,28 +163,32 @@ static int DetectHttpMethodSetupSticky(DetectEngineCtx *de_ctx, Signature *s, co
*/
static bool DetectHttpMethodValidateCallback(const Signature *s, const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_http_method_buffer_id];
for ( ; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_http_method_buffer_id)
continue;
const DetectContentData *cd = (const DetectContentData *)sm->ctx;
if (cd->content && cd->content_len) {
if (cd->content[cd->content_len-1] == 0x20) {
*sigerror = "http_method pattern with trailing space";
SCLogError("%s", *sigerror);
return false;
} else if (cd->content[0] == 0x20) {
*sigerror = "http_method pattern with leading space";
SCLogError("%s", *sigerror);
return false;
} else if (cd->content[cd->content_len-1] == 0x09) {
*sigerror = "http_method pattern with trailing tab";
SCLogError("%s", *sigerror);
return false;
} else if (cd->content[0] == 0x09) {
*sigerror = "http_method pattern with leading tab";
SCLogError("%s", *sigerror);
return false;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (const DetectContentData *)sm->ctx;
if (cd->content && cd->content_len) {
if (cd->content[cd->content_len - 1] == 0x20) {
*sigerror = "http_method pattern with trailing space";
SCLogError("%s", *sigerror);
return false;
} else if (cd->content[0] == 0x20) {
*sigerror = "http_method pattern with leading space";
SCLogError("%s", *sigerror);
return false;
} else if (cd->content[cd->content_len - 1] == 0x09) {
*sigerror = "http_method pattern with trailing tab";
SCLogError("%s", *sigerror);
return false;
} else if (cd->content[0] == 0x09) {
*sigerror = "http_method pattern with leading tab";
SCLogError("%s", *sigerror);
return false;
}
}
}
}

@ -922,42 +922,47 @@ static uint8_t DetectEngineInspectHttp2Header(DetectEngineCtx *de_ctx,
static bool DetectHttp2HeaderValidateCallback(const Signature *s, const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_http2_header_buffer_id];
for ( ; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_http2_header_buffer_id)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
bool escaped = false;
bool namevaluesep = false;
for (size_t i = 0; i < cd->content_len; ++i) {
if (escaped) {
if (cd->content[i] == ' ') {
if (namevaluesep) {
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
bool escaped = false;
bool namevaluesep = false;
for (size_t i = 0; i < cd->content_len; ++i) {
if (escaped) {
if (cd->content[i] == ' ') {
if (namevaluesep) {
*sigerror = "Invalid http2.header string : "
"': ' is a special sequence for separation between name "
"and value "
" and thus can only be present once";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
namevaluesep = true;
} else if (cd->content[i] != ':') {
*sigerror = "Invalid http2.header string : "
"': ' is a special sequence for separation between name and value "
" and thus can only be present once";
"':' is an escaping character for itself, "
"or space for the separation between name and value";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
namevaluesep = true;
} else if (cd->content[i] != ':') {
*sigerror = "Invalid http2.header string : "
"':' is an escaping character for itself, "
"or space for the separation between name and value";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
escaped = false;
} else if (cd->content[i] == ':') {
escaped = true;
}
escaped = false;
} else if(cd->content[i] == ':') {
escaped = true;
}
}
if (escaped) {
*sigerror = "Invalid http2.header string : "
"':' is an escaping character for itself, "
"or space for the separation between name and value";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
if (escaped) {
*sigerror = "Invalid http2.header string : "
"':' is an escaping character for itself, "
"or space for the separation between name and value";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
}
}
return true;

@ -71,6 +71,7 @@
#include "app-layer-detect-proto.h"
#include "action-globals.h"
#include "util-validate.h"
/* Table with all SigMatch registrations */
SigTableElmt sigmatch_table[DETECT_TBLSIZE];
@ -211,27 +212,52 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx,
}
}
pm = DetectGetLastSMByListId(s, sm_list,
DETECT_CONTENT, DETECT_PCRE, -1);
if (pm != NULL) {
if (pm->type == DETECT_CONTENT) {
DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
} else {
DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id == sm_list) {
pm = DetectGetLastSMByListPtr(
s, s->init_data->curbuf->tail, DETECT_CONTENT, DETECT_PCRE, -1);
if (pm != NULL) {
if (pm->type == DETECT_CONTENT) {
DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
} else {
DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
}
}
}
}
s->alproto = alproto;
s->flags |= SIG_FLAG_APPLAYER;
if (s->init_data->curbuf == NULL || (int)s->init_data->curbuf->id != sm_list) {
if (s->init_data->curbuf != NULL && s->init_data->curbuf->head == NULL) {
SCLogError("no matches for previous buffer");
return -1;
}
if (SignatureInitDataBufferCheckExpand(s) < 0) {
SCLogError("failed to expand rule buffer array");
return -1;
}
/* initialize a new buffer */
s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++];
s->init_data->curbuf->id = sm_list;
s->init_data->curbuf->head = NULL;
s->init_data->curbuf->tail = NULL;
SCLogDebug("idx %u list %d set up curbuf %p s->init_data->buffer_index %u",
s->init_data->buffer_index - 1, sm_list, s->init_data->curbuf,
s->init_data->buffer_index);
}
/* transfer the sm from the pmatch list to sm_list */
SigMatchTransferSigMatchAcrossLists(sm,
&s->init_data->smlists[DETECT_SM_LIST_PMATCH],
&s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH],
&s->init_data->smlists[sm_list],
&s->init_data->smlists_tail[sm_list]);
SigMatchTransferSigMatchAcrossLists(sm, &s->init_data->smlists[DETECT_SM_LIST_PMATCH],
&s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], &s->init_data->curbuf->head,
&s->init_data->curbuf->tail);
if (sm->type == DETECT_CONTENT) {
s->init_data->max_content_list_id =
MAX(s->init_data->max_content_list_id, (uint32_t)sm_list);
}
ret = 0;
end:
@ -353,42 +379,74 @@ void SigTableApplyStrictCommandlineOption(const char *str)
* \param new The sig match to append.
* \param list The list to append to.
*/
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
void SigMatchAppendSMToList(Signature *s, SigMatch *new, const int list)
{
if (list > 0 && (uint32_t)list >= s->init_data->smlists_array_size)
{
uint32_t old_size = s->init_data->smlists_array_size;
uint32_t new_size = (uint32_t)list + 1;
void *ptr = SCRealloc(s->init_data->smlists, (new_size * sizeof(SigMatch *)));
if (ptr == NULL)
abort();
s->init_data->smlists = ptr;
ptr = SCRealloc(s->init_data->smlists_tail, (new_size * sizeof(SigMatch *)));
if (ptr == NULL)
abort();
s->init_data->smlists_tail = ptr;
for (uint32_t i = old_size; i < new_size; i++) {
s->init_data->smlists[i] = NULL;
s->init_data->smlists_tail[i] = NULL;
}
s->init_data->smlists_array_size = new_size;
if (new->type == DETECT_CONTENT) {
s->init_data->max_content_list_id = MAX(s->init_data->max_content_list_id, (uint32_t)list);
}
if (s->init_data->smlists[list] == NULL) {
s->init_data->smlists[list] = new;
s->init_data->smlists_tail[list] = new;
new->next = NULL;
new->prev = NULL;
SCLogDebug("s:%p new:%p list:%d: %s, s->init_data->list_set %s s->init_data->list %d", s, new,
list, sigmatch_table[new->type].name, BOOL2STR(s->init_data->list_set),
s->init_data->list);
if (list < DETECT_SM_LIST_MAX) {
if (s->init_data->smlists[list] == NULL) {
s->init_data->smlists[list] = new;
s->init_data->smlists_tail[list] = new;
new->next = NULL;
new->prev = NULL;
} else {
SigMatch *cur = s->init_data->smlists_tail[list];
cur->next = new;
new->prev = cur;
new->next = NULL;
s->init_data->smlists_tail[list] = new;
}
new->idx = s->init_data->sm_cnt;
s->init_data->sm_cnt++;
} else {
SigMatch *cur = s->init_data->smlists_tail[list];
cur->next = new;
new->prev = cur;
new->next = NULL;
s->init_data->smlists_tail[list] = new;
}
/* app-layer-events (and possibly others?) can get here w/o a "list"
* already set up. */
/* unset any existing list if it isn't the same as the new */
if (s->init_data->list != DETECT_SM_LIST_NOTSET && list != s->init_data->list) {
SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list);
s->init_data->list = DETECT_SM_LIST_NOTSET;
}
if ((s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) ||
s->init_data->curbuf == NULL) {
if (SignatureInitDataBufferCheckExpand(s) < 0) {
SCLogError("failed to expand rule buffer array");
// return -1; TODO error handle
}
new->idx = s->init_data->sm_cnt;
s->init_data->sm_cnt++;
/* initialize new buffer */
s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++];
s->init_data->curbuf->id = list;
/* buffer set up by sigmatch is tracked in case we add a stickybuffer for the
* same list. */
s->init_data->curbuf->sm_init = true;
SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
}
BUG_ON(s->init_data->curbuf == NULL);
new->prev = s->init_data->curbuf->tail;
if (s->init_data->curbuf->tail)
s->init_data->curbuf->tail->next = new;
if (s->init_data->curbuf->head == NULL)
s->init_data->curbuf->head = new;
s->init_data->curbuf->tail = new;
new->idx = s->init_data->sm_cnt;
s->init_data->sm_cnt++;
SCLogDebug("appended %s to list %d, rule pos %u (s->init_data->list %d)",
sigmatch_table[new->type].name, list, new->idx, s->init_data->list);
for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) {
SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id,
sigmatch_table[sm->type].name, sm->idx);
}
}
}
void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
@ -439,21 +497,18 @@ SigMatch *DetectGetLastSMFromMpmLists(const DetectEngineCtx *de_ctx, const Signa
SigMatch *sm_new;
uint32_t sm_type;
/* if we have a sticky buffer, use that */
if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
s->init_data->list < (int)s->init_data->smlists_array_size) {
if (!(DetectEngineBufferTypeSupportsMpmGetById(de_ctx, s->init_data->list))) {
return NULL;
for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
const int id = s->init_data->buffers[i].id;
if (DetectEngineBufferTypeSupportsMpmGetById(de_ctx, id)) {
sm_new = DetectGetLastSMByListPtr(s, s->init_data->buffers[i].tail, DETECT_CONTENT, -1);
if (sm_new == NULL)
continue;
if (sm_last == NULL || sm_new->idx > sm_last->idx)
sm_last = sm_new;
}
sm_last = DetectGetLastSMByListPtr(s,
s->init_data->smlists_tail[s->init_data->list],
DETECT_CONTENT, -1);
return sm_last;
}
/* otherwise brute force it */
for (sm_type = 0; sm_type < s->init_data->smlists_array_size; sm_type++) {
for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) {
if (!DetectEngineBufferTypeSupportsMpmGetById(de_ctx, sm_type))
continue;
SigMatch *sm_list = s->init_data->smlists_tail[sm_type];
@ -478,8 +533,30 @@ SigMatch *DetectGetLastSMFromLists(const Signature *s, ...)
SigMatch *sm_last = NULL;
SigMatch *sm_new;
/* otherwise brute force it */
for (int buf_type = 0; buf_type < (int)s->init_data->smlists_array_size; buf_type++) {
SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
s->init_data->list != (int)s->init_data->buffers[x].id) {
SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x,
s->init_data->list, (int)s->init_data->buffers[x].id);
continue;
}
int sm_type;
va_list ap;
va_start(ap, s);
for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
if (sm_new == NULL)
continue;
if (sm_last == NULL || sm_new->idx > sm_last->idx)
sm_last = sm_new;
}
va_end(ap);
}
for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) {
if (s->init_data->smlists[buf_type] == NULL)
continue;
if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
@ -551,27 +628,43 @@ SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...)
SigMatch *sm_new;
int sm_type;
if ((uint32_t)list_id >= s->init_data->smlists_array_size) {
return NULL;
}
SigMatch *sm_list = s->init_data->smlists_tail[list_id];
if (sm_list == NULL)
return NULL;
if ((uint32_t)list_id >= DETECT_SM_LIST_MAX) {
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
sm_new = s->init_data->buffers[x].tail;
if (sm_new == NULL)
continue;
va_list ap;
va_start(ap, list_id);
va_list ap;
va_start(ap, list_id);
for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
{
sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
if (sm_new == NULL)
continue;
if (sm_last == NULL || sm_new->idx > sm_last->idx)
sm_last = sm_new;
}
for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
if (sm_new == NULL)
continue;
if (sm_last == NULL || sm_new->idx > sm_last->idx)
sm_last = sm_new;
}
va_end(ap);
va_end(ap);
}
} else {
SigMatch *sm_list = s->init_data->smlists_tail[list_id];
if (sm_list == NULL)
return NULL;
va_list ap;
va_start(ap, list_id);
for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
if (sm_new == NULL)
continue;
if (sm_last == NULL || sm_new->idx > sm_last->idx)
sm_last = sm_new;
}
va_end(ap);
}
return sm_last;
}
@ -582,12 +675,18 @@ SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...)
*/
SigMatch *DetectGetLastSM(const Signature *s)
{
const int nlists = s->init_data->smlists_array_size;
SigMatch *sm_last = NULL;
SigMatch *sm_new;
int i;
for (i = 0; i < nlists; i ++) {
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
sm_new = s->init_data->buffers[x].tail;
if (sm_new == NULL)
continue;
if (sm_last == NULL || sm_new->idx > sm_last->idx)
sm_last = sm_new;
}
for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
sm_new = s->init_data->smlists_tail[i];
if (sm_new == NULL)
continue;
@ -635,8 +734,16 @@ int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
if (key_sm == NULL)
return -1;
const int nlists = s->init_data->smlists_array_size;
for (int list = 0; list < nlists; list++) {
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
const SigMatch *sm = s->init_data->buffers[x].head;
while (sm != NULL) {
if (sm == key_sm)
return s->init_data->buffers[x].id;
sm = sm->next;
}
}
for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
const SigMatch *sm = s->init_data->smlists[list];
while (sm != NULL) {
if (sm == key_sm)
@ -1271,6 +1378,28 @@ static int SigParse(DetectEngineCtx *de_ctx, Signature *s,
SCReturnInt(ret);
}
/** \brief check if buffers array still has space left, expand if not
*/
int SignatureInitDataBufferCheckExpand(Signature *s)
{
if (s->init_data->buffers_size >= 64)
return -1;
if (s->init_data->buffer_index + 1 == s->init_data->buffers_size) {
void *ptr = SCRealloc(s->init_data->buffers,
(s->init_data->buffers_size + 8) * sizeof(SignatureInitDataBuffer));
if (ptr == NULL)
return -1;
s->init_data->buffers = ptr;
for (uint32_t x = s->init_data->buffers_size; x < s->init_data->buffers_size + 8; x++) {
SignatureInitDataBuffer *b = &s->init_data->buffers[x];
memset(b, 0, sizeof(*b));
}
s->init_data->buffers_size += 8;
}
return 0;
}
Signature *SigAlloc (void)
{
Signature *sig = SCMalloc(sizeof(Signature));
@ -1285,22 +1414,12 @@ Signature *SigAlloc (void)
}
sig->init_data->mpm_sm_list = -1;
sig->init_data->smlists_array_size = DetectBufferTypeMaxId();
SCLogDebug("smlists size %u", sig->init_data->smlists_array_size);
sig->init_data->smlists = SCCalloc(sig->init_data->smlists_array_size, sizeof(SigMatch *));
if (sig->init_data->smlists == NULL) {
SCFree(sig->init_data);
SCFree(sig);
return NULL;
}
sig->init_data->smlists_tail = SCCalloc(sig->init_data->smlists_array_size, sizeof(SigMatch *));
if (sig->init_data->smlists_tail == NULL) {
SCFree(sig->init_data->smlists);
SCFree(sig->init_data);
sig->init_data->buffers = SCCalloc(8, sizeof(SignatureInitDataBuffer));
if (sig->init_data->buffers == NULL) {
SCFree(sig);
return NULL;
}
sig->init_data->buffers_size = 8;
/* assign it to -1, so that we can later check if the value has been
* overwritten after the Signature has been parsed, and if it hasn't been
@ -1420,8 +1539,7 @@ void SigFree(DetectEngineCtx *de_ctx, Signature *s)
}
}
if (s->init_data) {
const int nlists = s->init_data->smlists_array_size;
for (i = 0; i < nlists; i++) {
for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
SigMatch *sm = s->init_data->smlists[i];
while (sm != NULL) {
SigMatch *nsm = sm->next;
@ -1429,11 +1547,20 @@ void SigFree(DetectEngineCtx *de_ctx, Signature *s)
sm = nsm;
}
}
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
SigMatch *sm = s->init_data->buffers[x].head;
while (sm != NULL) {
SigMatch *nsm = sm->next;
SigMatchFree(de_ctx, sm);
sm = nsm;
}
}
SCFree(s->init_data->buffers);
s->init_data->buffers = NULL;
}
SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
if (s->init_data) {
SCFree(s->init_data->smlists);
SCFree(s->init_data->smlists_tail);
SCFree(s->init_data);
s->init_data = NULL;
}
@ -1685,64 +1812,96 @@ SigMatchData* SigMatchList2DataArray(SigMatch *head)
*/
static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
{
uint32_t sig_flags = 0;
const int nlists = s->init_data->smlists_array_size;
SCEnter();
/* check for sticky buffers that were set w/o matches
* e.g. alert ... (file_data; sid:1;) */
if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
if (s->init_data->list >= (int)s->init_data->smlists_array_size ||
s->init_data->smlists[s->init_data->list] == NULL) {
SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
DetectEngineBufferTypeGetNameById(de_ctx, s->init_data->list));
SCReturnInt(0);
}
uint32_t sig_flags = 0;
int nlists = 0;
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
}
nlists += (nlists > 0);
SCLogDebug("nlists %d", nlists);
if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
DetectEngineBufferTypeGetNameById(de_ctx, s->init_data->curbuf->id));
SCReturnInt(0);
}
bool has_frame = false;
bool has_app = false;
bool has_pkt = false;
bool has_pmatch = false;
/* run buffer type validation callbacks if any */
if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
if (!DetectContentPMATCHValidateCallback(s))
SCReturnInt(0);
has_pmatch = true;
}
struct BufferVsDir {
int ts;
int tc;
} bufdir[nlists];
memset(&bufdir, 0, nlists * sizeof(struct BufferVsDir));
int x;
for (x = 0; x < nlists; x++) {
if (s->init_data->smlists[x]) {
const DetectEngineAppInspectionEngine *app = de_ctx->app_inspect_engines;
for ( ; app != NULL; app = app->next) {
if (app->sm_list == x &&
(AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
SCLogDebug("engine %s dir %d alproto %d",
DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list), app->dir,
app->alproto);
bufdir[x].ts += (app->dir == 0);
bufdir[x].tc += (app->dir == 1);
}
}
} bufdir[nlists + 1];
memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
SignatureInitDataBuffer *b = &s->init_data->buffers[x];
const DetectBufferType *bt = DetectEngineBufferTypeGetById(de_ctx, b->id);
if (bt == NULL) {
DEBUG_VALIDATE_BUG_ON(1); // should be impossible
continue;
}
SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
for (SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
}
if (!DetectEngineBufferRunValidateCallback(de_ctx, x, s, &de_ctx->sigerror)) {
SCReturnInt(0);
}
if (b->head == NULL) {
SCLogError("no matches in sticky buffer %s", bt->name);
SCReturnInt(0);
}
has_frame |= bt->frame;
has_app |= (bt->frame == false && bt->packet == false);
has_pkt |= bt->packet;
if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && bt->packet == false) {
SCLogError("Signature combines packet "
"specific matches (like dsize, flags, ttl) with stream / "
"state matching by matching on app layer proto (like using "
"http_* keywords).");
SCReturnInt(0);
}
if (!DetectBsizeValidateContentCallback(s, x)) {
SCReturnInt(0);
const DetectEngineAppInspectionEngine *app = de_ctx->app_inspect_engines;
for (; app != NULL; app = app->next) {
if (app->sm_list == b->id &&
(AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
SCLogDebug("engine %s dir %d alproto %d",
DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list), app->dir,
app->alproto);
SCLogDebug("b->id %d nlists %d", b->id, nlists);
bufdir[b->id].ts += (app->dir == 0);
bufdir[b->id].tc += (app->dir == 1);
}
}
if (!DetectEngineBufferRunValidateCallback(de_ctx, b->id, s, &de_ctx->sigerror)) {
SCReturnInt(0);
}
if (!DetectBsizeValidateContentCallback(s, b)) {
SCReturnInt(0);
}
}
int ts_excl = 0;
int tc_excl = 0;
int dir_amb = 0;
for (x = 0; x < nlists; x++) {
for (int x = 0; x < nlists; x++) {
if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
continue;
ts_excl += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
@ -1785,24 +1944,6 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
SCReturnInt(0);
}
bool has_pmatch = false;
bool has_frame = false;
bool has_app = false;
bool has_pkt = false;
for (int i = 0; i < nlists; i++) {
if (s->init_data->smlists[i] == NULL)
continue;
has_pmatch |= (i == DETECT_SM_LIST_PMATCH);
const DetectBufferType *b = DetectEngineBufferTypeGetById(de_ctx, i);
if (b == NULL)
continue;
has_frame |= b->frame;
has_app |= (b->frame == false && b->packet == false);
has_pkt |= b->packet;
}
if (has_pmatch && has_frame) {
SCLogError("can't mix pure content and frame inspection");
SCReturnInt(0);
@ -1816,23 +1957,6 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
SCReturnInt(0);
}
if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
for (int i = 0; i < nlists; i++) {
if (s->init_data->smlists[i] == NULL)
continue;
if (!(DetectEngineBufferTypeGetNameById(de_ctx, i)))
continue;
if (!(DetectEngineBufferTypeSupportsPacketGetById(de_ctx, i))) {
SCLogError("Signature combines packet "
"specific matches (like dsize, flags, ttl) with stream / "
"state matching by matching on app layer proto (like using "
"http_* keywords).");
SCReturnInt(0);
}
}
}
/* TCP: corner cases:
* - pkt vs stream vs depth/offset
* - pkt vs stream vs stream_size
@ -1861,45 +1985,10 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
}
}
}
if (s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA] != NULL) {
int list;
uint16_t idx = s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA]->idx;
for (list = 0; list < nlists; list++) {
if (list == DETECT_SM_LIST_POSTMATCH ||
list == DETECT_SM_LIST_TMATCH ||
list == DETECT_SM_LIST_SUPPRESS ||
list == DETECT_SM_LIST_THRESHOLD)
{
continue;
}
if (list != DETECT_SM_LIST_BASE64_DATA &&
s->init_data->smlists[list] != NULL) {
if (s->init_data->smlists[list]->idx > idx) {
SCLogError("Rule buffer "
"cannot be reset after base64_data.");
SCReturnInt(0);
}
}
}
}
#ifdef HAVE_LUA
DetectLuaPostSetup(s);
#endif
#ifdef DEBUG
for (int i = 0; i < nlists; i++) {
if (s->init_data->smlists[i] != NULL) {
for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
BUG_ON(sm == sm->prev);
BUG_ON(sm == sm->next);
}
}
}
#endif
if (s->init_data->init_flags & SIG_FLAG_INIT_JA3 && s->alproto != ALPROTO_UNKNOWN &&
s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) {
SCLogError("Cannot have ja3 with protocol %s.", AppProtoToString(s->alproto));
@ -2021,10 +2110,13 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, const char *sigstr,
SigBuildAddressMatchArray(sig);
/* run buffer type callbacks if any */
for (uint32_t x = 0; x < sig->init_data->smlists_array_size; x++) {
for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
if (sig->init_data->smlists[x])
DetectEngineBufferRunSetupCallback(de_ctx, x, sig);
}
for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
DetectEngineBufferRunSetupCallback(de_ctx, sig->init_data->buffers[x].id, sig);
}
/* validate signature, SigValidate will report the error reason */
if (SigValidate(de_ctx, sig) == 0) {

@ -49,6 +49,7 @@ typedef struct DetectParseRegex {
} DetectParseRegex;
/* prototypes */
int SignatureInitDataBufferCheckExpand(Signature *s);
Signature *SigAlloc(void);
void SigFree(DetectEngineCtx *de_ctx, Signature *s);
Signature *SigInit(DetectEngineCtx *, const char *sigstr);

@ -184,39 +184,42 @@ static int PrefilterMpmQuicHashRegister(DetectEngineCtx *de_ctx, SigGroupHead *s
static bool DetectQuicHashValidateCallback(const Signature *s, const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_buffer_id];
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_buffer_id)
continue;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = BUFFER_NAME " should not be used together with "
"nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = BUFFER_NAME " should not be used together with "
"nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
if (cd->content_len != 32) {
*sigerror = "Invalid length of the specified" BUFFER_NAME " (should "
"be 32 characters long). This rule will therefore "
"never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return FALSE;
}
for (size_t i = 0; i < cd->content_len; ++i) {
if (!isxdigit(cd->content[i])) {
*sigerror = "Invalid " BUFFER_NAME
" string (should be string of hexadecimal characters)."
"This rule will therefore never match.";
if (cd->content_len != 32) {
*sigerror = "Invalid length of the specified" BUFFER_NAME " (should "
"be 32 characters long). This rule will therefore "
"never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return FALSE;
return false;
}
for (size_t i = 0; i < cd->content_len; ++i) {
if (!isxdigit(cd->content[i])) {
*sigerror = "Invalid " BUFFER_NAME
" string (should be string of hexadecimal characters)."
"This rule will therefore never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
}
}
}
return TRUE;
return true;
}
void DetectQuicCyuHashRegister(void)

@ -72,28 +72,32 @@ static int DetectSipMethodSetup(DetectEngineCtx *de_ctx, Signature *s, const cha
static bool DetectSipMethodValidateCallback(const Signature *s, const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_buffer_id];
for ( ; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_buffer_id)
continue;
const DetectContentData *cd = (const DetectContentData *)sm->ctx;
if (cd->content && cd->content_len) {
if (cd->content[cd->content_len-1] == 0x20) {
*sigerror = "sip.method pattern with trailing space";
SCLogError("%s", *sigerror);
return true;
} else if (cd->content[0] == 0x20) {
*sigerror = "sip.method pattern with leading space";
SCLogError("%s", *sigerror);
return true;
} else if (cd->content[cd->content_len-1] == 0x09) {
*sigerror = "sip.method pattern with trailing tab";
SCLogError("%s", *sigerror);
return true;
} else if (cd->content[0] == 0x09) {
*sigerror = "sip.method pattern with leading tab";
SCLogError("%s", *sigerror);
return true;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (const DetectContentData *)sm->ctx;
if (cd->content && cd->content_len) {
if (cd->content[cd->content_len - 1] == 0x20) {
*sigerror = "sip.method pattern with trailing space";
SCLogError("%s", *sigerror);
return true;
} else if (cd->content[0] == 0x20) {
*sigerror = "sip.method pattern with leading space";
SCLogError("%s", *sigerror);
return true;
} else if (cd->content[cd->content_len - 1] == 0x09) {
*sigerror = "sip.method pattern with trailing tab";
SCLogError("%s", *sigerror);
return true;
} else if (cd->content[0] == 0x09) {
*sigerror = "sip.method pattern with leading tab";
SCLogError("%s", *sigerror);
return true;
}
}
}
}

@ -120,66 +120,68 @@ static int DetectSshHasshServerSetup(DetectEngineCtx *de_ctx, Signature *s, cons
static bool DetectSshHasshServerHashValidateCallback(const Signature *s, const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_ssh_hassh_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id)
continue;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "ssh.hassh.server should not be used together with "
"nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "ssh.hassh.server should not be used together with "
"nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
if (cd->content_len != 32)
{
*sigerror = "Invalid length of the specified ssh.hassh.server (should "
"be 32 characters long). This rule will therefore "
"never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
for (size_t i = 0; i < cd->content_len; ++i)
{
if(!isxdigit(cd->content[i]))
{
*sigerror = "Invalid ssh.hassh.server string (should be string of hexademical characters)."
"This rule will therefore never match.";
if (cd->content_len != 32) {
*sigerror = "Invalid length of the specified ssh.hassh.server (should "
"be 32 characters long). This rule will therefore "
"never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
for (size_t i = 0; i < cd->content_len; ++i) {
if (!isxdigit(cd->content[i])) {
*sigerror = "Invalid ssh.hassh.server string (should be string of hexademical "
"characters)."
"This rule will therefore never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
}
}
}
return true;
}
static void DetectSshHasshServerHashSetupCallback(const DetectEngineCtx *de_ctx,
Signature *s)
{
SigMatch *sm = s->init_data->smlists[g_ssh_hassh_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
uint32_t u;
for (u = 0; u < cd->content_len; u++)
{
if (isupper(cd->content[u])) {
cd->content[u] = u8_tolower(cd->content[u]);
SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
uint32_t u;
for (u = 0; u < cd->content_len; u++) {
if (isupper(cd->content[u])) {
cd->content[u] = u8_tolower(cd->content[u]);
}
}
}
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
de_ctx->spm_global_thread_ctx);
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx =
SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx);
}
}
}

@ -122,66 +122,68 @@ static int DetectSshHasshSetup(DetectEngineCtx *de_ctx, Signature *s, const char
static bool DetectSshHasshHashValidateCallback(const Signature *s,
const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_ssh_hassh_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id)
continue;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "ssh.hassh should not be used together with "
"nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "ssh.hassh should not be used together with "
"nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
if (cd->content_len != 32)
{
*sigerror = "Invalid length of the specified ssh.hassh (should "
"be 32 characters long). This rule will therefore "
"never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
for (size_t i = 0; i < cd->content_len; ++i)
{
if(!isxdigit(cd->content[i]))
{
*sigerror = "Invalid ssh.hassh string (should be string of hexademical characters)."
"This rule will therefore never match.";
if (cd->content_len != 32) {
*sigerror = "Invalid length of the specified ssh.hassh (should "
"be 32 characters long). This rule will therefore "
"never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
for (size_t i = 0; i < cd->content_len; ++i) {
if (!isxdigit(cd->content[i])) {
*sigerror =
"Invalid ssh.hassh string (should be string of hexademical characters)."
"This rule will therefore never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
}
}
}
return true;
}
static void DetectSshHasshHashSetupCallback(const DetectEngineCtx *de_ctx,
Signature *s)
{
SigMatch *sm = s->init_data->smlists[g_ssh_hassh_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
uint32_t u;
for (u = 0; u < cd->content_len; u++)
{
if (isupper(cd->content[u])) {
cd->content[u] = u8_tolower(cd->content[u]);
SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
uint32_t u;
for (u = 0; u < cd->content_len; u++) {
if (isupper(cd->content[u])) {
cd->content[u] = u8_tolower(cd->content[u]);
}
}
}
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
de_ctx->spm_global_thread_ctx);
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx =
SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx);
}
}
}

@ -163,76 +163,79 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
static bool DetectTlsFingerprintValidateCallback(const Signature *s,
const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_tls_cert_fingerprint_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_fingerprint_buffer_id)
continue;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->content_len != 59) {
*sigerror = "Invalid length of the specified fingerprint. "
"This rule will therefore never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->content_len != 59) {
*sigerror = "Invalid length of the specified fingerprint. "
"This rule will therefore never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
bool have_delimiters = false;
uint32_t u;
for (u = 0; u < cd->content_len; u++)
{
if (cd->content[u] == ':') {
have_delimiters = true;
break;
bool have_delimiters = false;
uint32_t u;
for (u = 0; u < cd->content_len; u++) {
if (cd->content[u] == ':') {
have_delimiters = true;
break;
}
}
}
if (!have_delimiters) {
*sigerror = "No colon delimiters ':' detected in content after "
"tls.cert_fingerprint. This rule will therefore "
"never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
if (!have_delimiters) {
*sigerror = "No colon delimiters ':' detected in content after "
"tls.cert_fingerprint. This rule will therefore "
"never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "tls.cert_fingerprint should not be used together "
"with nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "tls.cert_fingerprint should not be used together "
"with nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
}
}
return true;
}
static void DetectTlsFingerprintSetupCallback(const DetectEngineCtx *de_ctx,
Signature *s)
{
SigMatch *sm = s->init_data->smlists[g_tls_cert_fingerprint_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_fingerprint_buffer_id)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
bool changed = false;
uint32_t u;
for (u = 0; u < cd->content_len; u++)
{
if (isupper(cd->content[u])) {
cd->content[u] = u8_tolower(cd->content[u]);
changed = true;
SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
bool changed = false;
uint32_t u;
for (u = 0; u < cd->content_len; u++) {
if (isupper(cd->content[u])) {
cd->content[u] = u8_tolower(cd->content[u]);
changed = true;
}
}
}
/* recreate the context if changes were made */
if (changed) {
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
de_ctx->spm_global_thread_ctx);
/* recreate the context if changes were made */
if (changed) {
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx =
SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx);
}
}
}
}

@ -162,67 +162,71 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
static bool DetectTlsSerialValidateCallback(const Signature *s,
const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_tls_cert_serial_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_serial_buffer_id)
continue;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "tls.cert_serial should not be used together "
"with nocase, since the rule is automatically "
"uppercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "tls.cert_serial should not be used together "
"with nocase, since the rule is automatically "
"uppercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
/* no need to worry about this if the content is short enough */
if (cd->content_len <= 2)
return true;
uint32_t u;
for (u = 0; u < cd->content_len; u++)
if (cd->content[u] == ':')
/* no need to worry about this if the content is short enough */
if (cd->content_len <= 2)
return true;
*sigerror = "No colon delimiters ':' detected in content after "
"tls.cert_serial. This rule will therefore never "
"match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
uint32_t u;
for (u = 0; u < cd->content_len; u++)
if (cd->content[u] == ':')
return true;
return false;
}
*sigerror = "No colon delimiters ':' detected in content after "
"tls.cert_serial. This rule will therefore never "
"match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
}
return true;
}
static void DetectTlsSerialSetupCallback(const DetectEngineCtx *de_ctx,
Signature *s)
{
SigMatch *sm = s->init_data->smlists[g_tls_cert_serial_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_serial_buffer_id)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
bool changed = false;
uint32_t u;
for (u = 0; u < cd->content_len; u++)
{
if (islower(cd->content[u])) {
cd->content[u] = u8_toupper(cd->content[u]);
changed = true;
SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
bool changed = false;
uint32_t u;
for (u = 0; u < cd->content_len; u++) {
if (islower(cd->content[u])) {
cd->content[u] = u8_toupper(cd->content[u]);
changed = true;
}
}
}
/* recreate the context if changes were made */
if (changed) {
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
de_ctx->spm_global_thread_ctx);
/* recreate the context if changes were made */
if (changed) {
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx =
SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx);
}
}
}
}

@ -164,60 +164,64 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
static bool DetectTlsJa3HashValidateCallback(const Signature *s,
const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_tls_ja3_hash_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3_hash_buffer_id)
continue;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "ja3.hash should not be used together with "
"nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->content_len == SC_MD5_HEX_LEN)
return true;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "ja3.hash should not be used together with "
"nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
*sigerror = "Invalid length of the specified JA3 hash (should "
"be 32 characters long). This rule will therefore "
"never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
if (cd->content_len == SC_MD5_HEX_LEN)
return true;
*sigerror = "Invalid length of the specified JA3 hash (should "
"be 32 characters long). This rule will therefore "
"never match.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
return true;
}
static void DetectTlsJa3HashSetupCallback(const DetectEngineCtx *de_ctx,
Signature *s)
{
SigMatch *sm = s->init_data->smlists[g_tls_ja3_hash_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3_hash_buffer_id)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
bool changed = false;
uint32_t u;
for (u = 0; u < cd->content_len; u++)
{
if (isupper(cd->content[u])) {
cd->content[u] = u8_tolower(cd->content[u]);
changed = true;
SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
bool changed = false;
uint32_t u;
for (u = 0; u < cd->content_len; u++) {
if (isupper(cd->content[u])) {
cd->content[u] = u8_tolower(cd->content[u]);
changed = true;
}
}
}
/* recreate the context if changes were made */
if (changed) {
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
de_ctx->spm_global_thread_ctx);
/* recreate the context if changes were made */
if (changed) {
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx =
SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx);
}
}
}
}

@ -162,60 +162,64 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
static bool DetectTlsJa3SHashValidateCallback(const Signature *s,
const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[g_tls_ja3s_hash_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3s_hash_buffer_id)
continue;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "ja3s.hash should not be used together with "
"nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
}
const DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->content_len == SC_MD5_HEX_LEN)
return true;
if (cd->flags & DETECT_CONTENT_NOCASE) {
*sigerror = "ja3s.hash should not be used together with "
"nocase, since the rule is automatically "
"lowercased anyway which makes nocase redundant.";
SCLogWarning("rule %u: %s", s->id, *sigerror);
*sigerror = "Invalid length of the specified JA3S hash (should "
"be 32 characters long). This rule will therefore "
"never match.";
SCLogError("rule %u: %s", s->id, *sigerror);
return false;
}
if (cd->content_len == SC_MD5_HEX_LEN)
return true;
*sigerror = "Invalid length of the specified JA3S hash (should "
"be 32 characters long). This rule will therefore "
"never match.";
SCLogError("rule %u: %s", s->id, *sigerror);
return false;
}
return true;
}
static void DetectTlsJa3SHashSetupCallback(const DetectEngineCtx *de_ctx,
Signature *s)
{
SigMatch *sm = s->init_data->smlists[g_tls_ja3s_hash_buffer_id];
for ( ; sm != NULL; sm = sm->next)
{
if (sm->type != DETECT_CONTENT)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3s_hash_buffer_id)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
bool changed = false;
uint32_t u;
for (u = 0; u < cd->content_len; u++)
{
if (isupper(cd->content[u])) {
cd->content[u] = u8_tolower(cd->content[u]);
changed = true;
SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
DetectContentData *cd = (DetectContentData *)sm->ctx;
bool changed = false;
uint32_t u;
for (u = 0; u < cd->content_len; u++) {
if (isupper(cd->content[u])) {
cd->content[u] = u8_tolower(cd->content[u]);
changed = true;
}
}
}
/* recreate the context if changes were made */
if (changed) {
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
de_ctx->spm_global_thread_ctx);
/* recreate the context if changes were made */
if (changed) {
SpmDestroyCtx(cd->spm_ctx);
cd->spm_ctx =
SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx);
}
}
}
}

@ -147,86 +147,93 @@ static void DetectUrilenFree(DetectEngineCtx *de_ctx, void *ptr)
*/
void DetectUrilenApplyToContent(Signature *s, int list)
{
uint16_t high = UINT16_MAX;
bool found = false;
SigMatch *sm = s->init_data->smlists[list];
for ( ; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_AL_URILEN)
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)list)
continue;
DetectUrilenData *dd = (DetectUrilenData *)sm->ctx;
switch (dd->du16.mode) {
case DETECT_UINT_LT:
if (dd->du16.arg1 < UINT16_MAX) {
high = dd->du16.arg1 + 1;
}
break;
case DETECT_UINT_LTE:
// fallthrough
case DETECT_UINT_EQ:
high = dd->du16.arg1;
break;
case DETECT_UINT_RA:
if (dd->du16.arg2 < UINT16_MAX) {
high = dd->du16.arg2 + 1;
}
break;
case DETECT_UINT_NE:
// fallthrough
case DETECT_UINT_GTE:
// fallthrough
case DETECT_UINT_GT:
high = UINT16_MAX;
break;
}
found = true;
}
// skip 65535 to avoid mismatch on uri > 64k
if (!found || high == UINT16_MAX)
return;
SCLogDebug("high %u", high);
sm = s->init_data->smlists[list];
for ( ; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT) {
continue;
}
DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd == NULL) {
continue;
uint16_t high = UINT16_MAX;
bool found = false;
for (SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_AL_URILEN)
continue;
DetectUrilenData *dd = (DetectUrilenData *)sm->ctx;
switch (dd->du16.mode) {
case DETECT_UINT_LT:
if (dd->du16.arg1 < UINT16_MAX) {
high = dd->du16.arg1 + 1;
}
break;
case DETECT_UINT_LTE:
// fallthrough
case DETECT_UINT_EQ:
high = dd->du16.arg1;
break;
case DETECT_UINT_RA:
if (dd->du16.arg2 < UINT16_MAX) {
high = dd->du16.arg2 + 1;
}
break;
case DETECT_UINT_NE:
// fallthrough
case DETECT_UINT_GTE:
// fallthrough
case DETECT_UINT_GT:
high = UINT16_MAX;
break;
}
found = true;
}
if (cd->depth == 0 || cd->depth > high) {
cd->depth = high;
cd->flags |= DETECT_CONTENT_DEPTH;
SCLogDebug("updated %u, content %u to have depth %u "
"because of urilen.", s->id, cd->id, cd->depth);
// skip 65535 to avoid mismatch on uri > 64k
if (!found || high == UINT16_MAX)
return;
SCLogDebug("high %u", high);
for (SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT) {
continue;
}
DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd == NULL) {
continue;
}
if (cd->depth == 0 || cd->depth > high) {
cd->depth = high;
cd->flags |= DETECT_CONTENT_DEPTH;
SCLogDebug("updated %u, content %u to have depth %u "
"because of urilen.",
s->id, cd->id, cd->depth);
}
}
}
}
bool DetectUrilenValidateContent(const Signature *s, int list, const char **sigerror)
{
const SigMatch *sm = s->init_data->smlists[list];
for ( ; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT) {
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)list)
continue;
}
DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd == NULL) {
continue;
}
if (cd->depth && cd->depth < cd->content_len) {
*sigerror = "depth or urilen smaller than content len";
SCLogError("depth or urilen %u smaller "
"than content len %u",
cd->depth, cd->content_len);
return false;
for (const SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT) {
continue;
}
DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd == NULL) {
continue;
}
if (cd->depth && cd->depth < cd->content_len) {
*sigerror = "depth or urilen smaller than content len";
SCLogError("depth or urilen %u smaller "
"than content len %u",
cd->depth, cd->content_len);
return false;
}
}
}
return true;

@ -73,7 +73,7 @@ struct SCSigSignatureWrapper_;
/* holds the values for different possible lists in struct Signature.
* These codes are access points to particular lists in the array
* Signature->sm_lists[DETECT_SM_LIST_MAX]. */
* Signature->init_data->smlists[DETECT_SM_LIST_MAX]. */
enum DetectSigmatchListEnum {
/* list for non-payload per packet matches, e.g. ttl, flow keyword */
DETECT_SM_LIST_MATCH = 0,
@ -420,6 +420,7 @@ typedef struct DetectBufferType_ {
bool packet; /**< compat to packet matches */
bool frame; /**< is about Frame inspection */
bool supports_transforms;
bool multi_instance; /**< buffer supports multiple buffer instances per tx */
void (*SetupCallback)(const struct DetectEngineCtx_ *, struct Signature_ *);
bool (*ValidateCallback)(const struct Signature_ *, const char **sigerror);
DetectEngineTransforms transforms;
@ -483,10 +484,15 @@ typedef struct DetectEngineFrameInspectionEngine {
struct DetectEngineFrameInspectionEngine *next;
} DetectEngineFrameInspectionEngine;
#ifdef UNITTESTS
#define sm_lists init_data->smlists
#define sm_lists_tail init_data->smlists_tail
#endif
typedef struct SignatureInitDataBuffer_ {
uint32_t id; /**< buffer id */
bool sm_init; /**< initialized by sigmatch, which is likely something like `urilen:10; http.uri;
content:"abc";`. These need to be in the same list. Unset once `http.uri` is
set up. */
/* sig match list */
SigMatch *head;
SigMatch *tail;
} SignatureInitDataBuffer;
typedef struct SignatureInitData_ {
/** Number of sigmatches. Used for assigning SigMatch::idx */
@ -531,11 +537,19 @@ typedef struct SignatureInitData_ {
int prefilter_list;
uint32_t smlists_array_size;
/* holds all sm lists */
struct SigMatch_ **smlists;
/* holds all sm lists' tails */
struct SigMatch_ **smlists_tail;
/* holds built-in sm lists */
struct SigMatch_ *smlists[DETECT_SM_LIST_MAX];
/* holds built-in sm lists' tails */
struct SigMatch_ *smlists_tail[DETECT_SM_LIST_MAX];
/* Storage for buffers. */
SignatureInitDataBuffer *buffers;
uint32_t buffer_index;
uint32_t buffers_size;
SignatureInitDataBuffer *curbuf;
/* highest list/buffer id which holds a DETECT_CONTENT */
uint32_t max_content_list_id;
} SignatureInitData;
/** \brief Signature container */

Loading…
Cancel
Save