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);
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) {
-/* 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
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__ */
*/
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) {
*/
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) {
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);
}
}
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];
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;
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
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);
}
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);
}
}
/* 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);
}
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;
}
{
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)) {
/* 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;
}
/* 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++;
}
}
/* 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;
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;
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;
}
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;
* 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 {
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));
/* 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;
} 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;
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;
+ }
+ }
+ }
}
}
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) {
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);
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)) ||
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) &&
*/
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);
}
break;
smd++;
}
- SCFree(ptrs[i]);
+ SCFree(bufs[i]);
}
}
}
}
+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);
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);
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;
}
{
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;
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;
}
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);
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);
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(
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);
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.
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) {
goto error;
}
}
- } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
+ }
}
}
cd->flags |= DETECT_CONTENT_FAST_PATTERN;
/* 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) {
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;
+ }
}
}
}
*/
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;
+ }
}
}
}
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;
#include "app-layer-detect-proto.h"
#include "action-globals.h"
+#include "util-validate.h"
/* Table with all SigMatch registrations */
SigTableElmt sigmatch_table[DETECT_TBLSIZE];
}
}
- 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:
* \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)
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];
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 &&
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;
}
*/
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;
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)
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));
}
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
}
}
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;
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;
}
*/
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);
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);
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
}
}
}
-
- 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));
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) {
} DetectParseRegex;
/* prototypes */
+int SignatureInitDataBufferCheckExpand(Signature *s);
Signature *SigAlloc(void);
void SigFree(DetectEngineCtx *de_ctx, Signature *s);
Signature *SigInit(DetectEngineCtx *, const char *sigstr);
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)
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;
+ }
}
}
}
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);
+ }
}
}
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);
+ }
}
}
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);
+ }
}
}
}
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);
+ }
}
}
}
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);
+ }
}
}
}
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);
+ }
}
}
}
*/
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;
/* 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,
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;
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 */
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 */