From a6740d021a07ad0c041634205bce27af8c4a6357 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Sep 2026 01:26:35 +0000 Subject: [PATCH] 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. --- src/detect-pcre.c | 63 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) 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);