Skip to content

Commit 9a8ce8b

Browse files
committed
Refactoring Config*Int types
1 parent cf24aea commit 9a8ce8b

File tree

3 files changed

+1090
-946
lines changed

3 files changed

+1090
-946
lines changed

headers/modsecurity/rules_set_properties.h

Lines changed: 136 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313
*
1414
*/
1515

16+
#ifdef WIN32
17+
#ifdef max
18+
#undef max
19+
#endif
20+
#ifdef min
21+
#undef min
22+
#endif
23+
#endif
1624

1725
#ifdef __cplusplus
1826
#include <ctime>
@@ -22,6 +30,8 @@
2230
#include <list>
2331
#include <set>
2432
#include <cstring>
33+
#include <limits>
34+
#include <cstdint>
2535
#endif
2636

2737

@@ -68,29 +78,127 @@ class Driver;
6878
using modsecurity::debug_log::DebugLog;
6979
using modsecurity::audit_log::AuditLog;
7080

71-
/** @ingroup ModSecurity_CPP_API */
72-
class ConfigInt {
73-
public:
74-
ConfigInt() : m_set(false), m_value(0) { }
75-
bool m_set;
76-
int m_value;
81+
// template for different numeric int types
82+
template <typename T>
83+
class ConfigValue {
84+
public:
85+
bool m_set = false;
86+
T m_value = 0;
7787

78-
void merge(const ConfigInt *from) {
79-
if (m_set == true || from->m_set == false) {
80-
return;
81-
}
88+
ConfigValue() = default;
89+
90+
void merge(const ConfigValue<T>* from) {
91+
if (m_set || !from->m_set) return;
8292
m_set = true;
8393
m_value = from->m_value;
84-
return;
94+
}
95+
96+
// default parser
97+
bool parse(const std::string& a, std::string* errmsg = nullptr) {
98+
99+
// use an alias type because the template can convert both signed and unsigned int
100+
using LimitSigned = std::conditional_t<std::is_signed_v<T>, std::int64_t, std::uint64_t>;
101+
LimitSigned val;
102+
103+
// clear errno variable, wee need that later
104+
errno = 0;
105+
106+
try {
107+
if constexpr (std::is_signed_v<T>) {
108+
val = static_cast<std::int64_t>(std::stoll(a));
109+
} else {
110+
val = static_cast<std::uint64_t>(std::stoull(a));
111+
}
112+
}
113+
catch (const std::invalid_argument&) {
114+
// probably can't occur, but we handle it anyway
115+
set_error(errmsg, "Invalid number format (not numeric)");
116+
return false;
117+
}
118+
catch (const std::out_of_range&) {
119+
// the value is out of range, we can not handle it
120+
set_error(errmsg, "Number out of range");
121+
return false;
122+
}
123+
catch (...) { // NOSONAR
124+
// we don't need to handle all exceptions, the engine's BISON parser
125+
// does not allow other symbols than numbers
126+
set_error(errmsg, "An unknown error occurred while parsed the value.");
127+
return false;
128+
}
129+
130+
if (
131+
// first condition will be true if the value is bigger than int64/uint64 max value
132+
// the second condition checks if the value is fit as int64/uint64, but not fit for
133+
// designed type, eg. uint32; in that case the errno will be 0, but
134+
// we must check the value is not bigger than the given max() at the type class
135+
(errno == ERANGE && val == std::numeric_limits<LimitSigned>::max())
136+
||
137+
(val > static_cast<LimitSigned>(maxValue()))
138+
) {
139+
set_error(errmsg, "Value is too big.");
140+
return false;
141+
}
142+
143+
if (
144+
// same as above
145+
(errno == ERANGE && val == std::numeric_limits<LimitSigned>::min())
146+
||
147+
(val < static_cast<LimitSigned>(minValue()))
148+
) {
149+
set_error(errmsg, "Value is too small.");
150+
return false;
151+
}
152+
153+
m_value = static_cast<T>(val);
154+
m_set = true;
155+
return true;
156+
157+
}
158+
159+
protected:
160+
// derived classes must implement the maxValue
161+
virtual T maxValue() const = 0;
162+
// minValue is optional
163+
virtual T minValue() const { return 0; }
164+
165+
private:
166+
static inline void set_error(std::string* err, const char* msg) {
167+
if (err) *err = msg;
85168
}
86169
};
87170

171+
/** @ingroup ModSecurity_CPP_API */
172+
173+
class ConfigInt : public ConfigValue<int32_t> {
174+
protected:
175+
int32_t minValue() const override {
176+
return std::numeric_limits<int32_t>::min();
177+
}
178+
int32_t maxValue() const override {
179+
return std::numeric_limits<int32_t>::max();
180+
}
181+
};
182+
183+
class ConfigUnsignedInt : public ConfigValue<uint32_t> {
184+
protected:
185+
uint32_t maxValue() const override {
186+
return std::numeric_limits<uint32_t>::max();
187+
}
188+
};
189+
190+
class ConfigUnsignedLong : public ConfigValue<uint64_t> {
191+
protected:
192+
uint64_t maxValue() const override {
193+
return std::numeric_limits<uint64_t>::max();
194+
}
195+
};
88196

89197
class ConfigDouble {
90198
public:
91-
ConfigDouble() : m_set(false), m_value(0) { }
92-
bool m_set;
93-
double m_value;
199+
bool m_set = false;
200+
double m_value = 0.0;
201+
ConfigDouble() = default;
94202

95203
void merge(const ConfigDouble *from) {
96204
if (m_set == true || from->m_set == false) {
@@ -105,9 +213,9 @@ class ConfigDouble {
105213

106214
class ConfigString {
107215
public:
108-
ConfigString() : m_set(false), m_value("") { }
109-
bool m_set;
110-
std::string m_value;
216+
bool m_set = false;
217+
std::string m_value = "";
218+
ConfigString() = default;
111219

112220
void merge(const ConfigString *from) {
113221
if (m_set == true || from->m_set == false) {
@@ -122,10 +230,10 @@ class ConfigString {
122230

123231
class ConfigSet {
124232
public:
125-
ConfigSet() : m_set(false), m_clear(false) { }
126-
bool m_set;
127-
bool m_clear;
233+
bool m_set = false;
234+
bool m_clear = false;
128235
std::set<std::string> m_value;
236+
ConfigSet() = default;
129237
};
130238

131239

@@ -504,14 +612,14 @@ class RulesSetProperties {
504612
ConfigXMLParseXmlIntoArgs m_secXMLParseXmlIntoArgs;
505613
ConfigBoolean m_tmpSaveUploadedFiles;
506614
ConfigBoolean m_uploadKeepFiles;
507-
ConfigDouble m_argumentsLimit;
508-
ConfigDouble m_requestBodyJsonDepthLimit;
509-
ConfigDouble m_requestBodyLimit;
510-
ConfigDouble m_requestBodyNoFilesLimit;
511-
ConfigDouble m_responseBodyLimit;
512-
ConfigInt m_pcreMatchLimit;
513-
ConfigInt m_uploadFileLimit;
514-
ConfigInt m_uploadFileMode;
615+
ConfigUnsignedInt m_argumentsLimit;
616+
ConfigUnsignedInt m_requestBodyJsonDepthLimit;
617+
ConfigUnsignedLong m_requestBodyLimit;
618+
ConfigUnsignedLong m_requestBodyNoFilesLimit;
619+
ConfigUnsignedLong m_responseBodyLimit;
620+
ConfigUnsignedInt m_pcreMatchLimit;
621+
ConfigUnsignedInt m_uploadFileLimit;
622+
ConfigUnsignedInt m_uploadFileMode;
515623
DebugLog *m_debugLog;
516624
OnFailedRemoteRulesAction m_remoteRulesActionOnFailed;
517625
RuleEngine m_secRuleEngine;

0 commit comments

Comments
 (0)