Skip to content

Commit 30704a5

Browse files
committed
Adds hyperscan support to pm operator
1 parent a496865 commit 30704a5

File tree

8 files changed

+406
-157
lines changed

8 files changed

+406
-157
lines changed

src/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ UTILS = \
245245
utils/decode.cc \
246246
utils/geo_lookup.cc \
247247
utils/https_client.cc \
248+
utils/hyperscan.cc \
248249
utils/ip_tree.cc \
249250
utils/md5.cc \
250251
utils/msc_tree.cc \

src/operators/pm.cc

+152-16
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@
2525
#include <list>
2626
#include <memory>
2727

28-
#ifdef WITH_HS
29-
#include <hs.h>
30-
#endif
31-
32-
3328
#include "src/operators/operator.h"
3429
#ifndef WITH_HS
3530
#include "src/utils/acmp.h"
@@ -41,17 +36,18 @@ namespace operators {
4136

4237
Pm::~Pm() {
4338
#ifdef WITH_HS
39+
m_hs = NULL;
4440
#else
4541
acmp_node_t *root = m_p->root_node;
4642

4743
cleanup(root);
4844

4945
free(m_p);
5046
m_p = NULL;
47+
#endif
5148
#ifdef MODSEC_MUTEX_ON_PM
5249
pthread_mutex_destroy(&m_lock);
5350
#endif
54-
#endif
5551
}
5652

5753
#ifndef WITH_HS
@@ -95,22 +91,28 @@ void Pm::postOrderTraversal(acmp_btree_node_t *node) {
9591

9692
bool Pm::evaluate(Transaction *transaction, RuleWithActions *rule,
9793
const std::string &input, std::shared_ptr<RuleMessage> ruleMessage) {
94+
int rc = 0;
95+
const char *match = NULL;
9896
#ifdef WITH_HS
99-
return 0;
97+
#ifdef MODSEC_MUTEX_ON_PM
98+
pthread_mutex_lock(&m_lock);
99+
#endif
100+
rc = m_hs->search(input.c_str(), input.length(), &match);
101+
#ifdef MODSEC_MUTEX_ON_PM
102+
pthread_mutex_unlock(&m_lock);
103+
#endif
100104
#else
101-
int rc;
102105
ACMPT pt;
103106
pt.parser = m_p;
104107
pt.ptr = NULL;
105-
const char *match = NULL;
106108
#ifdef MODSEC_MUTEX_ON_PM
107109
pthread_mutex_lock(&m_lock);
108110
#endif
109111
rc = acmp_process_quick(&pt, &match, input.c_str(), input.length());
110112
#ifdef MODSEC_MUTEX_ON_PM
111113
pthread_mutex_unlock(&m_lock);
112114
#endif
113-
115+
#endif
114116
if (rc >= 0 && transaction) {
115117
std::string match_(match?match:"");
116118
logOffset(ruleMessage, rc - match_.size() + 1, match_.size());
@@ -125,16 +127,138 @@ bool Pm::evaluate(Transaction *transaction, RuleWithActions *rule,
125127
}
126128

127129
return rc >= 0;
130+
}
131+
132+
static
133+
char *parse_pm_content(const char *op_parm, unsigned short int op_len, const char **error_msg) {
134+
char *parm = NULL;
135+
char *content;
136+
unsigned short int offset = 0;
137+
// char converted = 0;
138+
int i, x;
139+
unsigned char bin = 0, esc = 0, bin_offset = 0;
140+
unsigned char c;
141+
unsigned char bin_parm[3] = { 0 };
142+
char *processed = NULL;
143+
144+
content = strdup(op_parm);
145+
146+
if (content == NULL) {
147+
*error_msg = std::string("Error allocating memory for pattern matching content.").c_str();
148+
return NULL;
149+
}
150+
151+
while (offset < op_len && (content[offset] == ' ' || content[offset] == '\t')) {
152+
offset++;
153+
};
154+
155+
op_len = strlen(content);
156+
157+
if (content[offset] == '\"' && content[op_len-1] == '\"') {
158+
parm = strdup(content + offset + 1);
159+
if (parm == NULL) {
160+
*error_msg = std::string("Error allocating memory for pattern matching content.").c_str();
161+
free(content);
162+
content = NULL;
163+
return NULL;
164+
}
165+
parm[op_len - offset - 2] = '\0';
166+
} else {
167+
parm = strdup(content + offset);
168+
if (parm == NULL) {
169+
free(content);
170+
content = NULL;
171+
*error_msg = std::string("Error allocating memory for pattern matching content.").c_str();
172+
return NULL;
173+
}
174+
}
175+
176+
free(content);
177+
content = NULL;
178+
179+
op_len = strlen(parm);
180+
181+
if (op_len == 0) {
182+
*error_msg = "Content length is 0.";
183+
free(parm);
184+
return NULL;
185+
}
186+
187+
for (i = 0, x = 0; i < op_len; i++) {
188+
if (parm[i] == '|') {
189+
if (bin) {
190+
bin = 0;
191+
} else {
192+
bin = 1;
193+
}
194+
} else if(!esc && parm[i] == '\\') {
195+
esc = 1;
196+
} else {
197+
if (bin) {
198+
if (parm[i] == 0 || parm[i] == 1 || parm[i] == 2 ||
199+
parm[i] == 3 || parm[i] == 4 || parm[i] == 5 ||
200+
parm[i] == 6 || parm[i] == 7 || parm[i] == 8 ||
201+
parm[i] == 9 ||
202+
parm[i] == 'A' || parm[i] == 'a' ||
203+
parm[i] == 'B' || parm[i] == 'b' ||
204+
parm[i] == 'C' || parm[i] == 'c' ||
205+
parm[i] == 'D' || parm[i] == 'd' ||
206+
parm[i] == 'E' || parm[i] == 'e' ||
207+
parm[i] == 'F' || parm[i] == 'f')
208+
{
209+
bin_parm[bin_offset] = (char)parm[i];
210+
bin_offset++;
211+
if (bin_offset == 2) {
212+
c = strtol((char *)bin_parm, (char **) NULL, 16) & 0xFF;
213+
bin_offset = 0;
214+
parm[x] = c;
215+
x++;
216+
//converted = 1;
217+
}
218+
} else if (parm[i] == ' ') {
219+
}
220+
} else if (esc) {
221+
if (parm[i] == ':' ||
222+
parm[i] == ';' ||
223+
parm[i] == '\\' ||
224+
parm[i] == '\"')
225+
{
226+
parm[x] = parm[i];
227+
x++;
228+
} else {
229+
*error_msg = std::string("Unsupported escape sequence.").c_str();
230+
free(parm);
231+
return NULL;
232+
}
233+
esc = 0;
234+
//converted = 1;
235+
} else {
236+
parm[x] = parm[i];
237+
x++;
238+
}
239+
}
240+
}
241+
242+
#if 0
243+
if (converted) {
244+
op_len = x;
245+
}
128246
#endif
129247

130-
return 0;
131-
}
248+
//processed = memcpy(processed, parm, op_len);
249+
processed = strdup(parm);
250+
free(parm);
251+
parm = NULL;
132252

253+
if (processed == NULL) {
254+
*error_msg = std::string("Error allocating memory for pattern matching content.").c_str();
255+
return NULL;
256+
}
257+
258+
return processed;
259+
}
133260

134261
bool Pm::init(const std::string &file, std::string *error) {
135-
#ifdef WITH_HS
136-
fprintf(stdout, "Sopport for HS is on the way: %s\n", hs_version());
137-
#else
138262
std::vector<std::string> vec;
139263
std::istringstream *iss;
140264
const char *err = NULL;
@@ -154,20 +278,32 @@ bool Pm::init(const std::string &file, std::string *error) {
154278
back_inserter(vec));
155279

156280
for (auto &a : vec) {
281+
#ifdef WITH_HS
282+
m_hs->addPattern(a.c_str(), a.length());
283+
}
284+
if (m_hs->compile(error) == false) {
285+
if (content) {
286+
free(content);
287+
content = NULL;
288+
}
289+
delete iss;
290+
return false;
291+
}
292+
#else
157293
acmp_add_pattern(m_p, a.c_str(), NULL, NULL, a.length());
158294
}
159295

160296
while (m_p->is_failtree_done == 0) {
161297
acmp_prepare(m_p);
162298
}
299+
#endif
163300

164301
if (content) {
165302
free(content);
166303
content = NULL;
167304
}
168305

169306
delete iss;
170-
#endif
171307
return true;
172308
}
173309

src/operators/pm.h

+10-8
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222
#include <utility>
2323

2424
#include "src/operators/operator.h"
25+
#ifdef WITH_HS
26+
#include "src/utils/hyperscan.h"
27+
#else
2528
#include "src/utils/acmp.h"
26-
29+
#endif
2730

2831
namespace modsecurity {
2932
namespace operators {
@@ -34,15 +37,13 @@ class Pm : public Operator {
3437
/** @ingroup ModSecurity_Operator */
3538
explicit Pm(std::unique_ptr<RunTimeString> param)
3639
: Operator("Pm", std::move(param)) {
37-
#ifdef WITH_HS
38-
#else
40+
#ifndef WITH_HS
3941
m_p = acmp_create(0);
4042
#endif
4143
}
4244
explicit Pm(const std::string &n, std::unique_ptr<RunTimeString> param)
4345
: Operator(n, std::move(param)) {
44-
#ifdef WITH_HS
45-
#else
46+
#ifndef WITH_HS
4647
m_p = acmp_create(0);
4748
#endif
4849
}
@@ -59,16 +60,17 @@ class Pm : public Operator {
5960
#endif
6061

6162
protected:
62-
#ifndef WITH_HS
63+
#ifdef WITH_HS
64+
std::shared_ptr<Utils::HyperscanPm> m_hs =
65+
std::make_shared<Utils::HyperscanPm>();
66+
#else
6367
ACMP *m_p;
6468
#endif
6569

6670
private:
67-
#ifndef WITH_HS
6871
#ifdef MODSEC_MUTEX_ON_PM
6972
pthread_mutex_t m_lock;
7073
#endif
71-
#endif
7274

7375
};
7476

src/operators/pm_from_file.cc

+8-3
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,18 @@ bool PmFromFile::init(const std::string &config, std::string *error) {
6969
for (std::string line; std::getline(*iss, line); ) {
7070
if (isComment(line) == false) {
7171
#ifdef WITH_HS
72+
m_hs->addPattern(line.c_str(), line.length());
73+
}
74+
}
75+
if (m_hs->compile(error) == false) {
76+
delete iss;
77+
return false;
78+
}
7279
#else
7380
acmp_add_pattern(m_p, line.c_str(), NULL, NULL, line.length());
74-
#endif
75-
}
81+
}
7682
}
7783

78-
#ifndef WITH_HS
7984
while (m_p->is_failtree_done == 0) {
8085
acmp_prepare(m_p);
8186
}

0 commit comments

Comments
 (0)