detect/mpm: honor absent in every fast_pattern pass

RetrieveFPForSig stopped at absent and transform_result only while
marking candidate lists; the max_len pass and GetMpmForList walked
every instance of the chosen list to its end. Repeated multi-instance
buffers with no transforms, or with transforms such as to_lowercase,
share a list id, so in "http.request_header; content:"Host";
http.request_header; absent: or_else; content:"<longer>";" the or_else
content became the fast pattern.

Stop at absent and transform_result in all three passes.

Issue: 7313
Issue: 7114
pull/16484/head
Jeff Lucovsky 3 weeks ago
parent 133cf410fd
commit a9d70166ec

@ -1119,10 +1119,20 @@ static void SetMpm(Signature *s, SigMatch *mpm_sm, const int mpm_sm_list)
s->init_data->mpm_sm = mpm_sm;
}
/* absent and transform_result end the part of a buffer that can supply the
* fast_pattern. Repeated buffers can share a list id, so every pass over a
* list's buffers has to stop at them, not just the first. */
static inline bool StopsFastPattern(const SigMatch *sm)
{
return sm->type == DETECT_ABSENT || sm->type == DETECT_TRANSFORM_RESULT;
}
static SigMatch *GetMpmForList(const Signature *s, SigMatch *list, SigMatch *mpm_sm,
uint16_t max_len, bool skip_negated_content)
{
for (SigMatch *sm = list; sm != NULL; sm = sm->next) {
if (StopsFastPattern(sm))
break;
if (sm->type != DETECT_CONTENT)
continue;
@ -1234,7 +1244,7 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
for (SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) {
// a buffer with absent or transform_result cannot use fast_pattern
if (sm->type == DETECT_ABSENT || sm->type == DETECT_TRANSFORM_RESULT)
if (StopsFastPattern(sm))
break;
if (sm->type != DETECT_CONTENT)
continue;
@ -1346,6 +1356,8 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
DetectEngineBufferTypeGetNameById(de_ctx, list_id));
for (SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) {
if (StopsFastPattern(sm))
break;
if (sm->type != DETECT_CONTENT)
continue;

@ -1091,11 +1091,55 @@ static int DetectAbsentTestParse04(void)
PASS;
}
/** \test fast_pattern is not taken from a buffer with absent when a repeated
* buffer shares its list id */
static int DetectAbsentTestParse05(void)
{
const char *sigs[] = {
"alert http any any -> any any (http.request_header; content:\"Host\"; "
"http.request_header; absent: or_else; content:\"a-much-longer-pattern\"; sid:1;)",
"alert http any any -> any any (http.request_header; absent: or_else; "
"content:\"a-much-longer-pattern\"; http.request_header; content:\"Host\"; sid:2;)",
"alert http any any -> any any (http.request_header; to_lowercase; content:\"host\"; "
"http.request_header; to_lowercase; absent: or_else; "
"content:\"a-much-longer-pattern\"; sid:3;)",
};
for (size_t i = 0; i < ARRAY_SIZE(sigs); i++) {
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
Signature *s = DetectEngineAppendSig(de_ctx, sigs[i]);
FAIL_IF_NULL(s);
FAIL_IF_NOT(s->init_data->buffer_index == 2);
FAIL_IF_NOT(s->init_data->buffers[0].id == s->init_data->buffers[1].id);
int mpm_cnt = 0;
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
for (SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (const DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_MPM) {
FAIL_IF_NOT(cd->content_len == 4);
mpm_cnt++;
}
}
}
FAIL_IF_NOT(mpm_cnt == 1);
DetectEngineCtxFree(de_ctx);
}
PASS;
}
void DetectAbsentRegisterTests(void)
{
UtRegisterTest("DetectAbsentTestParse01", DetectAbsentTestParse01);
UtRegisterTest("DetectAbsentTestParse02", DetectAbsentTestParse02);
UtRegisterTest("DetectAbsentTestParse03", DetectAbsentTestParse03);
UtRegisterTest("DetectAbsentTestParse04", DetectAbsentTestParse04);
UtRegisterTest("DetectAbsentTestParse05", DetectAbsentTestParse05);
}
#endif

Loading…
Cancel
Save