detect/mpm: use content after must_succeed as fast_pattern

transform_result stopped fast_pattern selection, and the validator
rejected fast_pattern on its buffer. Content after must_succeed only
matches when the transform succeeded, and the prefilter scans the same
transformed bytes, so "http.uri; from_base64; transform_result:
must_succeed; content:"evil";" lost its only fast pattern and ran on
every HTTP transaction.

Let content after must_succeed be the fast pattern, and accept
fast_pattern there.

Issue: 7313
Issue: 7114
pull/16484/head
Jeff Lucovsky 1 week ago
parent a9d70166ec
commit 15a068258d

@ -35,6 +35,7 @@
#include "detect-engine.h"
#include "detect-engine-siggroup.h"
#include "detect-engine-mpm.h"
#include "detect-isdataat.h"
#include "detect-engine-iponly.h"
#include "detect-parse.h"
#include "detect-engine-prefilter.h"
@ -1120,11 +1121,15 @@ static void SetMpm(Signature *s, SigMatch *mpm_sm, const int mpm_sm_list)
}
/* 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. */
* fast_pattern. transform_result: must_succeed does not: content after it
* can only match when the transform succeeded, and the prefilter then scans
* the same transformed bytes. 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;
if (sm->type == DETECT_TRANSFORM_RESULT)
return ((const DetectAbsentData *)sm->ctx)->mode != DETECT_ABSENT_MUST_SUCCEED;
return sm->type == DETECT_ABSENT;
}
static SigMatch *GetMpmForList(const Signature *s, SigMatch *list, SigMatch *mpm_sm,

@ -230,7 +230,7 @@ bool DetectAbsentValidateContentCallback(
"buffer");
return false;
}
if (has_fast_pattern) {
if (has_fast_pattern && absent->mode != DETECT_ABSENT_MUST_SUCCEED) {
SCLogError("signature can't have %s and fast_pattern on the same buffer", kw);
return false;
}
@ -1072,13 +1072,13 @@ static int DetectAbsentTestParse04(void)
"sid:6;)");
FAIL_IF(s != NULL);
/* transform_result: must_succeed + fast_pattern on the same buffer should fail */
/* transform_result: must_succeed allows fast_pattern on the same buffer */
s = DetectEngineAppendSig(de_ctx,
"alert http any any -> any any "
"(msg:\"must_succeed + fast_pattern\"; http.uri; "
"from_base64: mode strict; transform_result: must_succeed; content:\"x\"; "
"fast_pattern; sid:7;)");
FAIL_IF(s != NULL);
FAIL_IF_NULL(s);
/* fast_pattern appearing before absent on the same buffer should still fail
* (the simplified walk is order-independent for fast_pattern detection) */
@ -1134,6 +1134,44 @@ static int DetectAbsentTestParse05(void)
PASS;
}
/** \test content after transform_result: must_succeed can be the fast_pattern;
* content after error_or cannot */
static int DetectAbsentTestParse06(void)
{
const struct {
const char *sig;
bool mpm;
} tests[] = {
{ "alert http any any -> any any (http.uri; from_base64; "
"transform_result: must_succeed; content:\"evil\"; sid:1;)",
true },
{ "alert http any any -> any any (http.uri; from_base64; "
"transform_result: error_or; content:\"evil\"; sid:2;)",
false },
};
for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
Signature *s = DetectEngineAppendSig(de_ctx, tests[i].sig);
FAIL_IF_NULL(s);
FAIL_IF_NOT(s->init_data->buffer_index == 1);
bool mpm = false;
for (SigMatch *sm = s->init_data->buffers[0].head; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_CONTENT &&
(((const DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_MPM))
mpm = true;
}
FAIL_IF_NOT(mpm == tests[i].mpm);
DetectEngineCtxFree(de_ctx);
}
PASS;
}
void DetectAbsentRegisterTests(void)
{
UtRegisterTest("DetectAbsentTestParse01", DetectAbsentTestParse01);
@ -1141,5 +1179,6 @@ void DetectAbsentRegisterTests(void)
UtRegisterTest("DetectAbsentTestParse03", DetectAbsentTestParse03);
UtRegisterTest("DetectAbsentTestParse04", DetectAbsentTestParse04);
UtRegisterTest("DetectAbsentTestParse05", DetectAbsentTestParse05);
UtRegisterTest("DetectAbsentTestParse06", DetectAbsentTestParse06);
}
#endif

Loading…
Cancel
Save