Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds hyperscan support to pm operator #2551

Open
wants to merge 1 commit into
base: v3/dev/hyperscan
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ UTILS = \
utils/decode.cc \
utils/geo_lookup.cc \
utils/https_client.cc \
utils/hyperscan.cc \
utils/ip_tree.cc \
utils/md5.cc \
utils/msc_tree.cc \
Expand Down
168 changes: 152 additions & 16 deletions src/operators/pm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@
#include <list>
#include <memory>

#ifdef WITH_HS
#include <hs.h>
#endif


#include "src/operators/operator.h"
#ifndef WITH_HS
#include "src/utils/acmp.h"
Expand All @@ -41,17 +36,18 @@ namespace operators {

Pm::~Pm() {
#ifdef WITH_HS
m_hs = NULL;
#else
acmp_node_t *root = m_p->root_node;

cleanup(root);

free(m_p);
m_p = NULL;
#endif
#ifdef MODSEC_MUTEX_ON_PM
pthread_mutex_destroy(&m_lock);
#endif
#endif
}

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

bool Pm::evaluate(Transaction *transaction, RuleWithActions *rule,
const std::string &input, std::shared_ptr<RuleMessage> ruleMessage) {
int rc = 0;
const char *match = NULL;
#ifdef WITH_HS
return 0;
#ifdef MODSEC_MUTEX_ON_PM
pthread_mutex_lock(&m_lock);
#endif
rc = m_hs->search(input.c_str(), input.length(), &match);
#ifdef MODSEC_MUTEX_ON_PM
pthread_mutex_unlock(&m_lock);
#endif
#else
int rc;
ACMPT pt;
pt.parser = m_p;
pt.ptr = NULL;
const char *match = NULL;
#ifdef MODSEC_MUTEX_ON_PM
pthread_mutex_lock(&m_lock);
#endif
rc = acmp_process_quick(&pt, &match, input.c_str(), input.length());
#ifdef MODSEC_MUTEX_ON_PM
pthread_mutex_unlock(&m_lock);
#endif

#endif
if (rc >= 0 && transaction) {
std::string match_(match?match:"");
logOffset(ruleMessage, rc - match_.size() + 1, match_.size());
Expand All @@ -125,16 +127,138 @@ bool Pm::evaluate(Transaction *transaction, RuleWithActions *rule,
}

return rc >= 0;
}

static
char *parse_pm_content(const char *op_parm, unsigned short int op_len, const char **error_msg) {
char *parm = NULL;
char *content;
unsigned short int offset = 0;
// char converted = 0;
int i, x;
unsigned char bin = 0, esc = 0, bin_offset = 0;
unsigned char c;
unsigned char bin_parm[3] = { 0 };
char *processed = NULL;

content = strdup(op_parm);

if (content == NULL) {
*error_msg = std::string("Error allocating memory for pattern matching content.").c_str();
return NULL;
}

while (offset < op_len && (content[offset] == ' ' || content[offset] == '\t')) {
offset++;
};

op_len = strlen(content);

if (content[offset] == '\"' && content[op_len-1] == '\"') {
parm = strdup(content + offset + 1);
if (parm == NULL) {
*error_msg = std::string("Error allocating memory for pattern matching content.").c_str();
free(content);
content = NULL;
return NULL;
}
parm[op_len - offset - 2] = '\0';
} else {
parm = strdup(content + offset);
if (parm == NULL) {
free(content);
content = NULL;
*error_msg = std::string("Error allocating memory for pattern matching content.").c_str();
return NULL;
}
}

free(content);
content = NULL;

op_len = strlen(parm);

if (op_len == 0) {
*error_msg = "Content length is 0.";
free(parm);
return NULL;
}

for (i = 0, x = 0; i < op_len; i++) {
if (parm[i] == '|') {
if (bin) {
bin = 0;
} else {
bin = 1;
}
} else if(!esc && parm[i] == '\\') {
esc = 1;
} else {
if (bin) {
if (parm[i] == 0 || parm[i] == 1 || parm[i] == 2 ||
parm[i] == 3 || parm[i] == 4 || parm[i] == 5 ||
parm[i] == 6 || parm[i] == 7 || parm[i] == 8 ||
parm[i] == 9 ||
parm[i] == 'A' || parm[i] == 'a' ||
parm[i] == 'B' || parm[i] == 'b' ||
parm[i] == 'C' || parm[i] == 'c' ||
parm[i] == 'D' || parm[i] == 'd' ||
parm[i] == 'E' || parm[i] == 'e' ||
parm[i] == 'F' || parm[i] == 'f')
{
bin_parm[bin_offset] = (char)parm[i];
bin_offset++;
if (bin_offset == 2) {
c = strtol((char *)bin_parm, (char **) NULL, 16) & 0xFF;
bin_offset = 0;
parm[x] = c;
x++;
//converted = 1;
}
} else if (parm[i] == ' ') {
}
} else if (esc) {
if (parm[i] == ':' ||
parm[i] == ';' ||
parm[i] == '\\' ||
parm[i] == '\"')
{
parm[x] = parm[i];
x++;
} else {
*error_msg = std::string("Unsupported escape sequence.").c_str();
free(parm);
return NULL;
}
esc = 0;
//converted = 1;
} else {
parm[x] = parm[i];
x++;
}
}
}

#if 0
if (converted) {
op_len = x;
}
#endif

return 0;
}
//processed = memcpy(processed, parm, op_len);
processed = strdup(parm);
free(parm);
parm = NULL;

if (processed == NULL) {
*error_msg = std::string("Error allocating memory for pattern matching content.").c_str();
return NULL;
}

return processed;
}

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

for (auto &a : vec) {
#ifdef WITH_HS
m_hs->addPattern(a.c_str(), a.length());
}
if (m_hs->compile(error) == false) {
if (content) {
free(content);
content = NULL;
}
delete iss;
return false;
}
#else
acmp_add_pattern(m_p, a.c_str(), NULL, NULL, a.length());
}

while (m_p->is_failtree_done == 0) {
acmp_prepare(m_p);
}
#endif

if (content) {
free(content);
content = NULL;
}

delete iss;
#endif
return true;
}

Expand Down
18 changes: 10 additions & 8 deletions src/operators/pm.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
#include <utility>

#include "src/operators/operator.h"
#ifdef WITH_HS
#include "src/utils/hyperscan.h"
#else
#include "src/utils/acmp.h"

#endif

namespace modsecurity {
namespace operators {
Expand All @@ -34,15 +37,13 @@ class Pm : public Operator {
/** @ingroup ModSecurity_Operator */
explicit Pm(std::unique_ptr<RunTimeString> param)
: Operator("Pm", std::move(param)) {
#ifdef WITH_HS
#else
#ifndef WITH_HS
m_p = acmp_create(0);
#endif
}
explicit Pm(const std::string &n, std::unique_ptr<RunTimeString> param)
: Operator(n, std::move(param)) {
#ifdef WITH_HS
#else
#ifndef WITH_HS
m_p = acmp_create(0);
#endif
}
Expand All @@ -59,16 +60,17 @@ class Pm : public Operator {
#endif

protected:
#ifndef WITH_HS
#ifdef WITH_HS
std::shared_ptr<Utils::HyperscanPm> m_hs =
std::make_shared<Utils::HyperscanPm>();
#else
ACMP *m_p;
#endif

private:
#ifndef WITH_HS
#ifdef MODSEC_MUTEX_ON_PM
pthread_mutex_t m_lock;
#endif
#endif

};

Expand Down
11 changes: 8 additions & 3 deletions src/operators/pm_from_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,18 @@ bool PmFromFile::init(const std::string &config, std::string *error) {
for (std::string line; std::getline(*iss, line); ) {
if (isComment(line) == false) {
#ifdef WITH_HS
m_hs->addPattern(line.c_str(), line.length());
}
}
if (m_hs->compile(error) == false) {
delete iss;
return false;
}
#else
acmp_add_pattern(m_p, line.c_str(), NULL, NULL, line.length());
#endif
}
}
}

#ifndef WITH_HS
while (m_p->is_failtree_done == 0) {
acmp_prepare(m_p);
}
Expand Down
Loading