diff --git a/src/detect-pcre.c b/src/detect-pcre.c index c108425242..3e1fd82380 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -1045,8 +1045,11 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *r /* errors below shouldn't free pd */ - SigMatch *prev_pm = DetectGetLastSMByListPtr(s, sm->prev, - DETECT_CONTENT, DETECT_PCRE, -1); + /* Besides content and pcre, the keywords that move the detection pointer by + * 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) { SCLogError("pcre with /R (relative) needs " "preceding match in the same buffer"); @@ -1576,6 +1579,61 @@ static int DetectPcreParseTest28(void) 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) { uint8_t *buf = (uint8_t *)"lalala lalala\\ lala\n"; @@ -2106,6 +2164,7 @@ static void DetectPcreRegisterTests(void) UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26); UtRegisterTest("DetectPcreParseTest27", DetectPcreParseTest27); UtRegisterTest("DetectPcreParseTest28", DetectPcreParseTest28); + UtRegisterTest("DetectPcreParseTest29", DetectPcreParseTest29); UtRegisterTest("DetectPcreTestSig01", DetectPcreTestSig01); UtRegisterTest("DetectPcreTestSig02 -- anchored pcre", DetectPcreTestSig02);