diff --git a/CVE-2022-48279.patch b/CVE-2022-48279.patch deleted file mode 100644 index ee54388eb8f96c27d63a656beac03e9904c3b545..0000000000000000000000000000000000000000 --- a/CVE-2022-48279.patch +++ /dev/null @@ -1,405 +0,0 @@ -From 7a489bd07c66d3df19a320b4306e00c49716dbb0 Mon Sep 17 00:00:00 2001 -From: Martin Vierula -Date: Wed, 7 Sep 2022 11:09:47 -0700 -Subject: [PATCH] Multipart parsing fixes and new MULTIPART_PART_HEADERS - collection - ---- - CHANGES | 2 + - apache2/msc_multipart.c | 148 ++++++++++++++------ - apache2/msc_multipart.h | 19 +++ - apache2/re_variables.c | 57 ++++++++ - tests/regression/misc/00-multipart-parser.t | 45 ++++++ - 5 files changed, 230 insertions(+), 41 deletions(-) - -diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c -index d087c863e..4128ab17e 100644 ---- a/apache2/msc_multipart.c -+++ b/apache2/msc_multipart.c -@@ -325,7 +325,14 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { - } - - msr->mpd->mpp_state = 1; -+ msr->mpd->mpp_substate_part_data_read = 0; - msr->mpd->mpp->last_header_name = NULL; -+ -+ /* Record the last part header line in the collection */ -+ if (msr->mpd->mpp->last_header_line != NULL) { -+ *(char **)apr_array_push(msr->mpd->mpp->header_lines) = msr->mpd->mpp->last_header_line; -+ msr_log(msr, 9, "Multipart: Added part header line \"%s\"", msr->mpd->mpp->last_header_line); -+ } - } else { - /* Header line. */ - -@@ -379,12 +386,28 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { - *error_msg = apr_psprintf(msr->mp, "Multipart: Part header too long."); - return -1; - } -+ if ((msr->mpd->mpp->last_header_line != NULL) && (msr->mpd->mpp->last_header_name != NULL) -+ && (new_value != NULL)) { -+ msr->mpd->mpp->last_header_line = apr_psprintf(msr->mp, -+ "%s: %s", msr->mpd->mpp->last_header_name, new_value); -+ } -+ - } else { - char *header_name, *header_value, *data; - - /* new header */ - -+ /* Record the most recently-seen part header line in the collection */ -+ if (msr->mpd->mpp->last_header_line != NULL) { -+ *(char **)apr_array_push(msr->mpd->mpp->header_lines) = msr->mpd->mpp->last_header_line; -+ msr_log(msr, 9, "Multipart: Added part header line \"%s\"", msr->mpd->mpp->last_header_line); -+ } -+ - data = msr->mpd->buf; -+ -+ msr->mpd->mpp->last_header_line = apr_pstrdup(msr->mp, data); -+ remove_lf_crlf_inplace(msr->mpd->mpp->last_header_line); -+ - while((*data != ':') && (*data != '\0')) data++; - if (*data == '\0') { - *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (colon missing): %s.", -@@ -438,6 +461,8 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) { - if (error_msg == NULL) return -1; - *error_msg = NULL; - -+ msr->mpd->mpp_substate_part_data_read = 1; -+ - /* Preserve some bytes for later. */ - if ( ((MULTIPART_BUF_SIZE - msr->mpd->bufleft) >= 1) - && (*(p - 1) == '\n') ) -@@ -680,10 +705,14 @@ static int multipart_process_boundary(modsec_rec *msr, int last_part, char **err - if (msr->mpd->mpp == NULL) return -1; - msr->mpd->mpp->type = MULTIPART_FORMDATA; - msr->mpd->mpp_state = 0; -+ msr->mpd->mpp_substate_part_data_read = 0; - - msr->mpd->mpp->headers = apr_table_make(msr->mp, 10); - if (msr->mpd->mpp->headers == NULL) return -1; - msr->mpd->mpp->last_header_name = NULL; -+ msr->mpd->mpp->last_header_line = NULL; -+ msr->mpd->mpp->header_lines = apr_array_make(msr->mp, 2, sizeof(char *)); -+ if (msr->mpd->mpp->header_lines == NULL) return -1; - - msr->mpd->reserve[0] = 0; - msr->mpd->reserve[1] = 0; -@@ -983,6 +1012,19 @@ int multipart_complete(modsec_rec *msr, char **error_msg) { - && (*(msr->mpd->buf + 2 + strlen(msr->mpd->boundary)) == '-') - && (*(msr->mpd->buf + 2 + strlen(msr->mpd->boundary) + 1) == '-') ) - { -+ if ((msr->mpd->crlf_state_buf_end == 2) && (msr->mpd->flag_lf_line != 1)) { -+ msr->mpd->flag_lf_line = 1; -+ if (msr->mpd->flag_crlf_line) { -+ msr_log(msr, 4, "Multipart: Warning: mixed line endings used (CRLF/LF)."); -+ } else { -+ msr_log(msr, 4, "Multipart: Warning: incorrect line endings used (LF)."); -+ } -+ } -+ if (msr->mpd->mpp_substate_part_data_read == 0) { -+ /* it looks like the final boundary, but it's where part data should begin */ -+ msr->mpd->flag_invalid_part = 1; -+ msr_log(msr, 4, "Multipart: Warning: Invalid part (data contains final boundary)"); -+ } - /* Looks like the final boundary - process it. */ - if (multipart_process_boundary(msr, 1 /* final */, error_msg) < 0) { - msr->mpd->flag_error = 1; -@@ -1075,54 +1117,63 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf, - if ( (strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 2) - && (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) ) - { -- char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary); -- int is_final = 0; -+ if (msr->mpd->crlf_state_buf_end == 2) { -+ msr->mpd->flag_lf_line = 1; -+ } -+ if ((msr->mpd->mpp_substate_part_data_read == 0) && (msr->mpd->boundary_count > 0)) { -+ /* string matches our boundary, but it's where part data should begin */ -+ msr->mpd->flag_invalid_part = 1; -+ msr_log(msr, 4, "Multipart: Warning: Invalid part (data contains boundary)"); -+ } else { -+ char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary); -+ int is_final = 0; -+ -+ /* Is this the final boundary? */ -+ if ((*boundary_end == '-') && (*(boundary_end + 1)== '-')) { -+ is_final = 1; -+ boundary_end += 2; -+ -+ if (msr->mpd->is_complete != 0) { -+ msr->mpd->flag_error = 1; -+ *error_msg = apr_psprintf(msr->mp, -+ "Multipart: Invalid boundary (final duplicate)."); -+ return -1; -+ } -+ } - -- /* Is this the final boundary? */ -- if ((*boundary_end == '-') && (*(boundary_end + 1)== '-')) { -- is_final = 1; -- boundary_end += 2; -+ /* Allow for CRLF and LF line endings. */ -+ if ( ( (*boundary_end == '\r') -+ && (*(boundary_end + 1) == '\n') -+ && (*(boundary_end + 2) == '\0') ) -+ || ( (*boundary_end == '\n') -+ && (*(boundary_end + 1) == '\0') ) ) -+ { -+ if (*boundary_end == '\n') { -+ msr->mpd->flag_lf_line = 1; -+ } else { -+ msr->mpd->flag_crlf_line = 1; -+ } - -- if (msr->mpd->is_complete != 0) { -- msr->mpd->flag_error = 1; -- *error_msg = apr_psprintf(msr->mp, -- "Multipart: Invalid boundary (final duplicate)."); -- return -1; -- } -- } -+ if (multipart_process_boundary(msr, (is_final ? 1 : 0), error_msg) < 0) { -+ msr->mpd->flag_error = 1; -+ return -1; -+ } - -- /* Allow for CRLF and LF line endings. */ -- if ( ( (*boundary_end == '\r') -- && (*(boundary_end + 1) == '\n') -- && (*(boundary_end + 2) == '\0') ) -- || ( (*boundary_end == '\n') -- && (*(boundary_end + 1) == '\0') ) ) -- { -- if (*boundary_end == '\n') { -- msr->mpd->flag_lf_line = 1; -- } else { -- msr->mpd->flag_crlf_line = 1; -- } -+ if (is_final) { -+ msr->mpd->is_complete = 1; -+ } - -- if (multipart_process_boundary(msr, (is_final ? 1 : 0), error_msg) < 0) { -+ processed_as_boundary = 1; -+ msr->mpd->boundary_count++; -+ } -+ else { -+ /* error */ - msr->mpd->flag_error = 1; -+ *error_msg = apr_psprintf(msr->mp, -+ "Multipart: Invalid boundary: %s", -+ log_escape_nq(msr->mp, msr->mpd->buf)); - return -1; - } -- -- if (is_final) { -- msr->mpd->is_complete = 1; -- } -- -- processed_as_boundary = 1; -- msr->mpd->boundary_count++; -- } -- else { -- /* error */ -- msr->mpd->flag_error = 1; -- *error_msg = apr_psprintf(msr->mp, -- "Multipart: Invalid boundary: %s", -- log_escape_nq(msr->mp, msr->mpd->buf)); -- return -1; - } - } else { /* It looks like a boundary but we couldn't match it. */ - char *p = NULL; -@@ -1221,6 +1272,21 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf, - msr->mpd->bufptr = msr->mpd->buf; - msr->mpd->bufleft = MULTIPART_BUF_SIZE; - msr->mpd->buf_contains_line = (c == 0x0a) ? 1 : 0; -+ -+ if (c == 0x0a) { -+ if (msr->mpd->crlf_state == 1) { -+ msr->mpd->crlf_state = 3; -+ } else { -+ msr->mpd->crlf_state = 2; -+ } -+ } -+ msr->mpd->crlf_state_buf_end = msr->mpd->crlf_state; -+ } -+ -+ if (c == 0x0d) { -+ msr->mpd->crlf_state = 1; -+ } else if (c != 0x0a) { -+ msr->mpd->crlf_state = 0; - } - - if ((msr->mpd->is_complete) && (inleft != 0)) { -diff --git a/apache2/msc_multipart.h b/apache2/msc_multipart.h -index a0f6a08dd..13db0658f 100644 ---- a/apache2/msc_multipart.h -+++ b/apache2/msc_multipart.h -@@ -55,6 +55,8 @@ struct multipart_part { - - char *last_header_name; - apr_table_t *headers; -+ char *last_header_line; -+ apr_array_header_t *header_lines; - - unsigned int offset; - unsigned int length; -@@ -81,6 +83,15 @@ struct multipart_data { - char *bufptr; - int bufleft; - -+ /* line ending status seen immediately before current position. -+ * 0 = neither LF nor CR; 1 = prev char CR; 2 = prev char LF alone; -+ * 3 = prev two chars were CRLF -+ */ -+ int crlf_state; -+ -+ /* crlf_state at end of previous buffer */ -+ int crlf_state_buf_end; -+ - unsigned int buf_offset; - - /* pointer that keeps track of a part while -@@ -94,6 +105,14 @@ struct multipart_data { - */ - int mpp_state; - -+ /* part parsing substate; if mpp_state is 1 (collecting -+ * data), then for this variable: -+ * 0 means we have not yet read any data between the -+ * post-headers blank line and the next boundary -+ * 1 means we have read at some data after that blank line -+ */ -+ int mpp_substate_part_data_read; -+ - /* because of the way this parsing algorithm - * works we hold back the last two bytes of - * each data chunk so that we can discard it -diff --git a/apache2/re_variables.c b/apache2/re_variables.c -index 400738615..f3015acd9 100644 ---- a/apache2/re_variables.c -+++ b/apache2/re_variables.c -@@ -1394,6 +1394,52 @@ static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre - return 1; - } - -+/* MULTIPART_PART_HEADERS */ -+ -+static int var_multipart_part_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, -+ apr_table_t *vartab, apr_pool_t *mptmp) -+{ -+ multipart_part **parts = NULL; -+ int i, j, count = 0; -+ -+ if (msr->mpd == NULL) return 0; -+ -+ parts = (multipart_part **)msr->mpd->parts->elts; -+ for(i = 0; i < msr->mpd->parts->nelts; i++) { -+ int match = 0; -+ -+ /* Figure out if we want to include this variable. */ -+ if (var->param == NULL) match = 1; -+ else { -+ if (var->param_data != NULL) { /* Regex. */ -+ char *my_error_msg = NULL; -+ if (!(msc_regexec((msc_regex_t *)var->param_data, parts[i]->name, -+ strlen(parts[i]->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; -+ } else { /* Simple comparison. */ -+ if (strcasecmp(parts[i]->name, var->param) == 0) match = 1; -+ } -+ } -+ -+ /* If we had a match add this argument to the collection. */ -+ if (match) { -+ for (j = 0; j < parts[i]->header_lines->nelts; j++) { -+ char *header_line = ((char **)parts[i]->header_lines->elts)[j]; -+ msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); -+ -+ rvar->value = header_line; -+ rvar->value_len = strlen(rvar->value); -+ rvar->name = apr_psprintf(mptmp, "MULTIPART_PART_HEADERS:%s", -+ log_escape_nq(mptmp, parts[i]->name)); -+ apr_table_addn(vartab, rvar->name, (void *)rvar); -+ -+ count++; -+ } -+ } -+ } -+ -+ return count; -+} -+ - /* MODSEC_BUILD */ - - static int var_modsec_build_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, -@@ -2966,6 +3012,17 @@ void msre_engine_register_default_variables(msre_engine *engine) { - PHASE_REQUEST_BODY - ); - -+ /* MULTIPART_PART_HEADERS */ -+ msre_engine_variable_register(engine, -+ "MULTIPART_PART_HEADERS", -+ VAR_LIST, -+ 0, 1, -+ var_generic_list_validate, -+ var_multipart_part_headers_generate, -+ VAR_CACHE, -+ PHASE_REQUEST_BODY -+ ); -+ - /* GEO */ - msre_engine_variable_register(engine, - "GEO", -diff --git a/tests/regression/misc/00-multipart-parser.t b/tests/regression/misc/00-multipart-parser.t -index 3c1f41b7d..e5ee4c13c 100644 ---- a/tests/regression/misc/00-multipart-parser.t -+++ b/tests/regression/misc/00-multipart-parser.t -@@ -1849,3 +1849,48 @@ - ), - }, - -+# part headers -+{ -+ type => "misc", -+ comment => "multipart parser (part headers)", -+ conf => qq( -+ SecRuleEngine On -+ SecDebugLog $ENV{DEBUG_LOG} -+ SecDebugLogLevel 9 -+ SecRequestBodyAccess On -+ SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny,status:400,id:500168" -+ SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny,status:400,id:500169" -+ SecRule MULTIPART_PART_HEADERS:image "\@rx content-type:.*jpeg" "phase:2,deny,status:403,id:500170,t:lowercase" -+ ), -+ match_log => { -+ debug => [ qr/500170.*against MULTIPART_PART_HEADERS:image.*Rule returned 1./s, 1 ], -+ }, -+ match_response => { -+ status => qr/^403$/, -+ }, -+ request => new HTTP::Request( -+ POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", -+ [ -+ "Content-Type" => q(multipart/form-data; boundary=0000), -+ ], -+ normalize_raw_request_data( -+ q( -+ --0000 -+ Content-Disposition: form-data; name="username" -+ -+ Bill -+ --0000 -+ Content-Disposition: form-data; name="email" -+ -+ bill@fakesite.com -+ --0000 -+ Content-Disposition: form-data; name="image"; filename="image.jpg" -+ Content-Type: image/jpeg -+ -+ BINARYDATA -+ --0000-- -+ ), -+ ), -+ ), -+}, -+ diff --git a/mod_security-2.9.8-remote-rules-timeout.patch b/mod_security-2.9.8-remote-rules-timeout.patch new file mode 100644 index 0000000000000000000000000000000000000000..2814fdab59e278729989bcb26a299657f20179be --- /dev/null +++ b/mod_security-2.9.8-remote-rules-timeout.patch @@ -0,0 +1,85 @@ +diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c +index 80f8f2b..7912d84 100644 +--- a/apache2/apache2_config.c ++++ b/apache2/apache2_config.c +@@ -2354,6 +2354,24 @@ static const char *cmd_remote_rules(cmd_parms *cmd, void *_dcfg, const char *p1, + } + + ++static const char *cmd_remote_timeout(cmd_parms *cmd, void *_dcfg, const char *p1) ++{ ++ directory_config *dcfg = (directory_config *)_dcfg; ++ long int timeout; ++ ++ if (dcfg == NULL) return NULL; ++ ++ timeout = strtol(p1, NULL, 10); ++ if ((timeout == LONG_MAX)||(timeout == LONG_MIN)||(timeout < 0)) { ++ return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRemoteTimeout: %s", p1); ++ } ++ ++ remote_rules_timeout = timeout; ++ ++ return NULL; ++} ++ ++ + static const char *cmd_status_engine(cmd_parms *cmd, void *_dcfg, const char *p1) + { + assert(cmd != NULL); +@@ -3667,6 +3685,14 @@ const command_rec module_directives[] = { + "Abort or Warn" + ), + ++ AP_INIT_TAKE1 ( ++ "SecRemoteTimeout", ++ cmd_remote_timeout, ++ NULL, ++ CMD_SCOPE_ANY, ++ "timeout in seconds" ++ ), ++ + + AP_INIT_TAKE1 ( + "SecXmlExternalEntity", +diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c +index 7bb215e..c155495 100644 +--- a/apache2/mod_security2.c ++++ b/apache2/mod_security2.c +@@ -79,6 +79,8 @@ msc_remote_rules_server DSOLOCAL *remote_rules_server = NULL; + #endif + int DSOLOCAL remote_rules_fail_action = REMOTE_RULES_ABORT_ON_FAIL; + char DSOLOCAL *remote_rules_fail_message = NULL; ++unsigned long int DSOLOCAL remote_rules_timeout = NOT_SET; ++ + + int DSOLOCAL status_engine_state = STATUS_ENGINE_DISABLED; + +diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h +index f24bc75..8bcd453 100644 +--- a/apache2/modsecurity.h ++++ b/apache2/modsecurity.h +@@ -150,6 +150,7 @@ extern DSOLOCAL msc_remote_rules_server *remote_rules_server; + #endif + extern DSOLOCAL int remote_rules_fail_action; + extern DSOLOCAL char *remote_rules_fail_message; ++extern DSOLOCAL unsigned long int remote_rules_timeout; + + extern DSOLOCAL int status_engine_state; + +diff --git a/apache2/msc_remote_rules.c b/apache2/msc_remote_rules.c +index 99968f0..b8db13e 100644 +--- a/apache2/msc_remote_rules.c ++++ b/apache2/msc_remote_rules.c +@@ -358,6 +358,11 @@ int msc_remote_download_content(apr_pool_t *mp, const char *uri, const char *key + /* We want Curl to return error in case there is an HTTP error code */ + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); + ++ /* In case we want different timeout than a default one */ ++ if (remote_rules_timeout != NOT_SET){ ++ curl_easy_setopt(curl, CURLOPT_TIMEOUT, remote_rules_timeout); ++ } ++ + res = curl_easy_perform(curl); + + if (res != CURLE_OK) diff --git a/mod_security.conf b/mod_security.conf index 12e87c419715601f12e8406c37ad03022131ad8f..e9fe3ddcee5fb67af7c78b8c8613b17b06d3465e 100644 --- a/mod_security.conf +++ b/mod_security.conf @@ -1,226 +1,56 @@ -# -- Rule engine initialization ---------------------------------------------- - -# Enable ModSecurity, attaching it to every transaction. Use detection -# only to start with, because that minimises the chances of post-installation -# disruption. -# -SecRuleEngine DetectionOnly - - -# -- Request body handling --------------------------------------------------- - -# Allow ModSecurity to access request bodies. If you don't, ModSecurity -# won't be able to see any POST parameters, which opens a large security -# hole for attackers to exploit. -# -SecRequestBodyAccess On - - -# Enable XML request body parser. -# Initiate XML Processor in case of xml content-type -# -SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \ - "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" - -# Enable JSON request body parser. -# Initiate JSON Processor in case of JSON content-type; change accordingly -# if your application does not use 'application/json' -# -SecRule REQUEST_HEADERS:Content-Type "application/json" \ - "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" - -# Maximum request body size we will accept for buffering. If you support -# file uploads then the value given on the first line has to be as large -# as the largest file you are willing to accept. The second value refers -# to the size of data, with files excluded. You want to keep that value as -# low as practical. -# -SecRequestBodyLimit 13107200 -SecRequestBodyNoFilesLimit 131072 - -# Store up to 128 KB of request body data in memory. When the multipart -# parser reachers this limit, it will start using your hard disk for -# storage. That is slow, but unavoidable. -# -SecRequestBodyInMemoryLimit 131072 - -# What do do if the request body size is above our configured limit. -# Keep in mind that this setting will automatically be set to ProcessPartial -# when SecRuleEngine is set to DetectionOnly mode in order to minimize -# disruptions when initially deploying ModSecurity. -# -SecRequestBodyLimitAction Reject - -# Verify that we've correctly processed the request body. -# As a rule of thumb, when failing to process a request body -# you should reject the request (when deployed in blocking mode) -# or log a high-severity alert (when deployed in detection-only mode). -# -SecRule REQBODY_ERROR "!@eq 0" \ -"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2" - -# By default be strict with what we accept in the multipart/form-data -# request body. If the rule below proves to be too strict for your -# environment consider changing it to detection-only. You are encouraged -# _not_ to remove it altogether. -# -SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ -"id:'200003',phase:2,t:none,log,deny,status:400, \ -msg:'Multipart request body failed strict validation: \ -PE %{REQBODY_PROCESSOR_ERROR}, \ -BQ %{MULTIPART_BOUNDARY_QUOTED}, \ -BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ -DB %{MULTIPART_DATA_BEFORE}, \ -DA %{MULTIPART_DATA_AFTER}, \ -HF %{MULTIPART_HEADER_FOLDING}, \ -LF %{MULTIPART_LF_LINE}, \ -SM %{MULTIPART_MISSING_SEMICOLON}, \ -IQ %{MULTIPART_INVALID_QUOTING}, \ -IP %{MULTIPART_INVALID_PART}, \ -IH %{MULTIPART_INVALID_HEADER_FOLDING}, \ -FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'" - -# Did we see anything that might be a boundary? -# -SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \ -"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'" - -# PCRE Tuning -# We want to avoid a potential RegEx DoS condition -# -SecPcreMatchLimit 1000 -SecPcreMatchLimitRecursion 1000 - -# Some internal errors will set flags in TX and we will need to look for these. -# All of these are prefixed with "MSC_". The following flags currently exist: -# -# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded. -# -SecRule TX:/^MSC_/ "!@streq 0" \ - "id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" - - -# -- Response body handling -------------------------------------------------- - -# Allow ModSecurity to access response bodies. -# You should have this directive enabled in order to identify errors -# and data leakage issues. -# -# Do keep in mind that enabling this directive does increases both -# memory consumption and response latency. -# -SecResponseBodyAccess On - -# Which response MIME types do you want to inspect? You should adjust the -# configuration below to catch documents but avoid static files -# (e.g., images and archives). -# -SecResponseBodyMimeType text/plain text/html text/xml - -# Buffer response bodies of up to 512 KB in length. -SecResponseBodyLimit 524288 - -# What happens when we encounter a response body larger than the configured -# limit? By default, we process what we have and let the rest through. -# That's somewhat less secure, but does not break any legitimate pages. -# -SecResponseBodyLimitAction ProcessPartial - - -# -- Filesystem configuration ------------------------------------------------ - -# The location where ModSecurity stores temporary files (for example, when -# it needs to handle a file upload that is larger than the configured limit). -# -# This default setting is chosen due to all systems have /tmp available however, -# this is less than ideal. It is recommended that you specify a location that's private. -# -SecTmpDir /tmp/ - -# The location where ModSecurity will keep its persistent data. This default setting -# is chosen due to all systems have /tmp available however, it -# too should be updated to a place that other users can't access. -# -SecDataDir /tmp/ - - -# -- File uploads handling configuration ------------------------------------- - -# The location where ModSecurity stores intercepted uploaded files. This -# location must be private to ModSecurity. You don't want other users on -# the server to access the files, do you? -# -#SecUploadDir /opt/modsecurity/var/upload/ - -# By default, only keep the files that were determined to be unusual -# in some way (by an external inspection script). For this to work you -# will also need at least one file inspection rule. -# -#SecUploadKeepFiles RelevantOnly - -# Uploaded files are by default created with permissions that do not allow -# any other user to access them. You may need to relax that if you want to -# interface ModSecurity to an external program (e.g., an anti-virus). -# -#SecUploadFileMode 0600 - - -# -- Debug log configuration ------------------------------------------------- - -# The default debug log configuration is to duplicate the error, warning -# and notice messages from the error log. -# -#SecDebugLog /opt/modsecurity/var/log/debug.log -#SecDebugLogLevel 3 - - -# -- Audit log configuration ------------------------------------------------- - -# Log the transactions that are marked by a rule, as well as those that -# trigger a server error (determined by a 5xx or 4xx, excluding 404, -# level response status codes). -# -SecAuditEngine RelevantOnly -SecAuditLogRelevantStatus "^(?:5|4(?!04))" - -# Log everything we know about a transaction. -SecAuditLogParts ABIJDEFHZ - -# Use a single file for logging. This is much easier to look at, but -# assumes that you will use the audit log only ocassionally. -# -SecAuditLogType Serial -SecAuditLog /var/log/modsec_audit.log - -# Specify the path for concurrent audit logging. -#SecAuditLogStorageDir /opt/modsecurity/var/audit/ - - -# -- Miscellaneous ----------------------------------------------------------- - -# Use the most commonly used application/x-www-form-urlencoded parameter -# separator. There's probably only one application somewhere that uses -# something else so don't expect to change this value. -# -SecArgumentSeparator & - -# Settle on version 0 (zero) cookies, as that is what most applications -# use. Using an incorrect cookie version may open your installation to -# evasion attacks (against the rules that examine named cookies). -# -SecCookieFormat 0 - -# Specify your Unicode Code Point. -# This mapping is used by the t:urlDecodeUni transformation function -# to properly map encoded data to your language. Properly setting -# these directives helps to reduce false positives and negatives. -# -#SecUnicodeMapFile unicode.mapping 20127 - -# Improve the quality of ModSecurity by sharing information about your -# current ModSecurity version and dependencies versions. -# The following information will be shared: ModSecurity version, -# Web Server version, APR version, PCRE version, Lua version, Libxml2 -# version, Anonymous unique id for host. -SecStatusEngine On - + + # Default recommended configuration + SecRuleEngine On + SecRequestBodyAccess On + SecRule REQUEST_HEADERS:Content-Type "text/xml" \ + "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" + SecRequestBodyLimit 13107200 + SecRequestBodyNoFilesLimit 131072 + SecRequestBodyInMemoryLimit 131072 + SecRequestBodyLimitAction Reject + SecRule REQBODY_ERROR "!@eq 0" \ + "id:'200001', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2" + SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ + "id:'200002',phase:2,t:none,log,deny,status:400,msg:'Multipart request body \ + failed strict validation: \ + PE %{REQBODY_PROCESSOR_ERROR}, \ + BQ %{MULTIPART_BOUNDARY_QUOTED}, \ + BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ + DB %{MULTIPART_DATA_BEFORE}, \ + DA %{MULTIPART_DATA_AFTER}, \ + HF %{MULTIPART_HEADER_FOLDING}, \ + LF %{MULTIPART_LF_LINE}, \ + SM %{MULTIPART_MISSING_SEMICOLON}, \ + IQ %{MULTIPART_INVALID_QUOTING}, \ + IP %{MULTIPART_INVALID_PART}, \ + IH %{MULTIPART_INVALID_HEADER_FOLDING}, \ + FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'" + + SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \ + "id:'200003',phase:2,t:none,log,deny,status:44,msg:'Multipart parser detected a possible unmatched boundary.'" + + SecPcreMatchLimit 1000 + SecPcreMatchLimitRecursion 1000 + + SecRule TX:/^MSC_/ "!@streq 0" \ + "id:'200004',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" + + SecResponseBodyAccess Off + SecDebugLog /var/log/httpd/modsec_debug.log + SecDebugLogLevel 0 + SecAuditEngine RelevantOnly + SecAuditLogRelevantStatus "^(?:5|4(?!04))" + SecAuditLogParts ABIJDEFHZ + SecAuditLogType Serial + SecAuditLog /var/log/httpd/modsec_audit.log + SecArgumentSeparator & + SecCookieFormat 0 + SecTmpDir /var/lib/mod_security + SecDataDir /var/lib/mod_security + + # ModSecurity Core Rules Set and Local configuration + Include modsecurity.d/*.conf + Include modsecurity.d/activated_rules/*.conf + Include modsecurity.d/local_rules/*.conf + + diff --git a/mod_security.spec b/mod_security.spec index 65bc83c7bf4be27ab31396270c899e96e9555b10..4c5510b30db3e476dd4edb55aa951b51154f4d99 100644 --- a/mod_security.spec +++ b/mod_security.spec @@ -6,28 +6,22 @@ %global mod_audit_log_collector 0 Name: mod_security -Version: 2.9.5 -Release: 10 +Version: 2.9.9 +Release: 1 Summary: Security module for the Apache HTTP Server -License: ASL 2.0 -URL: http://www.modsecurity.org/ -Source: https://github.com/SpiderLabs/ModSecurity/releases/download/v%{version}/modsecurity-%{version}.tar.gz +License: Apache-2.0 +URL: https://www.modsecurity.org/ +Source: https://github.com/owasp-modsecurity/ModSecurity/releases/download/v%{version}/modsecurity-v%{version}.tar.gz Source1: mod_security.conf Source2: 10-mod_security.conf Source3: modsecurity_localrules.conf -Patch0000: modsecurity-2.9.5-lua-54.patch -Patch0001: modsecurity-2.9.5-use-uid-if-user-name-is-not-available.patch -Patch0002: modsecurity-2.9.5-Properly-cleanup-XML-parser-contexts-upon-completion.patch -Patch0003: modsecurity-2.9.5-Add-SecRequestBodyJsonDepthLimit-to-modsecurity.conf.patch -Patch0004: modsecurity-2.9.5-Fix-memory-leak-that-occurs-on-JSON-parsing-error.patch -Patch0005: modsecurity-2.9.5-Set-SecStatusEngine-Off-in-modsecurity.conf.patch -Patch0006: modsecurity-2.9.5-Allow-no-key-single-value-JSON-body.patch -# https://github.com/SpiderLabs/ModSecurity/commit/51a30d7b406af95c4143560d9753cf0b6d2151f5 -Patch0007: CVE-2022-48279.patch +Patch0001: modsecurity-2.9.3-apulibs.patch +Patch0002: mod_security-2.9.8-remote-rules-timeout.patch + Requires: httpd httpd-mmn = %{_httpd_mmn} -BuildRequires: gcc make perl-generators httpd-devel yajl yajl-devel -BuildRequires: pkgconfig(lua) pkgconfig(libcurl) pkgconfig(libxml-2.0) pkgconfig(libpcre) +BuildRequires: gcc make perl-generators httpd-devel yajl yajl-devel pcre2-devel +BuildRequires: pkgconfig(lua) pkgconfig(libcurl) pkgconfig(libxml-2.0) BuildRequires: autoconf automake libtool %description @@ -46,14 +40,20 @@ This package collects mod_security audit log. %endif %prep -%autosetup -p1 -n modsecurity-%{version} +%autosetup -p1 -n modsecurity-v%{version} %build ./autogen.sh -%configure --with-yajl --with-apxs=%{_httpd_apxs} --enable-pcre-match-limit-recursion=1000000 --enable-pcre-match-limit=1000000 +%configure --enable-pcre-match-limit=1000000 \ + --enable-pcre-match-limit-recursion=1000000 \ + --with-apxs=%{_httpd_apxs} \ + --with-yajl \ + --with-pcre2 \ + --disable-static + sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool -make %{_smp_mflags} +%make_build %install install -d %{buildroot}%{_bindir} @@ -64,14 +64,14 @@ install -d %{buildroot}%{_sysconfdir}/httpd/modsecurity.d/ install -d %{buildroot}%{_sysconfdir}/httpd/modsecurity.d/local_rules install -d %{buildroot}%{_sysconfdir}/httpd/modsecurity.d/activated_rules install -m 700 -d $RPM_BUILD_ROOT%{_localstatedir}/lib/%{name} -install -Dp -m0644 %{SOURCE3} %{buildroot}%{_sysconfdir}/httpd/modsecurity.d/local_rules/ +install -Dp -m0644 %{S:3} %{buildroot}%{_sysconfdir}/httpd/modsecurity.d/local_rules/ %if "%{_httpd_modconfdir}" != "%{_httpd_confdir}" -install -Dp -m0644 %{SOURCE1} %{buildroot}%{_httpd_confdir}/mod_security.conf +install -Dp -m0644 %{S:1} %{buildroot}%{_httpd_confdir}/mod_security.conf sed -i 's/Include/IncludeOptional/' %{buildroot}%{_httpd_confdir}/mod_security.conf -install -Dp -m0644 %{SOURCE2} %{buildroot}%{_httpd_modconfdir}/10-mod_security.conf +install -Dp -m0644 %{S:2} %{buildroot}%{_httpd_modconfdir}/10-mod_security.conf %else install -d -m0755 %{buildroot}%{_httpd_confdir} -cat %{SOURCE2} %{SOURCE1} > %{buildroot}%{_httpd_confdir}/mod_security.conf +cat %{S:2} %{S:1} > %{buildroot}%{_httpd_confdir}/mod_security.conf %endif %if %mod_audit_log_collector @@ -83,7 +83,8 @@ install -m0755 mlogc/mlogc-batch-load.pl %{buildroot}%{_bindir}/mlogc-batch-load %endif %files -%doc README.* NOTICE LICENSE CHANGES +%license LICENSE +%doc README.* NOTICE CHANGES %{_httpd_moddir}/mod_security2.so %config(noreplace) %{_httpd_confdir}/*.conf %if "%{_httpd_modconfdir}" != "%{_httpd_confdir}" @@ -106,6 +107,16 @@ install -m0755 mlogc/mlogc-batch-load.pl %{buildroot}%{_bindir}/mlogc-batch-load %endif %changelog +* Mon May 26 2025 wangkai <13474090681@163.com> - 2.9.9-1 +- Update to 2.9.9 for fix CVE-2025-47947 + +* Mon Sep 09 2024 Funda Wang - 2.9.8-1 +- update to 2.9.8 + +* Mon Jul 17 2023 chenchen - 2.9.7-1 +- Upgrade to version 2.9.7 +- Fix CVE-2022-39956 + * Mon May 06 2024 yaoxin - 2.9.5-10 - Fix HTTP service startup failure diff --git a/mod_security.yaml b/mod_security.yaml index 7c8b49d3b0f39e66e680c466c4db67d7a951fb8f..69478be180b0c434ea41cfdb22315efe1727dc85 100644 --- a/mod_security.yaml +++ b/mod_security.yaml @@ -1,4 +1,4 @@ version_control: github -src_repo: SpiderLabs/ModSecurity +src_repo: owasp-modsecurity/ModSecurity tag_prefix: ^v -seperator: . +separator: . diff --git a/modsecurity-2.9.3-apulibs.patch b/modsecurity-2.9.3-apulibs.patch new file mode 100644 index 0000000000000000000000000000000000000000..bde44bb3c697ea447408c66b785c537d3a8e4d7b --- /dev/null +++ b/modsecurity-2.9.3-apulibs.patch @@ -0,0 +1,14 @@ + +Strip redundant APR-util dependent libraries, it is sufficient to link against -laprutil-1. + +--- modsecurity-2.9.3/build/find_apu.m4.apulibs ++++ modsecurity-2.9.3/build/find_apu.m4 +@@ -59,7 +59,7 @@ + APU_CFLAGS="`${APU_CONFIG} --includes`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu CFLAGS: $APU_CFLAGS); fi + APU_LDFLAGS="`${APU_CONFIG} --ldflags`" +- APU_LDFLAGS="$APU_LDFLAGS `${APU_CONFIG} --libs`" ++ APU_LDFLAGS="$APU_LDFLAGS `${APU_CONFIG} --avoid-ldap --avoid-dbm --libs`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LDFLAGS: $APU_LDFLAGS); fi + APU_LDADD="`${APU_CONFIG} --link-libtool`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LDADD: $APU_LDADD); fi diff --git a/modsecurity-2.9.5-Add-SecRequestBodyJsonDepthLimit-to-modsecurity.conf.patch b/modsecurity-2.9.5-Add-SecRequestBodyJsonDepthLimit-to-modsecurity.conf.patch deleted file mode 100644 index 3918deade2dbef08ded858068a3dfb13f690bd92..0000000000000000000000000000000000000000 --- a/modsecurity-2.9.5-Add-SecRequestBodyJsonDepthLimit-to-modsecurity.conf.patch +++ /dev/null @@ -1,30 +0,0 @@ -From d12959e18fccaf12708897baced782b9a63622fa Mon Sep 17 00:00:00 2001 -From: yaoguangzhong -Date: Sat, 7 Jan 2023 11:05:51 +0800 -Subject: [PATCH] Add SecRequestBodyJsonDepthLimit to - modsecurity.conf-recommended - -From Author: Martin Vierula ---- - modsecurity.conf-recommended | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended -index f357d95..c84ddce 100644 ---- a/modsecurity.conf-recommended -+++ b/modsecurity.conf-recommended -@@ -58,6 +58,11 @@ SecRequestBodyInMemoryLimit 131072 - # - SecRequestBodyLimitAction Reject - -+# Maximum parsing depth allowed for JSON objects. You want to keep this -+# value as low as practical. -+# -+SecRequestBodyJsonDepthLimit 512 -+ - # Verify that we've correctly processed the request body. - # As a rule of thumb, when failing to process a request body - # you should reject the request (when deployed in blocking mode) --- -2.27.0 - diff --git a/modsecurity-2.9.5-Allow-no-key-single-value-JSON-body.patch b/modsecurity-2.9.5-Allow-no-key-single-value-JSON-body.patch deleted file mode 100644 index c746e80c6ad881cd2de9e809e910d2f250c002ee..0000000000000000000000000000000000000000 --- a/modsecurity-2.9.5-Allow-no-key-single-value-JSON-body.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 630d57d7bd07696a72ac8ded7593bbcf31168a95 Mon Sep 17 00:00:00 2001 -From: yaoguangzhong -Date: Mon, 9 Jan 2023 16:00:15 +0800 -Subject: [PATCH] backport Allow no-key, single-value JSON body - -From Author: Martin Vierula -From commit 4a98032b7f827c4edd2514ce2af29222bb2ba289 -Signed-off-by: Guangzhong Yao ---- - apache2/msc_json.c | 3 +-- - apache2/msc_json.h | 2 +- - tests/regression/rule/15-json.t | 34 +++++++++++++++++++++++++++++++++ - 3 files changed, 36 insertions(+), 3 deletions(-) - -diff --git a/apache2/msc_json.c b/apache2/msc_json.c -index cbaab0e..bab3a6d 100644 ---- a/apache2/msc_json.c -+++ b/apache2/msc_json.c -@@ -27,8 +27,7 @@ int json_add_argument(modsec_rec *msr, const char *value, unsigned length) - * to reference this argument; for now we simply ignore these - */ - if (!msr->json->current_key) { -- msr_log(msr, 3, "Cannot add scalar value without an associated key"); -- return 1; -+ msr->json->current_key = ""; - } - - arg = (msc_arg *) apr_pcalloc(msr->mp, sizeof(msc_arg)); -diff --git a/apache2/msc_json.h b/apache2/msc_json.h -index 7e3d725..089dab4 100644 ---- a/apache2/msc_json.h -+++ b/apache2/msc_json.h -@@ -39,7 +39,7 @@ struct json_data { - - /* prefix is used to create data hierarchy (i.e., 'parent.child.value') */ - unsigned char *prefix; -- unsigned char *current_key; -+ const unsigned char *current_key; - long int current_depth; - int depth_limit_exceeded; - }; -diff --git a/tests/regression/rule/15-json.t b/tests/regression/rule/15-json.t -index f84355a..65f53ec 100644 ---- a/tests/regression/rule/15-json.t -+++ b/tests/regression/rule/15-json.t -@@ -224,6 +224,40 @@ - ), - ), - ), -+}, -+{ -+ type => "rule", -+ comment => "json parser - no-key single value", -+ conf => qq( -+ SecRuleEngine On -+ SecRequestBodyAccess On -+ SecDebugLog $ENV{DEBUG_LOG} -+ SecAuditEngine RelevantOnly -+ SecAuditLog "$ENV{AUDIT_LOG}" -+ SecDebugLogLevel 9 -+ SecRequestBodyJsonDepthLimit 3 -+ SecRule REQUEST_HEADERS:Content-Type "application/json" \\ -+ "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" -+ SecRule REQBODY_ERROR "!\@eq 0" "id:'200444',phase:2,log,deny,status:403,msg:'Failed to parse request body'" -+ SecRule ARGS "\@streq 25" "id:'200445',phase:2,log,deny,status:403" -+ ), -+ match_log => { -+ audit => [ qr/200445/s, 1 ], -+ }, -+ match_response => { -+ status => qr/^403$/, -+ }, -+ request => new HTTP::Request( -+ POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", -+ [ -+ "Content-Type" => "application/json", -+ ], -+ normalize_raw_request_data( -+ q( -+ 25 -+ ), -+ ), -+ ), - } - - --- -2.39.0.windows.2 - diff --git a/modsecurity-2.9.5-Fix-memory-leak-that-occurs-on-JSON-parsing-error.patch b/modsecurity-2.9.5-Fix-memory-leak-that-occurs-on-JSON-parsing-error.patch deleted file mode 100644 index 1ee6e1f36cece5e1cc7ef706fa18c3e01eafeca4..0000000000000000000000000000000000000000 --- a/modsecurity-2.9.5-Fix-memory-leak-that-occurs-on-JSON-parsing-error.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0951ccdfa2eee85e71ddcec6a45c87ce37772c69 Mon Sep 17 00:00:00 2001 -From: yaoguangzhong -Date: Sat, 7 Jan 2023 15:02:18 +0800 -Subject: [PATCH] Fix memory leak that occurs on JSON parsing error - -From Author: Martin Vierula -commit c6582df2e5e3a92ba4b90e2a6cfaeb89f61bcadf ---- - apache2/msc_json.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/apache2/msc_json.c b/apache2/msc_json.c -index d69e9eb..cbaab0e 100644 ---- a/apache2/msc_json.c -+++ b/apache2/msc_json.c -@@ -351,11 +351,12 @@ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char - /* Feed our parser and catch any errors */ - msr->json->status = yajl_parse(msr->json->handle, buf, size); - if (msr->json->status != yajl_status_ok) { -- /* We need to free the yajl error message later, how to do this? */ - if (msr->json->depth_limit_exceeded) { - *error_msg = "JSON depth limit exceeded"; - } else { -- *error_msg = yajl_get_error(msr->json->handle, 0, NULL, 0); -+ char *yajl_err = yajl_get_error(msr->json->handle, 0, buf, size); -+ *error_msg = apr_pstrdup(msr->mp, yajl_err); -+ yajl_free_error(msr->json->handle, yajl_err); - } - return -1; - } -@@ -375,11 +376,12 @@ int json_complete(modsec_rec *msr, char **error_msg) { - /* Wrap up the parsing process */ - msr->json->status = yajl_complete_parse(msr->json->handle); - if (msr->json->status != yajl_status_ok) { -- /* We need to free the yajl error message later, how to do this? */ - if (msr->json->depth_limit_exceeded) { - *error_msg = "JSON depth limit exceeded"; - } else { -- *error_msg = yajl_get_error(msr->json->handle, 0, NULL, 0); -+ char *yajl_err = yajl_get_error(msr->json->handle, 0, NULL, 0); -+ *error_msg = apr_pstrdup(msr->mp, yajl_err); -+ yajl_free_error(msr->json->handle, yajl_err); - } - - return -1; --- -2.27.0 - diff --git a/modsecurity-2.9.5-Properly-cleanup-XML-parser-contexts-upon-completion.patch b/modsecurity-2.9.5-Properly-cleanup-XML-parser-contexts-upon-completion.patch deleted file mode 100644 index e74ddde56f846d9a3a02302ffc9ed4bbd41dad81..0000000000000000000000000000000000000000 --- a/modsecurity-2.9.5-Properly-cleanup-XML-parser-contexts-upon-completion.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 6a5ec1ff7bd5a4a653da417f9a49a50cf5b2429d Mon Sep 17 00:00:00 2001 -From: Vladimir Krivopalov -Date: Mon, 13 Jan 2020 16:36:09 -0800 -Subject: [PATCH] Properly cleanup XML parser contexts upon completion - -It is currently possible that the XML parsing context is not properly -cleaned up if a parsed XML document is malformed. - -This fix makes sure that the context is taken care of. - -Signed-off-by: Vladimir Krivopalov ---- - apache2/msc_xml.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c -index a31decb5..9cc4da65 100644 ---- a/apache2/msc_xml.c -+++ b/apache2/msc_xml.c -@@ -137,6 +137,13 @@ int xml_complete(modsec_rec *msr, char **error_msg) { - * Frees the resources used for XML parsing. - */ - apr_status_t xml_cleanup(modsec_rec *msr) { -+ if (msr->xml->parsing_ctx != NULL) { -+ if (msr->xml->parsing_ctx->myDoc) { -+ xmlFreeDoc(msr->xml->parsing_ctx->myDoc); -+ } -+ xmlFreeParserCtxt(msr->xml->parsing_ctx); -+ msr->xml->parsing_ctx = NULL; -+ } - if (msr->xml->doc != NULL) { - xmlFreeDoc(msr->xml->doc); - msr->xml->doc = NULL; --- -2.27.0 - diff --git a/modsecurity-2.9.5-Set-SecStatusEngine-Off-in-modsecurity.conf.patch b/modsecurity-2.9.5-Set-SecStatusEngine-Off-in-modsecurity.conf.patch deleted file mode 100644 index ce14f7169e7c2052366fa59d78ce90a8f510a319..0000000000000000000000000000000000000000 --- a/modsecurity-2.9.5-Set-SecStatusEngine-Off-in-modsecurity.conf.patch +++ /dev/null @@ -1,28 +0,0 @@ -From fc84c6a3f6c446760350f80189d4bbfc116c143c Mon Sep 17 00:00:00 2001 -From: yaoguangzhong -Date: Sat, 7 Jan 2023 15:26:23 +0800 -Subject: [PATCH] backport Set SecStatusEngine Off in - modsecurity.conf-recommended - -From Author: Martin Vierula -commit 733427197e2fe4fabcbb0f43bd1e636ef923a6b4 ---- - modsecurity.conf-recommended | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended -index c84ddce..923f5d8 100644 ---- a/modsecurity.conf-recommended -+++ b/modsecurity.conf-recommended -@@ -234,5 +234,6 @@ SecUnicodeMapFile unicode.mapping 20127 - # The following information will be shared: ModSecurity version, - # Web Server version, APR version, PCRE version, Lua version, Libxml2 - # version, Anonymous unique id for host. --SecStatusEngine On -- -++# NB: As of April 2022, there is no longer any advantage to turning this -++# setting On, as there is no active receiver for the information. -++SecStatusEngine Off --- -2.27.0 - diff --git a/modsecurity-2.9.5-lua-54.patch b/modsecurity-2.9.5-lua-54.patch deleted file mode 100644 index 62dd671b02a0f3c01e79822bd637a84f14065bd9..0000000000000000000000000000000000000000 --- a/modsecurity-2.9.5-lua-54.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff -ru modsecurity-2.9.5/apache2/msc_lua.c modsecurity-2.9.5-lua-patch/apache2/msc_lua.c ---- modsecurity-2.9.5/apache2/msc_lua.c 2018-12-04 18:49:37.000000000 +0000 -+++ modsecurity-2.9.5-lua-patch/apache2/msc_lua.c 2020-08-08 16:55:14.936045777 +0000 -@@ -429,12 +429,12 @@ - #else - - /* Create new state. */ --#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 || LUA_VERSION_NUM == 501 -+#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 || LUA_VERSION_NUM == 501 || LUA_VERSION_NUM == 504 - L = luaL_newstate(); - #elif LUA_VERSION_NUM == 500 - L = lua_open(); - #else --#error We are only tested under Lua 5.0, 5.1, 5.2, or 5.3. -+#error We are only tested under Lua 5.0, 5.1, 5.2, 5.3 or 5.4. - #endif - luaL_openlibs(L); - -@@ -459,10 +459,10 @@ - /* Register functions. */ - #if LUA_VERSION_NUM == 500 || LUA_VERSION_NUM == 501 - luaL_register(L, "m", mylib); --#elif LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 -+#elif LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 || LUA_VERSION_NUM == 504 - luaL_setfuncs(L, mylib, 0); - #else --#error We are only tested under Lua 5.0, 5.1, 5.2, or 5.3. -+#error We are only tested under Lua 5.0, 5.1, 5.2, 5.3 or 5.4. - #endif - - lua_setglobal(L, "m"); diff --git a/modsecurity-2.9.5-use-uid-if-user-name-is-not-available.patch b/modsecurity-2.9.5-use-uid-if-user-name-is-not-available.patch deleted file mode 100644 index 648e6e19815070fe680b32a07c7b380beed18c4d..0000000000000000000000000000000000000000 --- a/modsecurity-2.9.5-use-uid-if-user-name-is-not-available.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 46c6cb2759327d94e619454dbe61f1e7639dd607 Mon Sep 17 00:00:00 2001 -From: Armin Abfalterer -Date: Tue, 12 Mar 2019 16:29:43 +0100 -Subject: [PATCH] use uid if user name is not available - ---- - apache2/msc_logging.c | 10 +++++++--- - apache2/persist_dbm.c | 29 +++++++++++++++++++---------- - 2 files changed, 26 insertions(+), 13 deletions(-) - -diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c -index d50f709e..d1a867c3 100644 ---- a/apache2/msc_logging.c -+++ b/apache2/msc_logging.c -@@ -234,16 +234,20 @@ static char *construct_auditlog_filename(apr_pool_t *mp, const char *uniqueid) { - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - * It also changes the return statement. - */ -- char *username; -+ char *userinfo; -+ apr_status_t rc; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, mp); -- apr_uid_name_get(&username, uid, mp); -+ rc = apr_uid_name_get(&userinfo, uid, mp); -+ if (rc != APR_SUCCESS) { -+ userinfo = apr_psprintf(mp, "%u", uid); -+ } - - apr_time_exp_lt(&t, apr_time_now()); - - apr_strftime(tstr, &len, 299, "/%Y%m%d/%Y%m%d-%H%M/%Y%m%d-%H%M%S", &t); -- return apr_psprintf(mp, "/%s%s-%s", username, tstr, uniqueid); -+ return apr_psprintf(mp, "/%s%s-%s", userinfo, tstr, uniqueid); - } - - /** -diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c -index efbbf6eb..e4f8036f 100644 ---- a/apache2/persist_dbm.c -+++ b/apache2/persist_dbm.c -@@ -104,11 +104,14 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ -- char *username; -+ char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); -- apr_uid_name_get(&username, uid, msr->mp); -+ rc = apr_uid_name_get(&userinfo, uid, msr->mp); -+ if (rc != APR_SUCCESS) { -+ userinfo = apr_psprintf(msr->mp, "%u", uid); -+ } - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " -@@ -117,7 +120,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec - goto cleanup; - } - -- dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", col_name, NULL); -+ dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), -@@ -385,11 +388,14 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ -- char *username; -+ char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); -- apr_uid_name_get(&username, uid, msr->mp); -+ rc = apr_uid_name_get(&userinfo, uid, msr->mp); -+ if (rc != APR_SUCCESS) { -+ userinfo = apr_psprintf(msr->mp, "%u", uid); -+ } - - var_name = (msc_string *)apr_table_get(col, "__name"); - if (var_name == NULL) { -@@ -409,7 +415,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { - } - - // ENH: lowercase the var name in the filename -- dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", var_name->value, NULL); -+ dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), -@@ -675,11 +681,14 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ -- char *username; -+ char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); -- apr_uid_name_get(&username, uid, msr->mp); -+ rc = apr_uid_name_get(&userinfo, uid, msr->mp); -+ if (rc != APR_SUCCESS) { -+ userinfo = apr_psprintf(msr->mp, "%u", uid); -+ } - - if (msr->txcfg->data_dir == NULL) { - /* The user has been warned about this problem enough times already by now. -@@ -690,9 +699,9 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { - } - - if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) -- dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", msr->txcfg->webappid, "_", col_name, NULL); -+ dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); - else -- dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", col_name, NULL); -+ dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), --- -2.27.0 - diff --git a/modsecurity-2.9.5.tar.gz b/modsecurity-v2.9.9.tar.gz similarity index 57% rename from modsecurity-2.9.5.tar.gz rename to modsecurity-v2.9.9.tar.gz index cbbf85bfd7b30fa238ae6cb1d2d59af9df977379..f3649b8e3b452c031dd1d8e826cc1d896eef1e00 100644 Binary files a/modsecurity-2.9.5.tar.gz and b/modsecurity-v2.9.9.tar.gz differ diff --git a/modsecurity_localrules.conf b/modsecurity_localrules.conf index 13935cd13185526fbf89d4e7bae60c0da363766c..983d7df3c459efa3b0c713f01e9ee7cee12f6419 100644 --- a/modsecurity_localrules.conf +++ b/modsecurity_localrules.conf @@ -1,3 +1,5 @@ +# User defined rules and settings . +# # You can use this file/directory to drop your local rules or # to remove some rules provided by mod_security_crs package with SecRuleRemoveById #