detect/pcre: accept a relative pcre after byte_jump

A rule whose relative pcre follows a keyword that moves the detection
pointer is refused at load time with "pcre with /R (relative) needs
preceding match in the same buffer":

  alert tcp any any -> any any (msg:"x"; byte_jump:4,0; pcre:"/^x/R"; ...)

The search for the preceding match only asked for content and pcre
sigmatches, so a rule that anchors a relative pcre on a byte_jump had
nothing to find even though byte_jump leaves the detection pointer at
the jump target.

Add the keywords that update det_ctx->buffer_offset to the search:
byte_jump, byte_extract and byte_math. byte_test and isdataat only read
that pointer, so they stay rejected; a relative pcre after them alone
would silently match from the start of the buffer.

Ticket: #7987.
pull/16497/head
Victor Julien 4 weeks ago
parent 73095bb089
commit a6740d021a

@ -1045,8 +1045,11 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *r
/* errors below shouldn't free pd */ /* errors below shouldn't free pd */
SigMatch *prev_pm = DetectGetLastSMByListPtr(s, sm->prev, /* Besides content and pcre, the keywords that move the detection pointer by
DETECT_CONTENT, DETECT_PCRE, -1); * updating det_ctx->buffer_offset also anchor a relative match. byte_test
* and isdataat only read that pointer, so they are not accepted here. */
SigMatch *prev_pm = DetectGetLastSMByListPtr(s, sm->prev, DETECT_CONTENT, DETECT_PCRE,
DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_BYTEMATH, -1);
if (s->init_data->list == DETECT_SM_LIST_NOTSET && prev_pm == NULL) { if (s->init_data->list == DETECT_SM_LIST_NOTSET && prev_pm == NULL) {
SCLogError("pcre with /R (relative) needs " SCLogError("pcre with /R (relative) needs "
"preceding match in the same buffer"); "preceding match in the same buffer");
@ -1576,6 +1579,61 @@ static int DetectPcreParseTest28(void)
PASS; PASS;
} }
/** \test #7987 a relative pcre is anchored on the keywords that move the
* detection pointer, not just on content and pcre. */
static int DetectPcreParseTest29(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list =
SigInit(de_ctx, "alert tcp any any -> any any (msg:\"byte_jump\"; byte_jump:4,0; "
"pcre:\"/abc/R\"; sid:1; rev:1;)");
FAIL_IF_NULL(de_ctx->sig_list);
SigCleanSignatures(de_ctx);
de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"relative byte_jump\"; "
"byte_jump:4,0,relative; pcre:\"/abc/R\"; sid:1; rev:1;)");
FAIL_IF_NULL(de_ctx->sig_list);
SigCleanSignatures(de_ctx);
de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"byte_extract\"; "
"byte_extract:4,0,len; pcre:\"/abc/R\"; sid:1; rev:1;)");
FAIL_IF_NULL(de_ctx->sig_list);
SigCleanSignatures(de_ctx);
de_ctx->sig_list =
SigInit(de_ctx, "alert tcp any any -> any any (msg:\"byte_math\"; "
"byte_math: bytes 4, offset 0, oper +, rvalue 0, result len; "
"pcre:\"/abc/R\"; sid:1; rev:1;)");
FAIL_IF_NULL(de_ctx->sig_list);
SigCleanSignatures(de_ctx);
/* byte_test and isdataat only read the detection pointer, so they are still
* no preceding match for a relative pcre. */
de_ctx->sig_list =
SigInit(de_ctx, "alert tcp any any -> any any (msg:\"byte_test\"; byte_test:4,=,0,0; "
"pcre:\"/abc/R\"; sid:1; rev:1;)");
FAIL_IF_NOT_NULL(de_ctx->sig_list);
SigCleanSignatures(de_ctx);
de_ctx->sig_list =
SigInit(de_ctx, "alert tcp any any -> any any (msg:\"isdataat\"; isdataat:10; "
"pcre:\"/abc/R\"; sid:1; rev:1;)");
FAIL_IF_NOT_NULL(de_ctx->sig_list);
SigCleanSignatures(de_ctx);
de_ctx->sig_list = SigInit(de_ctx,
"alert tcp any any -> any any (msg:\"no match\"; pcre:\"/abc/R\"; sid:1; rev:1;)");
FAIL_IF_NOT_NULL(de_ctx->sig_list);
DetectEngineCtxFree(de_ctx);
PASS;
}
static int DetectPcreTestSig01(void) static int DetectPcreTestSig01(void)
{ {
uint8_t *buf = (uint8_t *)"lalala lalala\\ lala\n"; uint8_t *buf = (uint8_t *)"lalala lalala\\ lala\n";
@ -2106,6 +2164,7 @@ static void DetectPcreRegisterTests(void)
UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26); UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26);
UtRegisterTest("DetectPcreParseTest27", DetectPcreParseTest27); UtRegisterTest("DetectPcreParseTest27", DetectPcreParseTest27);
UtRegisterTest("DetectPcreParseTest28", DetectPcreParseTest28); UtRegisterTest("DetectPcreParseTest28", DetectPcreParseTest28);
UtRegisterTest("DetectPcreParseTest29", DetectPcreParseTest29);
UtRegisterTest("DetectPcreTestSig01", DetectPcreTestSig01); UtRegisterTest("DetectPcreTestSig01", DetectPcreTestSig01);
UtRegisterTest("DetectPcreTestSig02 -- anchored pcre", DetectPcreTestSig02); UtRegisterTest("DetectPcreTestSig02 -- anchored pcre", DetectPcreTestSig02);

Loading…
Cancel
Save