Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 73 additions & 3 deletions apache2/re.c
Original file line number Diff line number Diff line change
Expand Up @@ -986,12 +986,80 @@
return 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) {
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;
Comment on lines +992 to +998
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The helper is named apr_table_action_exists, which reads like an APR API and is very close to apr_table_* symbols. To avoid confusion (and potential future naming collisions in backports), consider renaming it to something module-specific (e.g., msre_table_action_value_exists).

Copilot uses AI. Check for mistakes.
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) &&

Check failure on line 1020 in apache2/re.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ39gAuWde_Mn-3XwGMK&open=AZ39gAuWde_Mn-3XwGMK&pullRequest=3518
(strncmp(segment_start, value, value_len) == 0)) {
return 1;
}
if (*cursor == '\0') {

Check failure on line 1024 in apache2/re.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ39gAuWde_Mn-3XwGML&open=AZ39gAuWde_Mn-3XwGML&pullRequest=3518
break;
}
segment_start = cursor + 1;
}
cursor++;
}
}
return 0;
}

/**
* 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) {
/* logdata & msg cannot be used because ',' is used as entries separators */
if (apr_table_action_exists(p, vartable, "capture", name, value)) return 1;
Comment on lines +1035 to +1040
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says this checks for duplicates for "tags, logdata (and others)", but logdata (and msg) are explicitly not handled by this code path. Please update the comment to match actual behavior (or extend the implementation if logdata is intended to be deduped).

Copilot uses AI. Check for mistakes.
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;
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation in this block mixes tabs and spaces (e.g., the return 0; line). Please use the file’s existing indentation style consistently to avoid churn in future diffs.

Suggested change
return 0;
return 0;

Copilot uses AI. Check for mistakes.
}

/**
* Generic parser that is used as basis for target and action parsing.
* It breaks up the input string into name-parameter pairs and places
* them into the given table.
*/
int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable,

Check failure on line 1062 in apache2/re.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 58 to the 25 allowed.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ39gAuWde_Mn-3XwGMN&open=AZ39gAuWde_Mn-3XwGMN&pullRequest=3518
char **error_msg)
{
char *p = (char *)text;
Expand Down Expand Up @@ -1103,9 +1171,11 @@
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++;
}
Comment on lines +1174 to +1178
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are new behavior changes here (silently dropping duplicate action parameters like tag) but the regression test suite currently has a TODO for tag metadata actions (tests/regression/action/00-meta.t). Please add a regression test that asserts duplicate tag entries don't appear multiple times in the audit log metadata output, so this behavior is locked in and doesn't regress.

Copilot uses AI. Check for mistakes.

/* move to the first character of the next name-value pair */
while(isspace(*p)||(*p == ',')||(*p == '|')) p++;
Expand Down