Skip to content

Commit 9d4b426

Browse files
authored
Merge pull request #2844 from martinhsv/v2/master
Support configurable limit on number of arguments processed
2 parents ac52086 + 0981b32 commit 9d4b426

File tree

6 files changed

+109
-4
lines changed

6 files changed

+109
-4
lines changed

CHANGES

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
DD mmm YYYY - 2.9.x (to be released)
22
-------------------
33

4+
* Support configurable limit on number of arguments processed
5+
[Issue #2844 - @jleproust, @martinhsv]
46
* Silence compiler warning about discarded const
57
[Issue #2843 - @Steve8291, @martinhsv]
68
* Support for JIT option for PCRE2

apache2/apache2_config.c

+30
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ void *create_directory_config(apr_pool_t *mp, char *path)
5454
dcfg->reqbody_limit = NOT_SET;
5555
dcfg->reqbody_no_files_limit = NOT_SET;
5656
dcfg->reqbody_json_depth_limit = NOT_SET;
57+
dcfg->arguments_limit = NOT_SET;
5758
dcfg->resbody_access = NOT_SET;
5859

5960
dcfg->debuglog_name = NOT_SET_P;
@@ -338,6 +339,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
338339
? parent->reqbody_no_files_limit : child->reqbody_no_files_limit);
339340
merged->reqbody_json_depth_limit = (child->reqbody_json_depth_limit == NOT_SET
340341
? parent->reqbody_json_depth_limit : child->reqbody_json_depth_limit);
342+
merged->arguments_limit = (child->arguments_limit == NOT_SET
343+
? parent->arguments_limit : child->arguments_limit);
341344
merged->resbody_access = (child->resbody_access == NOT_SET
342345
? parent->resbody_access : child->resbody_access);
343346

@@ -655,6 +658,7 @@ void init_directory_config(directory_config *dcfg)
655658
if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT;
656659
if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT;
657660
if (dcfg->reqbody_json_depth_limit == NOT_SET) dcfg->reqbody_json_depth_limit = REQUEST_BODY_JSON_DEPTH_DEFAULT_LIMIT;
661+
if (dcfg->arguments_limit == NOT_SET) dcfg->arguments_limit = ARGUMENTS_LIMIT;
658662
if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0;
659663
if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT;
660664
if (dcfg->if_limit_action == NOT_SET) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
@@ -1955,6 +1959,24 @@ static const char *cmd_request_body_json_depth_limit(cmd_parms *cmd, void *_dcfg
19551959
return NULL;
19561960
}
19571961

1962+
static const char *cmd_arguments_limit(cmd_parms *cmd, void *_dcfg,
1963+
const char *p1)
1964+
{
1965+
directory_config *dcfg = (directory_config *)_dcfg;
1966+
long int limit;
1967+
1968+
if (dcfg == NULL) return NULL;
1969+
1970+
limit = strtol(p1, NULL, 10);
1971+
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
1972+
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecArgumentsLimit: %s", p1);
1973+
}
1974+
1975+
dcfg->arguments_limit = limit;
1976+
1977+
return NULL;
1978+
}
1979+
19581980
static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg,
19591981
const char *p1)
19601982
{
@@ -3596,6 +3618,14 @@ const command_rec module_directives[] = {
35963618
"maximum request body JSON parsing depth ModSecurity will accept."
35973619
),
35983620

3621+
AP_INIT_TAKE1 (
3622+
"SecArgumentsLimit",
3623+
cmd_arguments_limit,
3624+
NULL,
3625+
CMD_SCOPE_ANY,
3626+
"maximum number of ARGS that ModSecurity will accept."
3627+
),
3628+
35993629
AP_INIT_TAKE1 (
36003630
"SecRequestEncoding",
36013631
cmd_request_encoding,

apache2/modsecurity.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
3-
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
3+
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
44
*
55
* You may not use this file except in compliance with
66
* the License.  You may obtain a copy of the License at
@@ -96,6 +96,7 @@ typedef struct msc_parm msc_parm;
9696
#define REQUEST_BODY_DEFAULT_LIMIT 134217728
9797
#define REQUEST_BODY_NO_FILES_DEFAULT_LIMIT 1048576
9898
#define REQUEST_BODY_JSON_DEPTH_DEFAULT_LIMIT 10000
99+
#define ARGUMENTS_LIMIT 1000
99100
#define RESPONSE_BODY_DEFAULT_LIMIT 524288
100101
#define RESPONSE_BODY_HARD_LIMIT 1073741824L
101102

@@ -500,6 +501,7 @@ struct directory_config {
500501
long int reqbody_limit;
501502
long int reqbody_no_files_limit;
502503
long int reqbody_json_depth_limit;
504+
long int arguments_limit;
503505
int resbody_access;
504506

505507
long int of_limit;

apache2/msc_json.c

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
3-
* Copyright (c) 2004-2011 Trustwave Holdings, Inc. (http://www.trustwave.com/)
3+
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
44
*
55
* You may not use this file except in compliance with
66
* the License.  You may obtain a copy of the License at
@@ -57,6 +57,15 @@ int json_add_argument(modsec_rec *msr, const char *value, unsigned length)
5757
msr_log(msr, 9, "Adding JSON argument '%s' with value '%s'",
5858
arg->name, arg->value);
5959
}
60+
if (apr_table_elts(msr->arguments)->nelts >= msr->txcfg->arguments_limit) {
61+
if (msr->txcfg->debuglog_level >= 4) {
62+
msr_log(msr, 4, "Skipping request argument, over limit (%s): name \"%s\", value \"%s\"",
63+
arg->origin, log_escape_ex(msr->mp, arg->name, arg->name_len),
64+
log_escape_ex(msr->mp, arg->value, arg->value_len));
65+
}
66+
msr->msc_reqbody_error = 1;
67+
return 0;
68+
}
6069

6170
apr_table_addn(msr->arguments,
6271
log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *) arg);

apache2/msc_parsers.c

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
3-
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
3+
* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
44
*
55
* You may not use this file except in compliance with
66
* the License.  You may obtain a copy of the License at
@@ -346,6 +346,21 @@ void add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg)
346346
log_escape_ex(msr->mp, arg->value, arg->value_len));
347347
}
348348

349-
apr_table_addn(arguments, log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *)arg);
349+
if (apr_table_elts(arguments)->nelts >= msr->txcfg->arguments_limit) {
350+
if (msr->txcfg->debuglog_level >= 4) {
351+
msr_log(msr, 4, "Skipping request argument, over limit (%s): name \"%s\", value \"%s\"",
352+
arg->origin, log_escape_ex(msr->mp, arg->name, arg->name_len),
353+
log_escape_ex(msr->mp, arg->value, arg->value_len));
354+
}
355+
if (msr->msc_reqbody_error != 1) {
356+
char *error_msg = apr_psprintf(msr->mp, "SecArgumentsLimit exceeded");
357+
msr->msc_reqbody_error = 1;
358+
if (error_msg != NULL) {
359+
msr->msc_reqbody_error_msg = error_msg;
360+
}
361+
}
362+
} else {
363+
apr_table_addn(arguments, log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *)arg);
364+
}
350365
}
351366

tests/regression/config/10-request-directives.t

+47
Original file line numberDiff line numberDiff line change
@@ -703,3 +703,50 @@
703703
),
704704
},
705705

706+
# SecArgumentsLimit
707+
{
708+
type => "config",
709+
comment => "SecArgumentsLimit (pos)",
710+
conf => qq(
711+
SecRuleEngine On
712+
SecRequestBodyAccess On
713+
SecArgumentsLimit 5
714+
SecRule REQBODY_ERROR "!\@eq 0" "id:'500232',phase:2,log,deny,status:403,msg:'Failed to parse request body'"
715+
),
716+
match_log => {
717+
error => [ qr/Access denied with code 403 /, 1 ],
718+
},
719+
match_response => {
720+
status => qr/^403$/,
721+
},
722+
request => new HTTP::Request(
723+
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
724+
[
725+
"Content-Type" => "application/x-www-form-urlencoded",
726+
],
727+
"a=1&b=2&c=3&d=4&e=5&f=6",
728+
),
729+
},
730+
{
731+
type => "config",
732+
comment => "SecArgumentsLimit (neg)",
733+
conf => qq(
734+
SecRuleEngine On
735+
SecRequestBodyAccess On
736+
SecArgumentsLimit 5
737+
SecRule REQBODY_ERROR "!\@eq 0" "id:'500233',phase:2,log,deny,status:403,msg:'Failed to parse request body'"
738+
),
739+
match_log => {
740+
},
741+
match_response => {
742+
status => qr/^200$/,
743+
},
744+
request => new HTTP::Request(
745+
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
746+
[
747+
"Content-Type" => "application/x-www-form-urlencoded",
748+
],
749+
"a=1&b=2&c=3&d=4&e=5",
750+
),
751+
},
752+

0 commit comments

Comments
 (0)