Skip to content

Commit a43a773

Browse files
committed
Update Regex util to support match limits
If the rx or rxGlobal operator encounters a regex error, the RX_ERROR and RX_ERROR_RULE_ID variables are set. RX_ERROR contains a simple error code which can be either OTHER or MATCH_LIMIT. RX_ERROR_RULE_ID unsurprisingly contains the ID of the rule associated with the error. More than one rule may encounter regex errors, but only the first error is reflected in these variables.
1 parent 369002d commit a43a773

17 files changed

+7513
-7121
lines changed

Diff for: headers/modsecurity/rules_set_properties.h

+2
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ class RulesSetProperties {
379379
from->m_responseBodyLimitAction,
380380
PropertyNotSetBodyLimitAction);
381381

382+
to->m_pcreMatchLimit.merge(&from->m_pcreMatchLimit);
382383
to->m_uploadFileLimit.merge(&from->m_uploadFileLimit);
383384
to->m_uploadFileMode.merge(&from->m_uploadFileMode);
384385
to->m_uploadDirectory.merge(&from->m_uploadDirectory);
@@ -470,6 +471,7 @@ class RulesSetProperties {
470471
ConfigDouble m_requestBodyLimit;
471472
ConfigDouble m_requestBodyNoFilesLimit;
472473
ConfigDouble m_responseBodyLimit;
474+
ConfigInt m_pcreMatchLimit;
473475
ConfigInt m_uploadFileLimit;
474476
ConfigInt m_uploadFileMode;
475477
DebugLog *m_debugLog;

Diff for: headers/modsecurity/transaction.h

+4
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ class TransactionAnchoredVariables {
184184
m_variableUniqueID(t, "UNIQUE_ID"),
185185
m_variableUrlEncodedError(t, "URLENCODED_ERROR"),
186186
m_variableUserID(t, "USERID"),
187+
m_variableRxError(t, "RX_ERROR"),
188+
m_variableRxErrorRuleID(t, "RX_ERROR_RULE_ID"),
187189
m_variableArgs(t, "ARGS"),
188190
m_variableArgsGet(t, "ARGS_GET"),
189191
m_variableArgsPost(t, "ARGS_POST"),
@@ -264,6 +266,8 @@ class TransactionAnchoredVariables {
264266
AnchoredVariable m_variableUniqueID;
265267
AnchoredVariable m_variableUrlEncodedError;
266268
AnchoredVariable m_variableUserID;
269+
AnchoredVariable m_variableRxError;
270+
AnchoredVariable m_variableRxErrorRuleID;
267271

268272
AnchoredSetVariable m_variableArgs;
269273
AnchoredSetVariable m_variableArgsGet;

Diff for: src/operators/rx.cc

+31-2
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,41 @@ bool Rx::evaluate(Transaction *transaction, RuleWithActions *rule,
5151
re = m_re;
5252
}
5353

54-
std::vector<Utils::SMatchCapture> captures;
5554
if (re->hasError()) {
5655
ms_dbg_a(transaction, 3, "Error with regular expression: \"" + re->pattern + "\"");
5756
return false;
5857
}
59-
re->searchOneMatch(input, captures);
58+
59+
Utils::RegexResult regex_result;
60+
std::vector<Utils::SMatchCapture> captures;
61+
62+
if (transaction && transaction->m_rules->m_pcreMatchLimit.m_set) {
63+
unsigned long match_limit = transaction->m_rules->m_pcreMatchLimit.m_value;
64+
regex_result = re->searchOneMatch(input, captures, match_limit);
65+
} else {
66+
regex_result = re->searchOneMatch(input, captures);
67+
}
68+
69+
// FIXME: DRY regex error reporting. This logic is currently duplicated in other operators.
70+
if (regex_result != Utils::RegexResult::Ok) {
71+
std::string regex_error_str = "OTHER";
72+
if (regex_result == Utils::RegexResult::ErrorMatchLimit) {
73+
regex_error_str = "MATCH_LIMIT";
74+
}
75+
76+
ms_dbg_a(transaction, 1, "rx: regex error '" + regex_error_str + "' for pattern '" + re->pattern + "'");
77+
78+
// Only expose the first regex error to indicate there is an issue
79+
if (rule && transaction && transaction->m_variableRxError.m_value.empty()) {
80+
transaction->m_variableRxError.set(regex_error_str, transaction->m_variableOffset);
81+
transaction->m_variableRxErrorRuleID.set(
82+
std::to_string(rule->m_ruleId),
83+
transaction->m_variableOffset
84+
);
85+
}
86+
87+
return false;
88+
}
6089

6190
if (rule && rule->hasCaptureAction() && transaction) {
6291
for (const Utils::SMatchCapture& capture : captures) {

Diff for: src/operators/rx_global.cc

+29-1
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,36 @@ bool RxGlobal::evaluate(Transaction *transaction, RuleWithActions *rule,
5151
re = m_re;
5252
}
5353

54+
Utils::RegexResult regex_result;
5455
std::vector<Utils::SMatchCapture> captures;
55-
re->searchGlobal(input, captures);
56+
if (transaction && transaction->m_rules->m_pcreMatchLimit.m_set) {
57+
unsigned long match_limit = transaction->m_rules->m_pcreMatchLimit.m_value;
58+
regex_result = re->searchGlobal(input, captures, match_limit);
59+
} else {
60+
regex_result = re->searchGlobal(input, captures);
61+
}
62+
63+
// FIXME: DRY regex error reporting. This logic is currently duplicated in other operators.
64+
if (regex_result != Utils::RegexResult::Ok) {
65+
std::string regex_error_str = "OTHER";
66+
if (regex_result == Utils::RegexResult::ErrorMatchLimit) {
67+
regex_error_str = "MATCH_LIMIT";
68+
}
69+
70+
ms_dbg_a(transaction, 1, "rxGlobal: regex error '" + regex_error_str + "' for pattern '" + re->pattern + "'");
71+
72+
// Only expose the first regex error to indicate there is an issue
73+
if (rule && transaction && transaction->m_variableRxError.m_value.empty()) {
74+
transaction->m_variableRxError.set(regex_error_str, transaction->m_variableOffset);
75+
transaction->m_variableRxErrorRuleID.set(
76+
std::to_string(rule->m_ruleId),
77+
transaction->m_variableOffset
78+
);
79+
}
80+
81+
return false;
82+
}
83+
5684

5785
if (rule && rule->hasCaptureAction() && transaction) {
5886
for (const Utils::SMatchCapture& capture : captures) {

Diff for: src/parser/location.hh

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// A Bison parser, made by GNU Bison 3.7.2.
1+
// A Bison parser, made by GNU Bison 3.7.5.
22

33
// Locations for Bison parsers in C++
44

5-
// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc.
5+
// Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc.
66

77
// This program is free software: you can redistribute it and/or modify
88
// it under the terms of the GNU General Public License as published by

Diff for: src/parser/position.hh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// A Bison parser, made by GNU Bison 3.7.2.
1+
// A Bison parser, made by GNU Bison 3.7.5.
22

33
// Starting with Bison 3.2, this file is useless: the structure it
44
// used to define is now defined in "location.hh".

0 commit comments

Comments
 (0)