From 7379a4fb3f9e8adbc3c53c353ad110eeb728e2c9 Mon Sep 17 00:00:00 2001 From: b1v1r Date: Wed, 12 Aug 2009 23:03:11 +0000 Subject: [PATCH] Merge 2.5.x changes into trunk. --- CHANGES | 10 +- apache2/apache2_config.c | 22 +++- apache2/configure | 151 +++++++++++++++++++++- apache2/configure.in | 8 +- apache2/mlogc-src/Makefile.in | 2 +- apache2/mod_security2_config.h.in | 6 + apache2/re.c | 3 +- apache2/t/regression/rule/20-exceptions.t | 61 ++++++++- doc/modsecurity2-apache-reference.xml | 12 +- 9 files changed, 254 insertions(+), 21 deletions(-) diff --git a/CHANGES b/CHANGES index fc9d90b7..99800cfb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,11 @@ -27 July 2009 - trunk --------------------- +12 Aug 2009 - trunk +------------------- + + * Fixed crash on configuration if SecMarker is used before any rules. + + * Fixed SecRuleUpdateActionById so that it will work on chain starters. + + * Cleanup build system for mlogc. * Allow mlogc to periodically flush memory pools. diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 8168f610..67e6e995 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -565,6 +565,11 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, msre_rule *rule = NULL; extern msc_engine *modsecurity; + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Rule: type=%d p1='%s' p2='%s' p3='%s'", type, p1, p2, p3); + #endif + /* Create a ruleset if one does not exist. */ if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) { dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool); @@ -698,7 +703,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, #ifdef DEBUG_CONF ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, - "Adding rule %pp id=\"%s\".", rule, (rule->actionset->id == NOT_SET_P + "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id)); #endif @@ -749,6 +754,11 @@ static const char *add_marker(cmd_parms *cmd, directory_config *dcfg, const char extern msc_engine *modsecurity; int p; + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Rule: type=%d p1='%s' p2='%s' p3='%s'", RULE_TYPE_MARKER, p1, p2, p3); + #endif + /* Create a ruleset if one does not exist. */ if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) { dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool); @@ -766,13 +776,21 @@ static const char *add_marker(cmd_parms *cmd, directory_config *dcfg, const char /* Add placeholder to each phase */ for (p = PHASE_FIRST; p <= PHASE_LAST; p++) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P + ? "(none)" : rule->actionset->id)); + #endif + if (msre_ruleset_rule_add(dcfg->ruleset, rule, p) < 0) { return "Internal Error: Failed to add marker to the ruleset."; } } /* No longer need to search for the ID */ - apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id); + if (dcfg->tmp_rule_placeholders != NULL) { + apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id); + } return NULL; } diff --git a/apache2/configure b/apache2/configure index d9899bee..d7e87a10 100755 --- a/apache2/configure +++ b/apache2/configure @@ -701,6 +701,7 @@ CPPFLAGS LDFLAGS CXXFLAGS CXX +AWK target_alias host_alias build_alias @@ -1897,6 +1898,48 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Checks for programs. +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:$LINENO: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4549,6 +4592,110 @@ _ACEOF ;; esac +{ $as_echo "$as_me:$LINENO: checking for pid_t" >&5 +$as_echo_n "checking for pid_t... " >&6; } +if test "${ac_cv_type_pid_t+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_type_pid_t=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if (sizeof (pid_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if (sizeof ((pid_t))) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_pid_t=yes +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5 +$as_echo "$ac_cv_type_pid_t" >&6; } +if test "x$ac_cv_type_pid_t" = x""yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + { $as_echo "$as_me:$LINENO: checking for size_t" >&5 $as_echo_n "checking for size_t... " >&6; } if test "${ac_cv_type_size_t+set}" = set; then @@ -5138,7 +5285,8 @@ esac -for ac_func in atexit fchmod getcwd memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol + +for ac_func in atexit fchmod getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -6708,6 +6856,7 @@ gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' +AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF diff --git a/apache2/configure.in b/apache2/configure.in index ceed7ac2..beb943cc 100644 --- a/apache2/configure.in +++ b/apache2/configure.in @@ -4,15 +4,16 @@ dnl dnl Use ./buildconf to produce a configure script dnl -AC_PREREQ(2.50) +AC_PREREQ(2.63) -AC_INIT() +AC_INIT dnl AC_INIT(ModSecurity, 2.5, mod-security-users@lists.sourceforge.net, modsecurity-apache) AC_CONFIG_SRCDIR([mod_security2.c]) AC_CONFIG_HEADER([mod_security2_config.h]) AC_CONFIG_AUX_DIR([build]) # Checks for programs. +AC_PROG_AWK AC_PROG_CXX AC_PROG_CC AC_PROG_CPP @@ -32,6 +33,7 @@ AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h]) AC_C_CONST AC_C_INLINE AC_C_RESTRICT +AC_TYPE_PID_T AC_TYPE_SIZE_T AC_STRUCT_TM AC_TYPE_UINT8_T @@ -39,7 +41,7 @@ AC_TYPE_UINT8_T # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_MEMCMP -AC_CHECK_FUNCS([atexit fchmod getcwd memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol]) +AC_CHECK_FUNCS([atexit fchmod getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol]) # Some directories MSC_BASE_DIR=`pwd` diff --git a/apache2/mlogc-src/Makefile.in b/apache2/mlogc-src/Makefile.in index 9c23aea4..6b73c4d8 100755 --- a/apache2/mlogc-src/Makefile.in +++ b/apache2/mlogc-src/Makefile.in @@ -10,7 +10,7 @@ srclibdir = $(srcdir)/srclib MLOGC_VERSION = `grep '^\#define *VERSION ' mlogc.c | sed 's/.*VERSION *"\([^"]*\)"/\1/'` APR_FLAGS = @APR_CFLAGS@ -APR_LIBS = @APR_LINK_LD@ +APR_LIBS = @APR_LINK_LD@ @APR_LIBS@ CURL_FLAGS = @CURL_CFLAGS@ CURL_LIBS = @CURL_LIBS@ diff --git a/apache2/mod_security2_config.h.in b/apache2/mod_security2_config.h.in index c54ba287..e6a70445 100644 --- a/apache2/mod_security2_config.h.in +++ b/apache2/mod_security2_config.h.in @@ -22,6 +22,9 @@ to 0 otherwise. */ #undef HAVE_MALLOC +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H @@ -111,6 +114,9 @@ /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc +/* Define to `int' if does not define. */ +#undef pid_t + /* Define to the equivalent of the C99 'restrict' keyword, or to nothing if this is not supported. Do not define if restrict is supported directly. */ diff --git a/apache2/re.c b/apache2/re.c index 7f9da78a..4b5e2ae3 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -1188,8 +1188,9 @@ static msre_rule * msre_ruleset_fetch_phase_rule(const msre_ruleset *ruleset, co for (i = 0; i < phase_arr->nelts; i++) { msre_rule *rule = (msre_rule *)rules[i]; + /* Rule with an action, not a sub-rule (chain) and a matching id */ if ( (rule->actionset != NULL) - && !rule->actionset->is_chained + && (!rule->actionset->is_chained || !rule->chain_starter) && (rule->actionset->id != NULL) && (strcmp(rule->actionset->id, id) == 0)) { diff --git a/apache2/t/regression/rule/20-exceptions.t b/apache2/t/regression/rule/20-exceptions.t index 43ccf215..12c058e9 100644 --- a/apache2/t/regression/rule/20-exceptions.t +++ b/apache2/t/regression/rule/20-exceptions.t @@ -1,10 +1,8 @@ ### Tests for rule exceptions -# SecRuleRemoveByMsg - # SecRuleRemoveById { - type => "config", + type => "rule", comment => "SecRuleRemoveById (single)", conf => qq( SecRuleEngine On @@ -27,7 +25,7 @@ ), }, { - type => "config", + type => "rule", comment => "SecRuleRemoveById (multiple)", conf => qq( SecRuleEngine On @@ -52,7 +50,7 @@ ), }, { - type => "config", + type => "rule", comment => "SecRuleRemoveById (range)", conf => qq( SecRuleEngine On @@ -77,7 +75,7 @@ ), }, { - type => "config", + type => "rule", comment => "SecRuleRemoveById (multiple + range)", conf => qq( SecRuleEngine On @@ -105,7 +103,7 @@ # SecRuleRemoveByMsg { - type => "config", + type => "rule", comment => "SecRuleRemoveByMsg", conf => qq( SecRuleEngine On @@ -127,3 +125,52 @@ GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", ), }, + +# SecRuleUpdateActionById +{ + type => "rule", + comment => "SecRuleUpdateActionById", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1,msg:'testing rule'" + SecRuleUpdateActionById 1 "pass,nolog" + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + debug => [ qr/id:1,.*,pass,nolog/, 1 ], + -debug => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "rule", + comment => "SecRuleUpdateActionById (chain)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1,msg:'testing rule',chain" + SecRule ARGS "bar" + SecRuleUpdateActionById 1 "pass,nolog" + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + debug => [ qr/id:1,.*,pass,nolog/, 1 ], + -debug => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?foo=bar", + ), +}, diff --git a/doc/modsecurity2-apache-reference.xml b/doc/modsecurity2-apache-reference.xml index fe5cf757..4a240ef4 100644 --- a/doc/modsecurity2-apache-reference.xml +++ b/doc/modsecurity2-apache-reference.xml @@ -6,7 +6,7 @@ Manual - Version 2.6.0-trunk (July 27, 2009) + Version 2.6.0-trunk (Aug 12, 2009) 2004-2009 @@ -533,7 +533,7 @@ LoadFile /usr/lib/liblua5.1.so Example Usage: SecAction - nolog,initcol:RESOURCE=%{REQUEST_FILENAME} + nolog,phase:1,initcol:RESOURCE=%{REQUEST_FILENAME} Processing Phase: Any @@ -4753,10 +4753,14 @@ setvar:session.suspicious=1,expirevar:session.suspicious=3600Example: The following example initiates IP address tracking. - SecAction initcol:ip=%{REMOTE_ADDR},nolog + SecAction phase:1,initcol:ip=%{REMOTE_ADDR},nolog Note + Normally you will want to use phase:1 + along with initcol so that the collection is + available in all phases. + Collections are loaded into memory when the initcol action is encountered. The collection in storage will be persisted (and the appropriate counters increased) only if it was @@ -4775,7 +4779,7 @@ setvar:session.suspicious=1,expirevar:session.suspicious=3600Example: - SecAction initcol:ip=%{REMOTE_ADDR},log + SecAction phase:1,initcol:ip=%{REMOTE_ADDR},log Note