static int msre_op_rx_execute()

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;
}