From 6afe490b4610634da3a6d044d61a03b1e3c9cb46 Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Sun, 16 Aug 2026 10:03:39 -0400 Subject: [PATCH] detect/pcre: skip flow captures on flowless packets DetectPcrePayloadMatch dispatched each capture group through a chain of captype tests whose flow-variable arm also required a non-NULL flow, and closed with an else that called BUG_ON(1) on the grounds that the captype was impossible. A capture typed VAR_TYPE_FLOW_VAR on a packet inspected without a flow, such as an ICMPv4 error message, matched no arm of that chain and reached the else. BUG_ON expands to assert() wherever assert.h is available and NDEBUG is unset and to exit(EXIT_FAILURE) otherwise, so one pcre rule whose flow capture matched such a packet killed the process. Test the captype before the substring is extracted and skip a flow capture when there is no flow, so nothing is allocated for a capture that has nowhere to go. The remaining capture groups of the same pcre still run: a rule that captures one group into a flow variable and the next into a packet variable still stores the packet variable. The SCFree(str_ptr) below BUG_ON(1) could never run, because BUG_ON terminates the process first. Use DEBUG_VALIDATE_BUG_ON instead, which compiles out unless debug validation is enabled, so a captype the parser cannot produce releases its capture rather than ending the process. Issue: 8862 --- src/detect-pcre.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index cafcb37e58..a361ab7c7d 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2025 Open Information Security Foundation +/* Copyright (C) 2007-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -276,6 +276,10 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, uint8_t x; for (x = 0; x < pe->idx; x++) { SCLogDebug("capturing %u", x); + if (pe->captypes[x] == VAR_TYPE_FLOW_VAR && f == NULL) { + /* no flow to store the capture in, so don't extract it. */ + continue; + } const char *pcre2_str_ptr = NULL; ret = pcre2_substring_get_bynumber( match, x + 1, (PCRE2_UCHAR8 **)&pcre2_str_ptr, &capture_len); @@ -327,7 +331,7 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, (void)DetectVarStoreMatch(det_ctx, pe->capids[x], (uint8_t *)str_ptr, (uint16_t)capture_len, DETECT_VAR_TYPE_PKT_POSTMATCH); - } else if (pe->captypes[x] == VAR_TYPE_FLOW_VAR && f != NULL) { + } else if (pe->captypes[x] == VAR_TYPE_FLOW_VAR) { (void)DetectVarStoreMatch(det_ctx, pe->capids[x], (uint8_t *)str_ptr, (uint16_t)capture_len, DETECT_VAR_TYPE_FLOW_POSTMATCH); @@ -336,7 +340,7 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, (uint16_t)capture_len); } else { - BUG_ON(1); // Impossible captype + DEBUG_VALIDATE_BUG_ON(1); // Impossible captype SCFree(str_ptr); } }