Skip to content
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
50 changes: 34 additions & 16 deletions headers/modsecurity/collection/collection.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <algorithm>
#include <memory>
#include <cstdint>
#include <cctype>
#endif


Expand All @@ -47,6 +48,23 @@ class Collection {
explicit Collection(const std::string &a) : m_name(a) { }
virtual ~Collection() { }

/*
* Collection variable names are case-insensitive in SecLang (e.g.
* `setvar:ip.counter` and `IP:COUNTER` refer to the same key). Normalise
* the variable-name term of the composite LMDB key to lowercase so that
* writes and reads performed with different casing hit the same entry.
* The compartment values (collection key, web app id) are intentionally
* left untouched since they may be opaque, case-sensitive identifiers.
*/
static std::string normKey(const std::string &k) {
std::string out;
out.reserve(k.size());
for (char c : k) {
out.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
}
return out;
}

virtual bool storeOrUpdateFirst(const std::string &key,
const std::string &value) = 0;

Expand All @@ -73,90 +91,90 @@ class Collection {
/* storeOrUpdateFirst */
virtual bool storeOrUpdateFirst(const std::string &key,
std::string compartment, const std::string &value) {
std::string nkey = compartment + "::" + key;
std::string nkey = compartment + "::" + normKey(key);
return storeOrUpdateFirst(nkey, value);
}


virtual bool storeOrUpdateFirst(const std::string &key,
std::string compartment, std::string compartment2,
const std::string &value) {
std::string nkey = compartment + "::" + compartment2 + "::" + key;
std::string nkey = compartment + "::" + compartment2 + "::" + normKey(key);
return storeOrUpdateFirst(nkey, value);
}


/* updateFirst */
virtual bool updateFirst(const std::string &key, std::string compartment,
const std::string &value) {
std::string nkey = compartment + "::" + key;
std::string nkey = compartment + "::" + normKey(key);
return updateFirst(nkey, value);
}


virtual bool updateFirst(const std::string &key, std::string compartment,
std::string compartment2, const std::string &value) {
std::string nkey = compartment + "::" + compartment2 + "::" + key;
std::string nkey = compartment + "::" + compartment2 + "::" + normKey(key);
return updateFirst(nkey, value);
}


/* del */
virtual void del(const std::string& key, std::string compartment) {
std::string nkey = compartment + "::" + key;
std::string nkey = compartment + "::" + normKey(key);
del(nkey);
}


virtual void del(const std::string& key, std::string compartment,
std::string compartment2) {
std::string nkey = compartment + "::" + compartment2 + "::" + key;
std::string nkey = compartment + "::" + compartment2 + "::" + normKey(key);
del(nkey);
}


/* setExpiry */
virtual void setExpiry(const std::string& key, std::string compartment,
int32_t expiry_seconds) {
std::string nkey = compartment + "::" + key;
std::string nkey = compartment + "::" + normKey(key);
setExpiry(nkey, expiry_seconds);
}


virtual void setExpiry(const std::string& key, std::string compartment,
std::string compartment2, int32_t expiry_seconds) {
std::string nkey = compartment + "::" + compartment2 + "::" + key;
std::string nkey = compartment + "::" + compartment2 + "::" + normKey(key);
setExpiry(nkey, expiry_seconds);
}


/* resolveFirst */
virtual std::unique_ptr<std::string> resolveFirst(const std::string& var,
std::string compartment) {
std::string nkey = compartment + "::" + var;
std::string nkey = compartment + "::" + normKey(var);
return resolveFirst(nkey);
}


virtual std::unique_ptr<std::string> resolveFirst(const std::string& var,
std::string compartment, std::string compartment2) {
std::string nkey = compartment + "::" + compartment2 + "::" + var;
std::string nkey = compartment + "::" + compartment2 + "::" + normKey(var);
return resolveFirst(nkey);
}


/* resolveSingleMatch */
virtual void resolveSingleMatch(const std::string& var,
std::string compartment, std::vector<const VariableValue *> *l) {
std::string nkey = compartment + "::" + var;
std::string nkey = compartment + "::" + normKey(var);
resolveSingleMatch(nkey, l);
}


virtual void resolveSingleMatch(const std::string& var,
std::string compartment, std::string compartment2,
std::vector<const VariableValue *> *l) {
std::string nkey = compartment + "::" + compartment2 + "::" + var;
std::string nkey = compartment + "::" + compartment2 + "::" + normKey(var);
resolveSingleMatch(nkey, l);
}

Expand All @@ -165,7 +183,7 @@ class Collection {
virtual void resolveMultiMatches(const std::string& var,
std::string compartment, std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) {
std::string nkey = compartment + "::" + var;
std::string nkey = compartment + "::" + normKey(var);
resolveMultiMatches(nkey, l, ke);
}

Expand All @@ -174,7 +192,7 @@ class Collection {
std::string compartment, std::string compartment2,
std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) {
std::string nkey = compartment + "::" + compartment2 + "::" + var;
std::string nkey = compartment + "::" + compartment2 + "::" + normKey(var);
resolveMultiMatches(nkey, l, ke);
}

Expand All @@ -183,15 +201,15 @@ class Collection {
virtual void resolveRegularExpression(const std::string& var,
std::string compartment, std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) {
std::string nkey = compartment + "::" + var;
std::string nkey = compartment + "::" + normKey(var);
resolveRegularExpression(nkey, l, ke);
}


virtual void resolveRegularExpression(const std::string& var,
std::string compartment, std::string compartment2,
std::vector<const VariableValue *> *l, variables::KeyExclusions &ke) {
std::string nkey = compartment + "::" + compartment2 + "::" + var;
std::string nkey = compartment + "::" + compartment2 + "::" + normKey(var);
resolveRegularExpression(nkey, l, ke);
}

Expand Down
3 changes: 3 additions & 0 deletions headers/modsecurity/rules_set_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@ class RulesSetProperties {

to->m_secWebAppId.merge(&from->m_secWebAppId);

to->m_secDataDir.merge(&from->m_secDataDir);

to->m_unicodeMapTable.merge(&from->m_unicodeMapTable);

to->m_httpblKey.merge(&from->m_httpblKey);
Expand Down Expand Up @@ -620,6 +622,7 @@ class RulesSetProperties {
ConfigString m_uploadTmpDirectory;
ConfigString m_secArgumentSeparator;
ConfigString m_secWebAppId;
ConfigString m_secDataDir;
std::vector<std::shared_ptr<actions::Action> > \
m_defaultActions[modsecurity::Phases::NUMBER_OF_PHASES];
ConfigUnicodeMap m_unicodeMapTable;
Expand Down
56 changes: 54 additions & 2 deletions src/actions/set_var.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,30 @@ bool SetVar::evaluate(RuleWithActions *rule, Transaction *t) {
} else if (user) {
user->del(t, m_variableNameExpanded);
} else {
// ?
const std::string &col = m_variable->m_collectionName;
if (col == "TX") {
t->m_collections.m_tx_collection->del(m_variableNameExpanded);
} else if (col == "IP") {
t->m_collections.m_ip_collection->del(m_variableNameExpanded,
t->m_collections.m_ip_collection_key,
t->m_rules->m_secWebAppId.m_value);
} else if (col == "SESSION") {
t->m_collections.m_session_collection->del(m_variableNameExpanded,
t->m_collections.m_session_collection_key,
t->m_collections.m_ip_collection_key);
} else if (col == "USER") {
t->m_collections.m_user_collection->del(m_variableNameExpanded,
t->m_collections.m_user_collection_key,
t->m_rules->m_secWebAppId.m_value);
} else if (col == "RESOURCE") {
t->m_collections.m_resource_collection->del(m_variableNameExpanded,
t->m_collections.m_resource_collection_key,
t->m_rules->m_secWebAppId.m_value);
} else if (col == "GLOBAL") {
t->m_collections.m_global_collection->del(m_variableNameExpanded,
t->m_collections.m_global_collection_key,
t->m_rules->m_secWebAppId.m_value);
}
}
goto end;
} else {
Expand Down Expand Up @@ -138,7 +161,36 @@ bool SetVar::evaluate(RuleWithActions *rule, Transaction *t) {
} else if (user) {
user->storeOrUpdateFirst(t, m_variableNameExpanded, targetValue);
} else {
// ?
const std::string &col = m_variable->m_collectionName;
if (col == "TX") {
t->m_collections.m_tx_collection->storeOrUpdateFirst(
m_variableNameExpanded, targetValue);
} else if (col == "IP") {
t->m_collections.m_ip_collection->storeOrUpdateFirst(
m_variableNameExpanded,
t->m_collections.m_ip_collection_key,
t->m_rules->m_secWebAppId.m_value, targetValue);
} else if (col == "SESSION") {
t->m_collections.m_session_collection->storeOrUpdateFirst(
m_variableNameExpanded,
t->m_collections.m_session_collection_key,
t->m_rules->m_secWebAppId.m_value, targetValue);
} else if (col == "USER") {
t->m_collections.m_user_collection->storeOrUpdateFirst(
m_variableNameExpanded,
t->m_collections.m_user_collection_key,
t->m_rules->m_secWebAppId.m_value, targetValue);
} else if (col == "RESOURCE") {
t->m_collections.m_resource_collection->storeOrUpdateFirst(
m_variableNameExpanded,
t->m_collections.m_resource_collection_key,
t->m_rules->m_secWebAppId.m_value, targetValue);
} else if (col == "GLOBAL") {
t->m_collections.m_global_collection->storeOrUpdateFirst(
m_variableNameExpanded,
t->m_collections.m_global_collection_key,
t->m_rules->m_secWebAppId.m_value, targetValue);
}
}

/*
Expand Down
28 changes: 26 additions & 2 deletions src/collection/backend/lmdb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -641,18 +641,42 @@
MDBEnvProvider::MDBEnvProvider() : m_env(NULL), valid(false) {
int rc;
MDB_txn *txn;

std::string datadir = m_s_dataDir;
int openFlags = MDB_WRITEMAP;
mdb_mode_t openMode = 0664;

if (datadir.empty()) {
// Legacy fallback: single file in the current working directory.
datadir = "./modsec-shared-collections";
openFlags |= MDB_NOSUBDIR;
}

mdb_env_create(&m_env);
rc = mdb_env_open(m_env, "./modsec-shared-collections",
MDB_WRITEMAP | MDB_NOSUBDIR, 0664);
rc = mdb_env_open(m_env, datadir.c_str(), openFlags, openMode);

if (rc == 0) {
valid = true;
mdb_txn_begin(m_env, NULL, 0, &txn);
mdb_dbi_open(txn, NULL, MDB_CREATE | MDB_DUPSORT, &m_dbi);
mdb_txn_commit(txn);
} else {
std::cerr << "ModSecurity: failed to open LMDB environment '"
<< datadir << "': " << mdb_strerror(rc)
<< " (collections will not be persisted)." << std::endl;
}
}

std::string MDBEnvProvider::m_s_dataDir = "";

void MDBEnvProvider::SetDataDir(const std::string &dir) {

Check warning on line 672 in src/collection/backend/lmdb.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this const reference to "std::string" by a "std::string_view".

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ9LhmQf6RGVZreOY1Tc&open=AZ9LhmQf6RGVZreOY1Tc&pullRequest=3597
m_s_dataDir = dir;
}

const std::string& MDBEnvProvider::GetDataDir() {
return m_s_dataDir;
}

MDB_env* MDBEnvProvider::GetEnv() {
return m_env;
}
Expand Down
13 changes: 13 additions & 0 deletions src/collection/backend/lmdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,26 @@
MDB_dbi* GetDBI();
bool isValid() const;

/**
* Set the directory used to hold the LMDB environment. Must be called
* before the singleton is first instantiated (i.e. before the first
* collection transaction). When set, SecDataDir is used as the LMDB
* environment directory (data.mdb / lock.mdb are created inside it).
* When unset, the legacy behaviour is preserved: a single
* "./modsec-shared-collections" file in the current working directory.
*/
static void SetDataDir(const std::string &dir);
static const std::string& GetDataDir();

~MDBEnvProvider();
private:
MDB_env *m_env;
MDB_dbi m_dbi;
bool valid;

MDBEnvProvider();

static std::string m_s_dataDir;
};

class LMDB :
Expand All @@ -97,24 +110,24 @@
public:
explicit LMDB(const std::string &name);

bool storeOrUpdateFirst(const std::string &key,

Check failure on line 113 in src/collection/backend/lmdb.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Correct these functions so that no function in "modsecurity::collection::backend::LMDB::storeOrUpdateFirst" hides a function in "modsecurity::collection::Collection::storeOrUpdateFirst".

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ9LhmLS6RGVZreOY1Tb&open=AZ9LhmLS6RGVZreOY1Tb&pullRequest=3597
const std::string &value) override;

bool updateFirst(const std::string &key,

Check failure on line 116 in src/collection/backend/lmdb.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Correct these functions so that no function in "modsecurity::collection::backend::LMDB::updateFirst" hides a function in "modsecurity::collection::Collection::updateFirst".

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ9LhmLS6RGVZreOY1TX&open=AZ9LhmLS6RGVZreOY1TX&pullRequest=3597
const std::string &value) override;

void del(const std::string& key) override;

Check failure on line 119 in src/collection/backend/lmdb.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Correct these functions so that no function in "modsecurity::collection::backend::LMDB::del" hides a function in "modsecurity::collection::Collection::del".

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ9LhmLS6RGVZreOY1TY&open=AZ9LhmLS6RGVZreOY1TY&pullRequest=3597

void setExpiry(const std::string& key, int32_t expiry_seconds) override;

Check failure on line 121 in src/collection/backend/lmdb.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Correct these functions so that no function in "modsecurity::collection::backend::LMDB::setExpiry" hides a function in "modsecurity::collection::Collection::setExpiry".

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ9LhmLS6RGVZreOY1TZ&open=AZ9LhmLS6RGVZreOY1TZ&pullRequest=3597

std::unique_ptr<std::string> resolveFirst(const std::string& var) override;

Check failure on line 123 in src/collection/backend/lmdb.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Correct these functions so that no function in "modsecurity::collection::backend::LMDB::resolveFirst" hides a function in "modsecurity::collection::Collection::resolveFirst".

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ9LhmLS6RGVZreOY1Ta&open=AZ9LhmLS6RGVZreOY1Ta&pullRequest=3597

void resolveSingleMatch(const std::string& var,

Check failure on line 125 in src/collection/backend/lmdb.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Correct these functions so that no function in "modsecurity::collection::backend::LMDB::resolveSingleMatch" hides a function in "modsecurity::collection::Collection::resolveSingleMatch".

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ9LhmLS6RGVZreOY1TV&open=AZ9LhmLS6RGVZreOY1TV&pullRequest=3597
std::vector<const VariableValue *> *l) override;
void resolveMultiMatches(const std::string& var,

Check failure on line 127 in src/collection/backend/lmdb.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Correct these functions so that no function in "modsecurity::collection::backend::LMDB::resolveMultiMatches" hides a function in "modsecurity::collection::Collection::resolveMultiMatches".

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ9LhmLS6RGVZreOY1TU&open=AZ9LhmLS6RGVZreOY1TU&pullRequest=3597
std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) override;
void resolveRegularExpression(const std::string& var,

Check failure on line 130 in src/collection/backend/lmdb.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Correct these functions so that no function in "modsecurity::collection::backend::LMDB::resolveRegularExpression" hides a function in "modsecurity::collection::Collection::resolveRegularExpression".

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ9LhmLS6RGVZreOY1TW&open=AZ9LhmLS6RGVZreOY1TW&pullRequest=3597
std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) override;

Expand Down
Loading
Loading