Skip to content

Commit 7a19578

Browse files
committed
Perform SqlHexDecode transformation in-place
- Validate buffer size before accessing data. The previous implementation would only check that there was a character available in the buffer but could continue processing/reading characters from an hex representation without checking bounds. - Removed inplace & mytolower helper functions from the class, as they're only referenced by the implementation. - Removed duplicate VALID_HEX & ISODIGIT macros, already in src/utils/string.h.
1 parent f8f3c47 commit 7a19578

File tree

2 files changed

+34
-72
lines changed

2 files changed

+34
-72
lines changed

src/actions/transformations/sql_hex_decode.cc

Lines changed: 34 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -23,79 +23,50 @@
2323
namespace modsecurity::actions::transformations {
2424

2525

26-
#ifndef VALID_HEX
27-
#define VALID_HEX(X) (((X >= '0') && (X <= '9')) \
28-
|| ((X >= 'a') && (X <= 'f')) \
29-
|| ((X >= 'A') && (X <= 'F')))
30-
#endif
31-
#ifndef ISODIGIT
32-
#define ISODIGIT(X) ((X >= '0') && (X <= '7'))
33-
#endif
34-
35-
bool SqlHexDecode::transform(std::string &value, const Transaction *trans) const {
36-
std::string ret;
37-
unsigned char *input;
38-
int size = 0;
39-
40-
input = reinterpret_cast<unsigned char *>
41-
(malloc(sizeof(char) * value.length()+1));
42-
43-
if (input == NULL) {
44-
return "";
45-
}
46-
47-
memcpy(input, value.c_str(), value.length()+1);
48-
49-
size = inplace(input, value.length());
50-
51-
ret.assign(reinterpret_cast<char *>(input), size);
52-
free(input);
53-
54-
const auto changed = ret != value;
55-
value = ret;
56-
return changed;
26+
static inline int mytolower(int ch) {
27+
if (ch >= 'A' && ch <= 'Z')
28+
return ('a' + ch - 'A');
29+
else
30+
return ch;
5731
}
5832

59-
60-
int SqlHexDecode::inplace(unsigned char *data, int len) {
61-
unsigned char *d, *begin = data;
62-
int count = 0;
63-
64-
if ((data == NULL) || (len == 0)) {
65-
return 0;
33+
static inline bool inplace(std::string &value) {
34+
if (value.empty()) {
35+
return false;
6636
}
6737

68-
for (d = data; (++count < len) && *data; *d++ = *data++) {
69-
if (*data != '0') {
70-
continue;
38+
auto d = reinterpret_cast<unsigned char*>(value.data());
39+
const unsigned char *data = d;
40+
const auto end = data + value.size();
41+
42+
bool changed = false;
43+
44+
while (data < end) {
45+
if (data + 3 < end
46+
&& *data == '0'
47+
&& mytolower(*(data + 1)) == 'x'
48+
&& VALID_HEX(*(data + 2)) && VALID_HEX(*(data + 3))) {
49+
data += 2; // skip '0x'
50+
do {
51+
*d++ = utils::string::x2c(data);
52+
data += 2;
53+
} while ((data + 1 < end) && VALID_HEX(*data) && VALID_HEX(*(data + 1)));
54+
changed = true;
7155
}
72-
++data;
73-
++count;
74-
if (mytolower(*data) != 'x') {
75-
data--;
76-
count--;
77-
continue;
56+
else {
57+
*d++ = *data++;
7858
}
59+
}
7960

80-
data++;
81-
++count;
61+
*d = '\0';
8262

83-
// Do we need to keep "0x" if no hexa after?
84-
if (!VALID_HEX(data[0]) || !VALID_HEX(data[1])) {
85-
data -= 2;
86-
count -= 2;
87-
continue;
88-
}
63+
value.resize(d - reinterpret_cast<const unsigned char*>(value.c_str()));
64+
return changed;
65+
}
8966

90-
while (VALID_HEX(data[0]) && VALID_HEX(data[1])) {
91-
*d++ = utils::string::x2c(data);
92-
data += 2;
93-
count += 2;
94-
}
95-
}
9667

97-
*d = '\0';
98-
return strlen(reinterpret_cast<char *>(begin));
68+
bool SqlHexDecode::transform(std::string &value, const Transaction *trans) const {
69+
return inplace(value);
9970
}
10071

10172

src/actions/transformations/sql_hex_decode.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,6 @@ class SqlHexDecode : public Transformation {
2626
: Transformation(action) { }
2727

2828
bool transform(std::string &value, const Transaction *trans) const override;
29-
30-
static int inplace(unsigned char *data, int len);
31-
32-
static int mytolower(int ch) {
33-
if (ch >= 'A' && ch <= 'Z')
34-
return ('a' + ch - 'A');
35-
else
36-
return ch;
37-
}
3829
};
3930

4031
} // namespace modsecurity::actions::transformations

0 commit comments

Comments
 (0)