From ff512807870c2aa74049fa1692782bede6d9c170 Mon Sep 17 00:00:00 2001 From: Jonathan Berrewaerts Date: Wed, 18 Mar 2026 16:13:00 +0100 Subject: [PATCH 1/4] re-integrated remove redundant actions --- apache2/re.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index d067c68419..b890e877aa 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -986,6 +986,41 @@ msre_action *msre_create_action(msre_engine *engine, apr_pool_t *mp, const char return action; } +// Return 1 if "name=value" is present in table (for supplied action) +static int apr_table_action_exists(apr_pool_t* p, const apr_table_t* vartable, const char* action, const char* name, const char* value) { + if (strcmp(name, action) != 0) return 0; + + const char* vars = apr_table_getm(p, vartable, name); + if (!vars) return 0; + + char pattern[200]; + sprintf(pattern, "(?:^|,)%.185s(?:,|$)", value); + + const char* errptr = NULL; + int erroffset; + const pcre* regex = pcre_compile(pattern, 0, &errptr, &erroffset, NULL); + return !pcre_exec(regex, NULL, vars, strlen(vars), 0, 0, 0, 0); +} + +// Return 1 if "name=value" is present in table for tags, logdata (and others) +static int action_exists(apr_pool_t* p, const apr_table_t* vartable, const char* name, const char* value) { + if (apr_table_action_exists(p, vartable, "capture", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "chain", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "initcol", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "logdata", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "multiMatch", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitiseArg", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitiseMatched", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitiseMatchedBytes", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitiseRequestHeader", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitiseResponseHeader", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "setrsc", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "setsid", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "setuid", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "tag", name, value)) return 1; + return 0; +} + /** * Generic parser that is used as basis for target and action parsing. * It breaks up the input string into name-parameter pairs and places @@ -1103,9 +1138,11 @@ int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable, value = apr_pstrmemdup(mp, value, p - value); } - /* add to table */ - apr_table_addn(vartable, name, value); - count++; + /* add to table (only if not already present) */ + if (!action_exists(mp, vartable, name, value)) { + apr_table_addn(vartable, name, value); + count++; + } /* move to the first character of the next name-value pair */ while(isspace(*p)||(*p == ',')||(*p == '|')) p++; From 8765d8364082e655c385d78b3c7e6072cc54b8da Mon Sep 17 00:00:00 2001 From: Jonathan Berrewaerts Date: Wed, 15 Apr 2026 10:45:23 +0200 Subject: [PATCH 2/4] Fix compilation error and update function --- apache2/re.c | 56 +++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index b890e877aa..68cdfe7dca 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -986,38 +986,44 @@ msre_action *msre_create_action(msre_engine *engine, apr_pool_t *mp, const char return action; } -// Return 1 if "name=value" is present in table (for supplied action) +/** + * Helper function for action_exists. It checks if "name=value" is present in table for supplied action. + */ static int apr_table_action_exists(apr_pool_t* p, const apr_table_t* vartable, const char* action, const char* name, const char* value) { - if (strcmp(name, action) != 0) return 0; + if (strcmp(name, action) != 0) return 0; + + const char* vars = apr_table_getm(p, vartable, name); + if (!vars) return 0; - const char* vars = apr_table_getm(p, vartable, name); - if (!vars) return 0; + char pattern[200]; + sprintf(pattern, "(?:^|,)%.185s(?:,|$)", value); - char pattern[200]; - sprintf(pattern, "(?:^|,)%.185s(?:,|$)", value); + char* error_msg = NULL; + msc_regex_t* regex = msc_pregcomp(p, pattern, 0, NULL, NULL); + if (regex == NULL) return 0; // we could log an error here - const char* errptr = NULL; - int erroffset; - const pcre* regex = pcre_compile(pattern, 0, &errptr, &erroffset, NULL); - return !pcre_exec(regex, NULL, vars, strlen(vars), 0, 0, 0, 0); + return (msc_regexec(regex, vars, strlen(vars), &error_msg) >= 0); } -// Return 1 if "name=value" is present in table for tags, logdata (and others) +/** + * Checks if "name=value" is present in table for tags, logdata (and others). + */ static int action_exists(apr_pool_t* p, const apr_table_t* vartable, const char* name, const char* value) { - if (apr_table_action_exists(p, vartable, "capture", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "chain", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "initcol", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "logdata", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "multiMatch", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "sanitiseArg", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "sanitiseMatched", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "sanitiseMatchedBytes", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "sanitiseRequestHeader", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "sanitiseResponseHeader", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "setrsc", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "setsid", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "setuid", name, value)) return 1; - if (apr_table_action_exists(p, vartable, "tag", name, value)) return 1; + /* logdata & msg cannot be used because ',' is used as entries separators */ + if (apr_table_action_exists(p, vartable, "capture", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "chain", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "initcol", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "multiMatch", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "phase", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitizeArg", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitizeMatched", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitizeMatchedBytes", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitizeRequestHeader", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "sanitizeResponseHeader", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "setrsc", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "setsid", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "setuid", name, value)) return 1; + if (apr_table_action_exists(p, vartable, "tag", name, value)) return 1; return 0; } From ddb0aa3c6bb0cf171381d9e88c0d2682a06831dd Mon Sep 17 00:00:00 2001 From: Jonathan Berrewaerts Date: Wed, 15 Apr 2026 11:00:35 +0200 Subject: [PATCH 3/4] use of apr_snprintf --- apache2/re.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 68cdfe7dca..943d9b6810 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -996,11 +996,11 @@ static int apr_table_action_exists(apr_pool_t* p, const apr_table_t* vartable, c if (!vars) return 0; char pattern[200]; - sprintf(pattern, "(?:^|,)%.185s(?:,|$)", value); + apr_snprintf(pattern, sizeof(pattern), "(?:^|,)%.185s(?:,|$)", value); char* error_msg = NULL; msc_regex_t* regex = msc_pregcomp(p, pattern, 0, NULL, NULL); - if (regex == NULL) return 0; // we could log an error here + if (regex == NULL) return 0; return (msc_regexec(regex, vars, strlen(vars), &error_msg) >= 0); } From 497c45d445cdce75e34520d97aabcdce83116bb7 Mon Sep 17 00:00:00 2001 From: Jonathan Berrewaerts Date: Wed, 6 May 2026 15:34:26 +0200 Subject: [PATCH 4/4] avoid truncation to 185 char --- apache2/re.c | 51 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 943d9b6810..5a5889abe4 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -990,19 +990,46 @@ msre_action *msre_create_action(msre_engine *engine, apr_pool_t *mp, const char * Helper function for action_exists. It checks if "name=value" is present in table for supplied action. */ static int apr_table_action_exists(apr_pool_t* p, const apr_table_t* vartable, const char* action, const char* name, const char* value) { + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *elts = NULL; + int i = 0; + apr_size_t value_len = 0; + (void)p; if (strcmp(name, action) != 0) return 0; - - const char* vars = apr_table_getm(p, vartable, name); - if (!vars) return 0; - - char pattern[200]; - apr_snprintf(pattern, sizeof(pattern), "(?:^|,)%.185s(?:,|$)", value); - - char* error_msg = NULL; - msc_regex_t* regex = msc_pregcomp(p, pattern, 0, NULL, NULL); - if (regex == NULL) return 0; - - return (msc_regexec(regex, vars, strlen(vars), &error_msg) >= 0); + if ((vartable == NULL) || (value == NULL)) return 0; + value_len = strlen(value); + arr = apr_table_elts(vartable); + if (arr == NULL) return 0; + elts = (const apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + const char *vars = NULL; + const char *segment_start = NULL; + const char *cursor = NULL; + if ((elts[i].key == NULL) || (strcmp(elts[i].key, name) != 0)) { + continue; + } + vars = elts[i].val; + if (vars == NULL) { + continue; + } + segment_start = vars; + cursor = vars; + for (;;) { + if ((*cursor == ',') || (*cursor == '\0')) { + apr_size_t segment_len = (apr_size_t)(cursor - segment_start); + if ((segment_len == value_len) && + (strncmp(segment_start, value, value_len) == 0)) { + return 1; + } + if (*cursor == '\0') { + break; + } + segment_start = cursor + 1; + } + cursor++; + } + } + return 0; } /**