diff --git a/src/detect-bsize.c b/src/detect-bsize.c index 4c89abc3c6..3b3efe87b7 100644 --- a/src/detect-bsize.c +++ b/src/detect-bsize.c @@ -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) { diff --git a/src/detect-bsize.h b/src/detect-bsize.h index 1535c6fdb2..d14bbab056 100644 --- a/src/detect-bsize.h +++ b/src/detect-bsize.h @@ -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__ */ diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 3f95eb39f4..80324fcce6 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -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) { diff --git a/src/detect-bytemath.c b/src/detect-bytemath.c index 58b157289f..abcc1761d4 100644 --- a/src/detect-bytemath.c +++ b/src/detect-bytemath.c @@ -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) { diff --git a/src/detect-content.c b/src/detect-content.c index 8dfa544fbf..536366e940 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -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); } } diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index beb736f471..0ccc408ef7 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -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; diff --git a/src/detect-engine-build.c b/src/detect-engine-build.c index 87e83008fc..f12fef1cbc 100644 --- a/src/detect-engine-build.c +++ b/src/detect-engine-build.c @@ -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; } diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 79c780eda0..d6b8dd92f6 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -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) { diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index db7cfc0ace..aabb02f74d 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -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); diff --git a/src/detect-engine.c b/src/detect-engine.c index 23341087fd..db1bd3b842 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -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); diff --git a/src/detect-engine.h b/src/detect-engine.h index 848aa4abb5..e593fb8cfd 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -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); diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 4f98f507e2..34f4cf4c69 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -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; diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index e4cae2d7e9..72eeaa4f6e 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -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) { diff --git a/src/detect-http-host.c b/src/detect-http-host.c index 8db78f6dc4..6f32044a11 100644 --- a/src/detect-http-host.c +++ b/src/detect-http-host.c @@ -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; + } } } } diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 7b8dbc3c26..0ce246359c 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -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; + } } } } diff --git a/src/detect-http2.c b/src/detect-http2.c index 7b9395710f..7006145031 100644 --- a/src/detect-http2.c +++ b/src/detect-http2.c @@ -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; diff --git a/src/detect-parse.c b/src/detect-parse.c index 108abe581a..2fc44d55bc 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -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) { diff --git a/src/detect-parse.h b/src/detect-parse.h index 95b4514bbc..697cd9754e 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -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); diff --git a/src/detect-quic-cyu-hash.c b/src/detect-quic-cyu-hash.c index c79f3ab2cb..91e58eb543 100644 --- a/src/detect-quic-cyu-hash.c +++ b/src/detect-quic-cyu-hash.c @@ -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) diff --git a/src/detect-sip-method.c b/src/detect-sip-method.c index bb2933e479..fccc8a73f9 100644 --- a/src/detect-sip-method.c +++ b/src/detect-sip-method.c @@ -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; + } } } } diff --git a/src/detect-ssh-hassh-server.c b/src/detect-ssh-hassh-server.c index 4f04287428..29dfedb58d 100644 --- a/src/detect-ssh-hassh-server.c +++ b/src/detect-ssh-hassh-server.c @@ -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); + } } } diff --git a/src/detect-ssh-hassh.c b/src/detect-ssh-hassh.c index a2da4e2c3b..75a88d25d5 100644 --- a/src/detect-ssh-hassh.c +++ b/src/detect-ssh-hassh.c @@ -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); + } } } diff --git a/src/detect-tls-cert-fingerprint.c b/src/detect-tls-cert-fingerprint.c index b459c440ce..bee1d01775 100644 --- a/src/detect-tls-cert-fingerprint.c +++ b/src/detect-tls-cert-fingerprint.c @@ -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); + } } } } diff --git a/src/detect-tls-cert-serial.c b/src/detect-tls-cert-serial.c index be03423d39..19c86be80e 100644 --- a/src/detect-tls-cert-serial.c +++ b/src/detect-tls-cert-serial.c @@ -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); + } } } } diff --git a/src/detect-tls-ja3-hash.c b/src/detect-tls-ja3-hash.c index 8aa1f58f30..7660fde4c2 100644 --- a/src/detect-tls-ja3-hash.c +++ b/src/detect-tls-ja3-hash.c @@ -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); + } } } } diff --git a/src/detect-tls-ja3s-hash.c b/src/detect-tls-ja3s-hash.c index 93dc9e24ab..583566012d 100644 --- a/src/detect-tls-ja3s-hash.c +++ b/src/detect-tls-ja3s-hash.c @@ -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); + } } } } diff --git a/src/detect-urilen.c b/src/detect-urilen.c index 6f7c4da206..9add5838cc 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -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; diff --git a/src/detect.h b/src/detect.h index bcaec38a32..a41b74ed8c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -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 */