Support for PCRE2

This commit is contained in:
Martin Vierula 2022-11-08 08:06:39 -08:00
parent 849cd7e848
commit 8fc0b519b7
No known key found for this signature in database
GPG Key ID: F2FC4E45883BCBA4
14 changed files with 438 additions and 29 deletions

View File

@ -1,6 +1,8 @@
DD mmm YYYY - 2.9.x (to be released)
-------------------
* Support for PCRE2
[Issue #2737, #2827 - @martinhsv]
07 Sep 2022 - 2.9.6
-------------------

View File

@ -42,6 +42,7 @@ mod_security2_la_CFLAGS = @APR_CFLAGS@ \
@LUA_CFLAGS@ \
@MODSEC_EXTRA_CFLAGS@ \
@PCRE_CFLAGS@ \
@PCRE2_CFLAGS@ \
@YAJL_CFLAGS@ \
@SSDEEP_CFLAGS@
@ -50,7 +51,8 @@ mod_security2_la_CPPFLAGS = @APR_CPPFLAGS@ \
@CURL_CPPFLAGS@ \
@LIBXML2_CFLAGS@ \
@LIBXML2_CPPFLAGS@ \
@PCRE_CPPFLAGS@
@PCRE_CPPFLAGS@ \
@PCRE2_CPPFLAGS@
mod_security2_la_LIBADD = @APR_LDADD@ \
@APU_LDADD@ \
@ -59,6 +61,7 @@ mod_security2_la_LIBADD = @APR_LDADD@ \
@LIBXML2_LDADD@ \
@LUA_LDADD@ \
@PCRE_LDADD@ \
@PCRE2_LDADD@ \
@YAJL_LDADD@
if AIX
@ -71,6 +74,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
@PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@ -85,6 +89,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
@PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@ -99,6 +104,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
@PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@ -113,6 +119,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
@PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@ -127,6 +134,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version -R @PCRE_LD_PATH
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
@PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@ -141,6 +149,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
@PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@ -155,6 +164,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
@PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@ -169,6 +179,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
@PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif

View File

@ -1,6 +1,6 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
@ -1293,7 +1293,11 @@ static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg,
{
directory_config *dcfg = _dcfg;
#ifdef WITH_PCRE2
dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE2_DOTALL, NULL, NULL);
#else
dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE_DOTALL, NULL, NULL);
#endif
if (dcfg->auditlog_relevant_regex == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
}

View File

@ -1,6 +1,6 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
@ -107,6 +107,8 @@ static int server_limit, thread_limit;
*/
static void version(apr_pool_t *mp) {
char *pcre_vrs = NULL;
char *pcre_loaded_vrs = NULL;
char pcre2_loaded_vrs_buffer[80] ={0};
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
"ModSecurity: APR compiled version=\"%s\"; "
@ -116,13 +118,20 @@ static void version(apr_pool_t *mp) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "ModSecurity: Loaded APR do not match with compiled!");
}
#ifdef WITH_PCRE2
pcre_vrs = apr_psprintf(mp,"%d.%d ", PCRE2_MAJOR, PCRE2_MINOR);
pcre_loaded_vrs = pcre2_loaded_vrs_buffer;
pcre2_config(PCRE2_CONFIG_VERSION, pcre_loaded_vrs);
#else
pcre_vrs = apr_psprintf(mp,"%d.%d ", PCRE_MAJOR, PCRE_MINOR);
pcre_loaded_vrs = pcre_version();
#endif
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
"ModSecurity: PCRE compiled version=\"%s\"; "
"loaded version=\"%s\"", pcre_vrs, pcre_version());
"loaded version=\"%s\"", pcre_vrs, pcre_loaded_vrs);
if (strstr(pcre_version(),pcre_vrs) == NULL) {
if (strstr(pcre_loaded_vrs,pcre_vrs) == NULL) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "ModSecurity: Loaded PCRE do not match with compiled!");
}

View File

@ -1,6 +1,6 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
@ -561,7 +561,11 @@ static int is_response_status_relevant(modsec_rec *msr, int status) {
rc = msc_regexec(msr->txcfg->auditlog_relevant_regex, buf, strlen(buf), &my_error_msg);
if (rc >= 0) return 1;
#ifdef WITH_PCRE2
if (rc == PCRE2_ERROR_NOMATCH) return 0;
#else
if (rc == PCRE_ERROR_NOMATCH) return 0;
#endif
msr_log(msr, 1, "Regex processing failed (rc %d): %s", rc, my_error_msg);

View File

@ -1,6 +1,6 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
@ -386,7 +386,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
case HASH_URL_HREF_HASH_RX:
if(em[i]->type == HASH_URL_HREF_HASH_RX) {
rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg);
#ifdef WITH_PCRE2
if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) {
#else
if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) {
#endif
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
if (s == NULL) return -1;
@ -415,7 +419,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
msr_log(msr, 4, "%s.", error_msg);
return -1;
}
#ifdef WITH_PCRE2
if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
#endif
return 1;
}
}
@ -441,7 +449,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
case HASH_URL_FACTION_HASH_RX:
if(em[i]->type == HASH_URL_FACTION_HASH_RX) {
rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg);
#ifdef WITH_PCRE2
if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) {
#else
if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) {
#endif
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
if (s == NULL) return -1;
@ -470,7 +482,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
msr_log(msr, 4, "%s.", error_msg);
return -1;
}
#ifdef WITH_PCRE2
if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
#endif
return 1;
}
}
@ -496,7 +512,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
case HASH_URL_LOCATION_HASH_RX:
if(em[i]->type == HASH_URL_LOCATION_HASH_RX) {
rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg);
#ifdef WITH_PCRE2
if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) {
#else
if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) {
#endif
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
if (s == NULL) return -1;
@ -525,7 +545,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
msr_log(msr, 4, "%s.", error_msg);
return -1;
}
#ifdef WITH_PCRE2
if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
#endif
return 1;
}
}
@ -551,7 +575,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
case HASH_URL_IFRAMESRC_HASH_RX:
if(em[i]->type == HASH_URL_IFRAMESRC_HASH_RX) {
rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg);
#ifdef WITH_PCRE2
if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) {
#else
if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) {
#endif
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
if (s == NULL) return -1;
@ -580,7 +608,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
msr_log(msr, 4, "%s.", error_msg);
return -1;
}
#ifdef WITH_PCRE2
if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
#endif
return 1;
}
}
@ -606,7 +638,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
case HASH_URL_FRAMESRC_HASH_RX:
if(em[i]->type == HASH_URL_FRAMESRC_HASH_RX) {
rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg);
#ifdef WITH_PCRE2
if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) {
#else
if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) {
#endif
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
if (s == NULL) return -1;
@ -635,7 +671,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
msr_log(msr, 4, "%s.", error_msg);
return -1;
}
#ifdef WITH_PCRE2
if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
#endif
return 1;
}
}

View File

@ -1,6 +1,6 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
@ -20,6 +20,16 @@
*/
static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) {
if (regex != NULL) {
#ifdef WITH_PCRE2
if (regex->match_context != NULL) {
pcre2_match_context_free(regex->match_context);
regex->match_context = NULL;
}
if (regex->re != NULL) {
pcre2_code_free(regex->re);
regex->re = NULL;
}
#else
if (regex->pe != NULL) {
#if defined(VERSION_NGINX)
pcre_free(regex->pe);
@ -32,6 +42,7 @@ static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) {
pcre_free(regex->re);
regex->re = NULL;
}
#endif
}
return APR_SUCCESS;
@ -48,6 +59,78 @@ static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) {
void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options,
const char **_errptr, int *_erroffset,
int match_limit, int match_limit_recursion)
#ifdef WITH_PCRE2
{
msc_regex_t *regex = NULL;
PCRE2_SPTR pcre2_pattern;
uint32_t pcre2_options;
int error_number = 0;
PCRE2_SIZE error_offset = 0;
pcre2_match_context *match_context = NULL;
regex = apr_pcalloc(pool, sizeof(msc_regex_t));
if (regex == NULL) return NULL;
regex->pattern = pattern;
pcre2_pattern = (PCRE2_SPTR)pattern;
pcre2_options = (uint32_t)options;
regex->re = pcre2_compile(pcre2_pattern, PCRE2_ZERO_TERMINATED,
pcre2_options, &error_number, &error_offset, NULL);
if (regex->re == NULL) {
if (_erroffset != NULL) {
*_erroffset = (int)error_offset;
}
return NULL;
}
/* TODO: Add PCRE2 JIT support */
/* Setup the pcre2 match context */
regex->match_context = NULL;
match_context = pcre2_match_context_create(NULL);
if (match_context == NULL) {
return NULL;
}
/* Prefer the match limit passed as an arg; else use compilation default */
{
uint32_t final_match_limit = 0;
if (match_limit > 0) {
final_match_limit = match_limit;
pcre2_set_match_limit(match_context, final_match_limit);
}
#ifdef MODSEC_PCRE_MATCH_LIMIT
else {
final_match_limit = MODSEC_PCRE_MATCH_LIMIT;
pcre2_set_match_limit(match_context, final_match_limit);
}
#endif /* MODSEC_PCRE_MATCH_LIMIT */
}
/* Prefer the depth limit passed as an arg; else use compilation default */
{
uint32_t final_match_limit_recursion = 0;
if (match_limit_recursion > 0) {
final_match_limit_recursion = match_limit_recursion;
pcre2_set_depth_limit(match_context, final_match_limit_recursion);
}
#ifdef MODSEC_PCRE_MATCH_LIMIT_RECURSION
else {
final_match_limit_recursion = MODSEC_PCRE_MATCH_LIMIT_RECURSION;
pcre2_set_depth_limit(match_context, final_match_limit_recursion);
}
#endif /* MODSEC_PCRE_MATCH_LIMIT_RECURSION */
}
regex->match_context = match_context;
apr_pool_cleanup_register(pool, (void *)regex,
(apr_status_t (*)(void *))msc_pcre_cleanup, apr_pool_cleanup_null);
return regex;
}
#else /* not WITH_PCRE2 */
{
const char *errptr = NULL;
int erroffset;
@ -131,6 +214,7 @@ void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options,
return regex;
}
#endif /* WITH_PCRE2 */
/**
* Compiles the provided regular expression pattern. Calls msc_pregcomp_ex()
@ -143,9 +227,9 @@ void *msc_pregcomp(apr_pool_t *pool, const char *pattern, int options,
}
/**
* Executes regular expression with extended options.
* Returns PCRE_ERROR_NOMATCH when there is no match, error code < -1
* on errors, and a value > 0 when there is a match.
* Executes regular expression with extended options (or match context)
* Returns PCRE_ERROR_NOMATCH (or PCRE2_ERROR_NOMATCH),
* error code < -1 on errors, and a value > 0 when there is a match.
*/
int msc_regexec_ex(msc_regex_t *regex, const char *s, unsigned int slen,
int startoffset, int options, int *ovector, int ovecsize, char **error_msg)
@ -153,7 +237,41 @@ int msc_regexec_ex(msc_regex_t *regex, const char *s, unsigned int slen,
if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */
*error_msg = NULL;
#ifdef WITH_PCRE2
{
PCRE2_SPTR pcre2_s;
int pcre2_ret;
pcre2_match_data *match_data;
PCRE2_SIZE *pcre2_ovector = NULL;
pcre2_s = (PCRE2_SPTR)s;
match_data = pcre2_match_data_create_from_pattern(regex->re, NULL);
pcre2_ret = pcre2_match(regex->re, pcre2_s, (PCRE2_SIZE)strlen(s),
(PCRE2_SIZE)(startoffset), (uint32_t)options, match_data, regex->match_context);
if (match_data != NULL) {
if (ovector != NULL) {
pcre2_ovector = pcre2_get_ovector_pointer(match_data);
if (pcre2_ovector != NULL) {
for (int i = 0; ((i < pcre2_ret) && ((i*2) <= ovecsize)); i++) {
if ((i*2) < ovecsize) {
ovector[2*i] = pcre2_ovector[2*i];
ovector[2*i+1] = pcre2_ovector[2*i+1];
}
}
}
}
pcre2_match_data_free(match_data);
}
if ((pcre2_ret*2) > ovecsize) {
return 0;
} else {
return pcre2_ret;
}
}
#else
return pcre_exec(regex->re, regex->pe, s, slen, startoffset, options, ovector, ovecsize);
#endif
}
/**
@ -188,6 +306,10 @@ int msc_regexec(msc_regex_t *regex, const char *s, unsigned int slen,
*/
int msc_fullinfo(msc_regex_t *regex, int what, void *where)
{
#ifdef WITH_PCRE2
return pcre2_pattern_info(regex->re, (uint32_t)what, where);
#else
return pcre_fullinfo(regex->re, regex->pe, what, where);
#endif
}

View File

@ -1,6 +1,6 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
@ -17,7 +17,14 @@
typedef struct msc_regex_t msc_regex_t;
#ifdef WITH_PCRE2
#define PCRE2_CODE_UNIT_WIDTH 8
#include "pcre2.h"
#else
#include "pcre.h"
#endif
#ifndef WITH_PCRE2
#ifndef PCRE_ERROR_MATCHLIMIT
/* Define for compile, but not valid in this version of PCRE. */
@ -29,12 +36,19 @@ typedef struct msc_regex_t msc_regex_t;
#define PCRE_ERROR_RECURSIONLIMIT (-21)
#endif /* PCRE_ERROR_RECURSIONLIMIT */
#endif
#include "apr_general.h"
#include "modsecurity.h"
struct msc_regex_t {
#ifdef WITH_PCRE2
pcre2_code *re;
pcre2_match_context *match_context;
#else
void *re;
void *pe;
#endif
const char *pattern;
};

View File

@ -1,6 +1,6 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
@ -345,8 +345,13 @@ int DSOLOCAL msc_beacon_string (char *beacon_string, int beacon_string_max_len)
apr = APR_VERSION_STRING;
apr_loaded = apr_version_string();
#ifdef WITH_PCRE2
apr_snprintf(pcre, 7, "%d.%d", PCRE2_MAJOR, PCRE2_MINOR);
pcre_loaded = ""; /* complete this if/when status reactivated */
#else
apr_snprintf(pcre, 7, "%d.%d", PCRE_MAJOR, PCRE_MINOR);
pcre_loaded = pcre_version();
#endif
#ifdef WITH_LUA
lua = LUA_VERSION;
#endif

View File

@ -1,6 +1,6 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
@ -697,7 +697,12 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) {
/* Compile pattern */
if(strstr(pattern,"%{") == NULL) {
regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
#ifdef WITH_PCRE2
int options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY;
#else
int options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY;
#endif
regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, options, &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);
@ -747,6 +752,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v
const char *target;
const char *errptr = NULL;
int erroffset;
int options = 0;
unsigned int target_length;
char *my_error_msg = NULL;
int ovector[33];
@ -786,7 +792,12 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v
msr_log(msr, 6, "Escaping pattern [%s]",pattern);
}
regex = msc_pregcomp_ex(msr->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr,
#ifdef WITH_PCRE2
options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY;
#else
options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY;
#endif
regex = msc_pregcomp_ex(msr->mp, pattern, options, &errptr,
&erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
if (regex == NULL) {
*error_msg = apr_psprintf(msr->mp, "Error compiling pattern (offset %d): %s",
@ -831,7 +842,11 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v
* and no memory has to be allocated for any backreferences.
*/
rc = msc_regexec_capture(regex, target, target_length, ovector, 30, &my_error_msg);
#ifdef WITH_PCRE2
if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) {
#else
if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) {
#endif
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
if (s == NULL) return -1;
@ -861,7 +876,11 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v
return -1;
}
#ifdef WITH_PCRE2
if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
#endif
/* We no longer escape the pattern here as it is done when logging */
char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>"));
char *hmac = NULL, *valid = NULL;
@ -940,7 +959,12 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) {
/* Compile pattern */
if(strstr(pattern,"%{") == NULL) {
regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
#ifdef WITH_PCRE2
int options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY;
#else
int options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY;
#endif
regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, options, &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);
@ -979,6 +1003,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
const char *target;
const char *errptr = NULL;
int erroffset;
int options = 0;
unsigned int target_length;
char *my_error_msg = NULL;
int ovector[33];
@ -1020,7 +1045,12 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
msr_log(msr, 6, "Escaping pattern [%s]",pattern);
}
regex = msc_pregcomp_ex(msr->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
#ifdef WITH_PCRE2
options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY;
#else
options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY;
#endif
regex = msc_pregcomp_ex(msr->mp, pattern, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
if (regex == NULL) {
*error_msg = apr_psprintf(msr->mp, "Error compiling pattern (offset %d): %s",
erroffset, errptr);
@ -1075,7 +1105,11 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
/* Show when the regex captures but "capture" is not set */
if (msr->txcfg->debuglog_level >= 6) {
int capcount = 0;
#ifdef WITH_PCRE2
rc = msc_fullinfo(regex, PCRE2_INFO_CAPTURECOUNT, &capcount);
#else
rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount);
#endif
if (msr->txcfg->debuglog_level >= 6) {
if ((capture == 0) && (capcount > 0)) {
msr_log(msr, 6, "Ignoring regex captures since \"capture\" action is not enabled.");
@ -1087,7 +1121,11 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
* and no memory has to be allocated for any backreferences.
*/
rc = msc_regexec_capture(regex, target, target_length, ovector, 30, &my_error_msg);
#ifdef WITH_PCRE2
if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) {
#else
if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) {
#endif
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
if (s == NULL) return -1;
@ -1178,7 +1216,11 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
}
}
#ifdef WITH_PCRE2
if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
#endif
/* We no longer escape the pattern here as it is done when logging */
char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>"));
@ -1623,13 +1665,19 @@ static int verify_gsb(gsb_db *gsb, modsec_rec *msr, const char *match, unsigned
static int msre_op_gsbLookup_param_init(msre_rule *rule, char **error_msg) {
const char *errptr = NULL;
int erroffset;
int options = 0;
msc_regex_t *regex;
if (error_msg == NULL) return -1;
*error_msg = NULL;
/* Compile rule->op_param */
regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, PCRE_DOTALL | PCRE_MULTILINE, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
#ifdef WITH_PCRE2
options = PCRE2_DOTALL | PCRE2_MULTILINE;
#else
options = PCRE_DOTALL | PCRE_MULTILINE;
#endif
regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, options, &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",
@ -1659,6 +1707,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var
char *my_error_msg = NULL;
int ovector[33];
unsigned int offset = 0;
int options = 0;
gsb_db *gsb = msr->txcfg->gsb;
const char *match = NULL;
unsigned int match_length;
@ -1697,7 +1746,12 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var
memcpy(data,var->value,var->value_len);
while (offset < size && (rv = msc_regexec_ex(regex, data, size, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg)) >= 0)
#ifdef WITH_PCRE2
options = PCRE2_NOTEMPTY;
#else
options = PCRE_NOTEMPTY;
#endif
while (offset < size && (rv = msc_regexec_ex(regex, data, size, offset, options, ovector, 30, &my_error_msg)) >= 0)
{
for(i = 0; i < rv; ++i)
{
@ -2731,13 +2785,19 @@ static int luhn_verify(const char *ccnumber, int len) {
static int msre_op_verifyCC_init(msre_rule *rule, char **error_msg) {
const char *errptr = NULL;
int erroffset;
int options = 0;
msc_regex_t *regex;
if (error_msg == NULL) return -1;
*error_msg = NULL;
#ifdef WITH_PCRE2
options = PCRE2_DOTALL | PCRE2_MULTILINE;
#else
options = PCRE_DOTALL | PCRE_MULTILINE;
#endif
/* Compile rule->op_param */
regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, PCRE_DOTALL | PCRE_MULTILINE, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, options, &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);
@ -2758,6 +2818,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var *
int rc;
int is_cc = 0;
int offset;
int options = 0;
int matched_bytes = 0;
char *qspos = NULL;
const char *parm = NULL;
@ -2817,10 +2878,19 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var *
}
}
rc = msc_regexec_ex(regex, target, target_length, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg);
#ifdef WITH_PCRE2
options = PCRE2_NOTEMPTY;
#else
options = PCRE_NOTEMPTY;
#endif
rc = msc_regexec_ex(regex, target, target_length, offset, options, ovector, 30, &my_error_msg);
/* If there was no match, then we are done. */
#ifdef WITH_PCRE2
if (rc == PCRE2_ERROR_NOMATCH) {
#else
if (rc == PCRE_ERROR_NOMATCH) {
#endif
break;
}
@ -3029,13 +3099,19 @@ static int cpf_verify(const char *cpfnumber, int len) {
static int msre_op_verifyCPF_init(msre_rule *rule, char **error_msg) {
const char *errptr = NULL;
int erroffset;
int options = 0;
msc_regex_t *regex;
if (error_msg == NULL) return -1;
*error_msg = NULL;
#ifdef WITH_PCRE2
options = PCRE2_DOTALL | PCRE2_MULTILINE;
#else
options = PCRE_DOTALL | PCRE_MULTILINE;
#endif
/* Compile rule->op_param */
regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, PCRE_DOTALL | PCRE_MULTILINE, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, options, &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);
@ -3068,6 +3144,7 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var
int rc;
int is_cpf = 0;
int offset;
int options = 0;
int matched_bytes = 0;
char *qspos = NULL;
const char *parm = NULL;
@ -3127,10 +3204,19 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var
}
}
rc = msc_regexec_ex(regex, target, target_length, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg);
#ifdef WITH_PCRE2
options = PCRE2_NOTEMPTY;
#else
options = PCRE_NOTEMPTY;
#endif
rc = msc_regexec_ex(regex, target, target_length, offset, options, ovector, 30, &my_error_msg);
/* If there was no match, then we are done. */
#ifdef WITH_PCRE2
if (rc == PCRE2_ERROR_NOMATCH) {
#else
if (rc == PCRE_ERROR_NOMATCH) {
#endif
break;
}
@ -3323,13 +3409,19 @@ invalid:
static int msre_op_verifySSN_init(msre_rule *rule, char **error_msg) {
const char *errptr = NULL;
int erroffset;
int options = 0;
msc_regex_t *regex;
if (error_msg == NULL) return -1;
*error_msg = NULL;
#ifdef WITH_PCRE2
options = PCRE2_DOTALL | PCRE2_MULTILINE;
#else
options = PCRE_DOTALL | PCRE_MULTILINE;
#endif
/* Compile rule->op_param */
regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, PCRE_DOTALL | PCRE_MULTILINE, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, options, &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);
@ -3362,6 +3454,7 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var
int rc;
int is_ssn = 0;
int offset;
int options = 0;
int matched_bytes = 0;
char *qspos = NULL;
const char *parm = NULL;
@ -3421,10 +3514,19 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var
}
}
rc = msc_regexec_ex(regex, target, target_length, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg);
#ifdef WITH_PCRE2
options = PCRE2_NOTEMPTY;
#else
options = PCRE_NOTEMPTY;
#endif
rc = msc_regexec_ex(regex, target, target_length, offset, options, ovector, 30, &my_error_msg);
/* If there was no match, then we are done. */
#ifdef WITH_PCRE2
if (rc == PCRE2_ERROR_NOMATCH) {
#else
if (rc == PCRE_ERROR_NOMATCH) {
#endif
break;
}

View File

@ -1,6 +1,6 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
@ -21,6 +21,9 @@
#include "libxml/xpathInternals.h"
#ifdef WITH_PCRE2
#define PCRE_ERROR_NOMATCH PCRE2_ERROR_NOMATCH
#endif
/**
* Generates a variable from a string and a length.
*/
@ -64,12 +67,18 @@ static char *var_generic_list_validate(msre_ruleset *ruleset, msre_var *var) {
msc_regex_t *regex = NULL;
const char *errptr = NULL;
const char *pattern = NULL;
int options = 0;
int erroffset;
pattern = apr_pstrmemdup(ruleset->mp, var->param + 1, strlen(var->param + 1) - 1);
if (pattern == NULL) return FATAL_ERROR;
regex = msc_pregcomp(ruleset->mp, pattern, PCRE_DOTALL | PCRE_CASELESS | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset);
#ifdef WITH_PCRE2
options = PCRE2_DOTALL | PCRE2_CASELESS | PCRE2_DOLLAR_ENDONLY;
#else
options = PCRE_DOTALL | PCRE_CASELESS | PCRE_DOLLAR_ENDONLY;
#endif
regex = msc_pregcomp(ruleset->mp, pattern, options, &errptr, &erroffset);
if (regex == NULL) {
return apr_psprintf(ruleset->mp, "Error compiling pattern (offset %d): %s",
erroffset, errptr);

View File

@ -82,7 +82,6 @@ AC_SUBST(PCRE_LD_PATH)
if test -z "${PCRE_VERSION}"; then
AC_MSG_NOTICE([*** pcre library not found.])
ifelse([$2], , AC_MSG_ERROR([pcre library is required]), $2)
else
AC_MSG_NOTICE([using pcre v${PCRE_VERSION}])
ifelse([$1], , , $1)

87
build/find_pcre2.m4 Normal file
View File

@ -0,0 +1,87 @@
dnl Check for PCRE2 Libraries
dnl CHECK_PCRE2(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
dnl Sets:
dnl PCRE2_CFLAGS
dnl PCRE2_LIBS
PCRE2_CONFIG=""
PCRE2_VERSION=""
PCRE2_CPPFLAGS=""
PCRE2_CFLAGS=""
PCRE2_LDFLAGS=""
PCRE2_LDADD=""
PCRE_LD_PATH=""
AC_DEFUN([CHECK_PCRE2],
[dnl
AC_ARG_WITH(
pcre2,
[AC_HELP_STRING([--with-pcre2=PATH],[Path to pcre2 prefix or config script])],
, with_pcre2=yes)
AS_CASE(["${with_pcre2}"],
[no], [test_paths=],
[yes], [test_paths="/usr/local/libpcre2 /usr/local/pcre2 /usr/local /opt/libpcre2 /opt/pcre2 /opt /usr"],
[test_paths="${with_pcre2}"])
AC_MSG_CHECKING([for libpcre2 config script])
for x in ${test_paths}; do
dnl # Determine if the script was specified and use it directly
if test ! -d "$x" -a -e "$x"; then
PCRE2_CONFIG=$x
pcre2_path="no"
break
fi
dnl # Try known config script names/locations
for PCRE2_CONFIG in pcre2-config; do
if test -e "${x}/bin/${PCRE2_CONFIG}"; then
pcre2_path="${x}/bin"
break
elif test -e "${x}/${PCRE2_CONFIG}"; then
pcre2_path="${x}"
break
else
pcre2_path=""
fi
done
if test -n "$pcre2_path"; then
break
fi
done
if test -n "${pcre2_path}"; then
if test "${pcre2_path}" != "no"; then
PCRE2_CONFIG="${pcre2_path}/${PCRE2_CONFIG}"
fi
AC_MSG_RESULT([${PCRE2_CONFIG}])
PCRE2_VERSION="`${PCRE2_CONFIG} --version`"
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 VERSION: $PCRE2_VERSION); fi
PCRE2_CFLAGS="`${PCRE2_CONFIG} --cflags`"
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 CFLAGS: $PCRE2_CFLAGS); fi
PCRE2_LDADD="`${PCRE2_CONFIG} --libs8`"
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 LDADD: $PCRE2_LDADD); fi
PCRE_LD_PATH="/`${PCRE2_CONFIG} --libs8 | cut -d'/' -f2,3,4,5,6 | cut -d ' ' -f1`"
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 PCRE_LD_PATH: $PCRE_LD_PATH); fi
else
AC_MSG_RESULT([no])
fi
AC_SUBST(PCRE2_CONFIG)
AC_SUBST(PCRE2_VERSION)
AC_SUBST(PCRE2_CPPFLAGS)
AC_SUBST(PCRE2_CFLAGS)
AC_SUBST(PCRE2_LDFLAGS)
AC_SUBST(PCRE2_LDADD)
AC_SUBST(PCRE_LD_PATH)
if test -z "${PCRE2_VERSION}"; then
AC_MSG_NOTICE([*** pcre2 library not found.])
else
AC_MSG_NOTICE([using pcre2 v${PCRE2_VERSION}])
PCRE2_CFLAGS="-DWITH_PCRE2 ${PCRE2_CFLAGS}"
ifelse([$1], , , $1)
fi
])

View File

@ -865,6 +865,7 @@ AC_SUBST(APXS_MODULES)
AC_SUBST(APXS_HTTPD)
CHECK_PCRE()
CHECK_PCRE2()
if test "$build_apache2_module" -ne 0 -o "$build_mlogc" -ne 0; then
CHECK_APR()
CHECK_APU()