Merge pull request #3233 from eduar-hte/remove-copies-pm-operator

Removed multiple heap-allocated copies in Pm::init & parse_pm_content
This commit is contained in:
Ervin Hegedus 2024-08-28 13:31:02 +02:00 committed by GitHub
commit 4951702d45
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 75 additions and 189 deletions

View File

@ -219,7 +219,6 @@ OPERATORS = \
operators/no_match.cc \
operators/operator.cc \
operators/pm.cc \
operators/pm_f.cc \
operators/pm_from_file.cc \
operators/rbl.cc \
operators/rsub.cc \

View File

@ -15,20 +15,80 @@
#include "src/operators/pm.h"
#include <string.h>
#include <string>
#include <algorithm>
#include <iterator>
#include <sstream>
#include <vector>
#include <list>
#include <memory>
#include "src/operators/operator.h"
#include "src/utils/acmp.h"
#include "src/utils/string.h"
static inline std::string parse_pm_content(const std::string &op_parm) {
auto offset = op_parm.find_first_not_of(" \t");
if (offset == std::string::npos) {
return op_parm;
}
auto size = op_parm.size() - offset;
if (size >= 2 &&
op_parm.at(offset) == '\"' && op_parm.back() == '\"') {
offset++;
size -= 2;
}
if (size == 0) {
return op_parm;
}
std::string parsed_parm(op_parm.c_str() + offset, size);
unsigned char bin_offset = 0;
unsigned char bin_parm[3] = { 0 };
bool bin = false, esc = false;
char *d = parsed_parm.data();
for(const char *s = d, *e = d + size; s != e; ++s) {
if (*s == '|') {
bin = !bin;
} else if(!esc && *s == '\\') {
esc = true;
} else {
if (bin) {
if (VALID_HEX(*s)) {
bin_parm[bin_offset] = (char)*s;
bin_offset++;
if (bin_offset == 2) {
unsigned char c = strtol((char *)bin_parm, (char **) nullptr, 16) & 0xFF;
bin_offset = 0;
*d++ = c;
}
} else {
// Invalid hex character
return op_parm;
}
} else if (esc) {
if (*s == ':' ||
*s == ';' ||
*s == '\\' ||
*s == '\"')
{
*d++ = *s;
} else {
// Unsupported escape sequence
return op_parm;
}
esc = false;
} else {
*d++ = *s;
}
}
}
parsed_parm.resize(d - parsed_parm.c_str());
return parsed_parm;
}
namespace modsecurity {
namespace operators {
@ -105,36 +165,19 @@ bool Pm::evaluate(Transaction *transaction, RuleWithActions *rule,
bool Pm::init(const std::string &file, std::string *error) {
std::vector<std::string> vec;
std::istringstream *iss;
const char *err = NULL;
const auto op_parm = parse_pm_content(m_param);
char *content = parse_pm_content(m_param.c_str(), m_param.length(), &err);
if (content == NULL) {
iss = new std::istringstream(m_param);
} else {
iss = new std::istringstream(content);
}
std::copy(std::istream_iterator<std::string>(*iss),
std::istringstream iss{op_parm};
std::for_each(std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>(),
back_inserter(vec));
for (auto &a : vec) {
acmp_add_pattern(m_p, a.c_str(), NULL, NULL, a.length());
}
[this](const auto &a) {
acmp_add_pattern(m_p, a.c_str(), NULL, NULL, a.length());
});
while (m_p->is_failtree_done == 0) {
acmp_prepare(m_p);
}
if (content) {
free(content);
content = NULL;
}
delete iss;
return true;
}

View File

@ -17,7 +17,6 @@
#define SRC_OPERATORS_PM_H_
#include <string>
#include <list>
#include <memory>
#include <utility>
#include <mutex>

View File

@ -1,27 +0,0 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include "src/operators/pm_f.h"
#include <string>
#include "src/operators/pm_from_file.h"
namespace modsecurity {
namespace operators {
} // namespace operators
} // namespace modsecurity

View File

@ -33,136 +33,9 @@
* that should be mitigated. This ACMP parser should be re-written to
* consume less memory.
*/
extern "C" {
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 = 0;
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
//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;
}
/*
*******************************************************************************
*******************************************************************************

View File

@ -23,6 +23,7 @@
#endif
#include <cstddef>
#include <string>
extern "C" {
@ -189,8 +190,6 @@ int acmp_process_quick(ACMPT *acmpt, const char **match, const char *data, size_
*/
int acmp_prepare(ACMP *parser);
char *parse_pm_content(const char *op_parm, unsigned short int op_len, const char **error_msg);
}
#endif /*ACMP_H_*/