in apache2/re_operators.c [961:1185]
static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
msc_regex_t *regex = (msc_regex_t *)rule->op_param_data;
msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
const char *target;
const char *errptr = NULL;
int erroffset;
unsigned int target_length;
char *my_error_msg = NULL;
int ovector[33];
int capture = 0;
int matched_bytes = 0;
int matched = 0;
int rc;
char *qspos = NULL;
const char *parm = NULL, *pattern = NULL;
msc_parm *mparm = NULL;
#ifdef WITH_PCRE_STUDY
#ifdef WITH_PCRE_JIT
int jit;
#endif
#endif
if (error_msg == NULL) return -1;
*error_msg = NULL;
if (regex == NULL) {
if(rule->re_precomp == 0) {
*error_msg = "Internal Error: regex data is null.";
return -1;
} else {
if(re_pattern == NULL) {
*error_msg = "Internal Error: regex variable data is null.";
return -1;
}
re_pattern->value = apr_pstrndup(msr->mp, rule->re_str, strlen(rule->re_str));
re_pattern->value_len = strlen(re_pattern->value);
expand_macros(msr, re_pattern, rule, msr->mp);
pattern = log_escape_re(msr->mp, re_pattern->value);
if (msr->txcfg->debuglog_level >= 6) {
msr_log(msr, 6, "Escaping pattern [%s]",pattern);
}
regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
if (regex == NULL) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s",
erroffset, errptr);
return 0;
}
#ifdef WITH_PCRE_STUDY
#ifdef WITH_PCRE_JIT
if (msr->txcfg->debuglog_level >= 4) {
rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit);
if ((rc != 0) || (jit != 1)) {
*error_msg = apr_psprintf(rule->ruleset->mp,
"Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - "
"Execution error - "
"Does not support JIT (%d)",
rule,((rule->actionset != NULL)&&((rule->actionset->id != NULL)&&
(rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-",
rule->filename != NULL ? rule->filename : "-",
rule->line_num,rc);
msr_log(msr, 4, "%s.", *error_msg);
}
}
#endif
#endif
}
}
/* If the given target is null run against an empty
* string. This is a behaviour consistent with previous
* releases.
*/
if (var->value == NULL) {
target = "";
target_length = 0;
} else {
target = var->value;
target_length = var->value_len;
}
/* Are we supposed to capture subexpressions? */
capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0;
matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0;
if(!matched_bytes)
matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0;
matched = apr_table_get(rule->actionset->actions, "sanitizeMatched") ? 1 : 0;
if(!matched)
matched = apr_table_get(rule->actionset->actions, "sanitiseMatched") ? 1 : 0;
/* Show when the regex captures but "capture" is not set */
if (msr->txcfg->debuglog_level >= 6) {
int capcount = 0;
rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount);
if (msr->txcfg->debuglog_level >= 6) {
if ((capture == 0) && (capcount > 0)) {
msr_log(msr, 6, "Ignoring regex captures since \"capture\" action is not enabled.");
}
}
}
/* We always use capture so that ovector can be used as working space
* and no memory has to be allocated for any backreferences.
*/
rc = msc_regexec_capture(regex, target, target_length, ovector, 30, &my_error_msg);
if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) {
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
if (s == NULL) return -1;
s->name = apr_pstrdup(msr->mp, "MSC_PCRE_LIMITS_EXCEEDED");
if (s->name == NULL) return -1;
s->name_len = strlen(s->name);
s->value = apr_pstrdup(msr->mp, "1");
if (s->value == NULL) return -1;
s->value_len = 1;
apr_table_setn(msr->tx_vars, s->name, (void *)s);
*error_msg = apr_psprintf(msr->mp,
"Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - "
"Execution error - "
"PCRE limits exceeded (%d): %s",
rule,((rule->actionset != NULL)&&(rule->actionset->id != NULL)) ? rule->actionset->id : "-",
rule->filename != NULL ? rule->filename : "-",
rule->line_num,rc, my_error_msg);
#ifdef WAF_JSON_LOGGING_ENABLE
msr_log_with_errorcode(msr, 3, 1, "%s.", *error_msg);
#else
msr_log(msr, 3, "%s.", *error_msg);
#endif
return 0; /* No match. */
}
else if (rc < -1) {
*error_msg = apr_psprintf(msr->mp, "Regex execution failed (%d): %s",
rc, my_error_msg);
return -1;
}
/* Handle captured subexpressions. */
if (capture && rc > 0) {
int i;
/* Unset any of the previously set capture variables. */
apr_table_unset(msr->tx_vars, "0");
apr_table_unset(msr->tx_vars, "1");
apr_table_unset(msr->tx_vars, "2");
apr_table_unset(msr->tx_vars, "3");
apr_table_unset(msr->tx_vars, "4");
apr_table_unset(msr->tx_vars, "5");
apr_table_unset(msr->tx_vars, "6");
apr_table_unset(msr->tx_vars, "7");
apr_table_unset(msr->tx_vars, "8");
apr_table_unset(msr->tx_vars, "9");
/* Use the available captures. */
for(i = 0; i < rc; i++) {
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
if (s == NULL) return -1;
s->name = apr_psprintf(msr->mp, "%d", i);
if (s->name == NULL) return -1;
s->name_len = strlen(s->name);
s->value = apr_pstrmemdup(msr->mp,
target + ovector[2 * i], ovector[2 * i + 1] - ovector[2 * i]);
if (s->value == NULL) return -1;
s->value_len = (ovector[2 * i + 1] - ovector[2 * i]);
apr_table_addn(msr->tx_vars, s->name, (void *)s);
if(((matched == 1) || (matched_bytes == 1)) && (var != NULL) && (var->name != NULL)) {
qspos = apr_psprintf(msr->mp, "%s", var->name);
parm = strstr(qspos, ":");
if (parm != NULL) {
parm++;
mparm = apr_palloc(msr->mp, sizeof(msc_parm));
if (mparm == NULL)
continue;
mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len);
mparm->pad_1 = rule->actionset->arg_min;
mparm->pad_2 = rule->actionset->arg_max;
apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm);
} else {
mparm = apr_palloc(msr->mp, sizeof(msc_parm));
if (mparm == NULL)
continue;
mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len);
apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm);
}
}
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i,
log_escape_nq_ex(msr->mp, s->value, s->value_len));
}
}
}
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
/* We no longer escape the pattern here as it is done when logging */
#ifdef WAF_JSON_LOGGING_ENABLE
char *pattern = apr_pstrdup(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>");
#else
char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>"));
#endif
/* This message will be logged. only the first 252 from the Pattern & the match */
*error_msg = apr_psprintf(msr->mp, "Pattern match \"%.252s\" at %.252s ....",
pattern, var->name);
return 1;
}
/* No match. */
return 0;
}