Skip to content

Commit

Permalink
Prevent default rule tags from being overridden, add extra test
Browse files Browse the repository at this point in the history
  • Loading branch information
Anilm3 committed Jun 18, 2024
1 parent 574b65a commit 2b05815
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 26 deletions.
3 changes: 3 additions & 0 deletions src/event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ void serialize_rule(const ddwaf::rule &rule, ddwaf_object &rule_map)
for (const auto &[key, value] : rule.get_tags()) {
ddwaf_object_map_addl(&tags_map, key.c_str(), key.size(), to_object(tmp, value));
}
for (const auto &[key, value] : rule.get_ancillary_tags()) {
ddwaf_object_map_addl(&tags_map, key.c_str(), key.size(), to_object(tmp, value));
}
ddwaf_object_map_add(&rule_map, "tags", &tags_map);
}

Expand Down
32 changes: 14 additions & 18 deletions src/rule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,8 @@ class rule {
rule(const rule &) = delete;
rule &operator=(const rule &) = delete;

rule(rule &&rhs) noexcept
: enabled_(rhs.enabled_), source_(rhs.source_), id_(std::move(rhs.id_)),
name_(std::move(rhs.name_)), tags_(std::move(rhs.tags_)), expr_(std::move(rhs.expr_)),
actions_(std::move(rhs.actions_))
{}

rule &operator=(rule &&rhs) noexcept
{
enabled_ = rhs.enabled_;
source_ = rhs.source_;
id_ = std::move(rhs.id_);
name_ = std::move(rhs.name_);
tags_ = std::move(rhs.tags_);
expr_ = std::move(rhs.expr_);
actions_ = std::move(rhs.actions_);
return *this;
}
rule(rule &&rhs) noexcept = default;
rule &operator=(rule &&rhs) noexcept = default;

virtual ~rule() = default;

Expand Down Expand Up @@ -94,8 +79,18 @@ class rule {
}

const std::unordered_map<std::string, std::string> &get_tags() const { return tags_; }
const std::unordered_map<std::string, std::string> &get_ancillary_tags() const
{
return ancillary_tags_;
}

void set_tag(const std::string &key, const std::string &value) { tags_[key] = value; }
void set_ancillary_tag(const std::string &key, const std::string &value)
{
// Ancillary tags aren't allowed to overlap with standard tags
if (!tags_.contains(key)) {
ancillary_tags_[key] = value;
}
}

const std::vector<std::string> &get_actions() const { return actions_; }

Expand All @@ -112,6 +107,7 @@ class rule {
std::string id_;
std::string name_;
std::unordered_map<std::string, std::string> tags_;
std::unordered_map<std::string, std::string> ancillary_tags_;
std::shared_ptr<expression> expr_;
std::vector<std::string> actions_;
};
Expand Down
8 changes: 6 additions & 2 deletions src/ruleset_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ std::shared_ptr<ruleset> ruleset_builder::build(parameter::map &root, base_rules
rule_ptr->set_actions(*ovrd.actions);
}

for (const auto &[tag, value] : ovrd.tags) { rule_ptr->set_tag(tag, value); }
for (const auto &[tag, value] : ovrd.tags) {
rule_ptr->set_ancillary_tag(tag, value);
}
}
}

Expand All @@ -113,7 +115,9 @@ std::shared_ptr<ruleset> ruleset_builder::build(parameter::map &root, base_rules
rule_ptr->set_actions(*ovrd.actions);
}

for (const auto &[tag, value] : ovrd.tags) { rule_ptr->set_tag(tag, value); }
for (const auto &[tag, value] : ovrd.tags) {
rule_ptr->set_ancillary_tag(tag, value);
}
}
}
}
Expand Down
56 changes: 50 additions & 6 deletions tests/interface_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ TEST(TestInterface, UpdateTagsByID)
EXPECT_EVENTS(result2,
{.id = "1",
.name = "rule1",
.tags = {{"type", "flow1"}, {"category", "new_category"}, {"confidence", "0"},
.tags = {{"type", "flow1"}, {"category", "category1"}, {"confidence", "1"},
{"new_tag", "value"}},
.matches = {{.op = "match_regex",
.op_value = "rule1",
Expand Down Expand Up @@ -834,7 +834,7 @@ TEST(TestInterface, UpdateTagsByID)
EXPECT_EVENTS(result2,
{.id = "1",
.name = "rule1",
.tags = {{"type", "flow1"}, {"category", "new_category"}, {"confidence", "0"},
.tags = {{"type", "flow1"}, {"category", "category1"}, {"confidence", "1"},
{"new_tag", "value"}},
.matches = {{.op = "match_regex",
.op_value = "rule1",
Expand Down Expand Up @@ -907,7 +907,7 @@ TEST(TestInterface, UpdateTagsByTags)
EXPECT_EVENTS(result2,
{.id = "1",
.name = "rule1",
.tags = {{"type", "flow1"}, {"category", "category1"}, {"confidence", "0"},
.tags = {{"type", "flow1"}, {"category", "category1"}, {"confidence", "1"},
{"new_tag", "value"}},
.matches = {{.op = "match_regex",
.op_value = "rule1",
Expand Down Expand Up @@ -1000,7 +1000,7 @@ TEST(TestInterface, UpdateTagsByTags)
EXPECT_EVENTS(result2,
{.id = "3",
.name = "rule3",
.tags = {{"type", "flow2"}, {"category", "category3"}, {"confidence", "0"},
.tags = {{"type", "flow2"}, {"category", "category3"}, {"confidence", "1"},
{"new_tag", "value"}},
.matches = {{.op = "match_regex",
.op_value = "rule3",
Expand Down Expand Up @@ -1055,7 +1055,7 @@ TEST(TestInterface, UpdateTagsByTags)
EXPECT_EVENTS(result2,
{.id = "3",
.name = "rule3",
.tags = {{"type", "flow2"}, {"category", "category3"}, {"confidence", "0"},
.tags = {{"type", "flow2"}, {"category", "category3"}, {"confidence", "1"},
{"new_tag", "value"}},
.matches = {{.op = "match_regex",
.op_value = "rule3",
Expand Down Expand Up @@ -1088,7 +1088,7 @@ TEST(TestInterface, UpdateOverrideByIDAndTag)
ddwaf_handle handle2;
{
auto overrides = yaml_to_object(
R"({rules_override: [{rules_target: [{tags: {type: flow1}}], on_match: ["block"], enabled: false}, {rules_target: [{rule_id: 1}], enabled: true}]})");
R"({rules_override: [{rules_target: [{tags: {type: flow1}}], tags: {new_tag: old_value}, on_match: ["block"], enabled: false}, {rules_target: [{rule_id: 1}], tags: {new_tag: new_value}, enabled: true}]})");
handle2 = ddwaf_update(handle1, &overrides, nullptr);
ddwaf_object_free(&overrides);
}
Expand All @@ -1110,6 +1110,28 @@ TEST(TestInterface, UpdateOverrideByIDAndTag)
EXPECT_EQ(ddwaf_run(context1, &parameter, nullptr, &result1, LONG_TIME), DDWAF_MATCH);
EXPECT_EQ(ddwaf_run(context2, &parameter, nullptr, &result2, LONG_TIME), DDWAF_MATCH);

EXPECT_EVENTS(result1,
{.id = "1",
.name = "rule1",
.tags = {{"type", "flow1"}, {"category", "category1"}, {"confidence", "1"}},
.matches = {{.op = "match_regex",
.op_value = "rule1",
.highlight = "rule1",
.args = {
{.name = "input", .value = "rule1", .address = "value1", .path = {}}}}}});

EXPECT_EVENTS(result2,
{.id = "1",
.name = "rule1",
.tags = {{"type", "flow1"}, {"category", "category1"}, {"confidence", "1"},
{"new_tag", "new_value"}},
.actions = {"block"},
.matches = {{.op = "match_regex",
.op_value = "rule1",
.highlight = "rule1",
.args = {
{.name = "input", .value = "rule1", .address = "value1", .path = {}}}}}});

EXPECT_ACTIONS(result1, {});
EXPECT_ACTIONS(
result2, {{"block_request",
Expand Down Expand Up @@ -1149,6 +1171,28 @@ TEST(TestInterface, UpdateOverrideByIDAndTag)
EXPECT_EQ(ddwaf_run(context2, &parameter, nullptr, &result2, LONG_TIME), DDWAF_MATCH);
EXPECT_EQ(ddwaf_run(context3, &parameter, nullptr, &result3, LONG_TIME), DDWAF_MATCH);

EXPECT_EVENTS(result2,
{.id = "1",
.name = "rule1",
.tags = {{"type", "flow1"}, {"category", "category1"}, {"confidence", "1"},
{"new_tag", "new_value"}},
.actions = {"block"},
.matches = {{.op = "match_regex",
.op_value = "rule1",
.highlight = "rule1",
.args = {
{.name = "input", .value = "rule1", .address = "value1", .path = {}}}}}});

EXPECT_EVENTS(result3,
{.id = "1",
.name = "rule1",
.tags = {{"type", "flow1"}, {"category", "category1"}, {"confidence", "1"}},
.matches = {{.op = "match_regex",
.op_value = "rule1",
.highlight = "rule1",
.args = {
{.name = "input", .value = "rule1", .address = "value1", .path = {}}}}}});

EXPECT_ACTIONS(
result2, {{"block_request",
{{"status_code", "403"}, {"grpc_status_code", "10"}, {"type", "auto"}}}});
Expand Down

0 comments on commit 2b05815

Please sign in to comment.