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

Rules result add compile condition context #2216

Merged
merged 2 commits into from Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
110 changes: 81 additions & 29 deletions tests/engine/test_filter_macro_resolver.cpp
Expand Up @@ -20,9 +20,27 @@ limitations under the License.
using namespace std;
using namespace libsinsp::filter::ast;

static pos_info create_pos(uint32_t idx, uint32_t line, uint32_t col)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good, but let's backport it to libs as a constructor/equality operator next!

{
pos_info ret;
ret.idx = idx;
ret.line = line;
ret.col = col;

return ret;
}

static bool operator==(const pos_info& p1, const pos_info& p2)
{
return (p1.idx == p2.idx) &&
(p1.line == p2.line) &&
(p1.col == p2.col);
}

TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
{
string macro_name = "test_macro";
pos_info macro_pos = create_pos(12, 85, 27);

SECTION("in the general case")
{
Expand All @@ -31,7 +49,7 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")

std::vector<std::unique_ptr<expr>> filter_and;
filter_and.push_back(unary_check_expr::create("evt.name", "", "exists"));
filter_and.push_back(not_expr::create(value_expr::create(macro_name)));
filter_and.push_back(not_expr::create(value_expr::create(macro_name, macro_pos)));
std::shared_ptr<expr> filter = std::move(and_expr::create(filter_and));

std::vector<std::unique_ptr<expr>> expected_and;
Expand All @@ -45,7 +63,8 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
// first run
REQUIRE(resolver.run(filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 1);
REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name);
mstemm marked this conversation as resolved.
Show resolved Hide resolved
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos);
REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(filter->is_equal(expected.get()));

Expand All @@ -61,7 +80,7 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
std::shared_ptr<expr> macro = std::move(
unary_check_expr::create("test.field", "", "exists"));

std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name));
std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name, macro_pos));

filter_macro_resolver resolver;
resolver.set_macro(macro_name, macro);
Expand All @@ -71,7 +90,8 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
REQUIRE(resolver.run(filter) == true);
REQUIRE(filter.get() != old_filter_ptr);
REQUIRE(resolver.get_resolved_macros().size() == 1);
REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos);
REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(filter->is_equal(macro.get()));

Expand All @@ -89,14 +109,17 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
string a_macro_name = macro_name + "_1";
string b_macro_name = macro_name + "_2";

pos_info a_macro_pos = create_pos(11, 75, 43);
pos_info b_macro_pos = create_pos(91, 21, 9);

std::shared_ptr<expr> a_macro = std::move(
unary_check_expr::create("one.field", "", "exists"));
std::shared_ptr<expr> b_macro = std::move(
unary_check_expr::create("another.field", "", "exists"));

std::vector<std::unique_ptr<expr>> filter_or;
filter_or.push_back(value_expr::create(a_macro_name));
filter_or.push_back(value_expr::create(b_macro_name));
filter_or.push_back(value_expr::create(a_macro_name, a_macro_pos));
filter_or.push_back(value_expr::create(b_macro_name, b_macro_pos));
std::shared_ptr<expr> filter = std::move(or_expr::create(filter_or));

std::vector<std::unique_ptr<expr>> expected_or;
Expand All @@ -111,11 +134,16 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
// first run
REQUIRE(resolver.run(filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 2);
REQUIRE(resolver.get_resolved_macros().find(a_macro_name)
!= resolver.get_resolved_macros().end());
REQUIRE(resolver.get_resolved_macros().find(b_macro_name)
!= resolver.get_resolved_macros().end());
auto a_resolved_itr = resolver.get_resolved_macros().find(a_macro_name);
REQUIRE(a_resolved_itr != resolver.get_resolved_macros().end());
REQUIRE(a_resolved_itr->first == a_macro_name);
REQUIRE(a_resolved_itr->second == a_macro_pos);

auto b_resolved_itr = resolver.get_resolved_macros().find(b_macro_name);
REQUIRE(b_resolved_itr != resolver.get_resolved_macros().end());
REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(b_resolved_itr->first == b_macro_name);
REQUIRE(b_resolved_itr->second == b_macro_pos);
REQUIRE(filter->is_equal(expected_filter.get()));

// second run
Expand All @@ -130,15 +158,18 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
string a_macro_name = macro_name + "_1";
string b_macro_name = macro_name + "_2";

pos_info a_macro_pos = create_pos(47, 1, 76);
pos_info b_macro_pos = create_pos(111, 65, 2);

std::vector<std::unique_ptr<expr>> a_macro_and;
a_macro_and.push_back(unary_check_expr::create("one.field", "", "exists"));
a_macro_and.push_back(value_expr::create(b_macro_name));
a_macro_and.push_back(value_expr::create(b_macro_name, b_macro_pos));
std::shared_ptr<expr> a_macro = std::move(and_expr::create(a_macro_and));

std::shared_ptr<expr> b_macro = std::move(
unary_check_expr::create("another.field", "", "exists"));

std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name));
std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name, a_macro_pos));

std::vector<std::unique_ptr<expr>> expected_and;
expected_and.push_back(unary_check_expr::create("one.field", "", "exists"));
Expand All @@ -152,10 +183,17 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
// first run
REQUIRE(resolver.run(filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 2);
REQUIRE(resolver.get_resolved_macros().find(a_macro_name)
!= resolver.get_resolved_macros().end());
REQUIRE(resolver.get_resolved_macros().find(b_macro_name)
!= resolver.get_resolved_macros().end());
auto a_resolved_itr = resolver.get_resolved_macros().find(a_macro_name);
REQUIRE(a_resolved_itr != resolver.get_resolved_macros().end());
REQUIRE(a_resolved_itr->first == a_macro_name);
REQUIRE(a_resolved_itr->second == a_macro_pos);

auto b_resolved_itr = resolver.get_resolved_macros().find(b_macro_name);
REQUIRE(b_resolved_itr != resolver.get_resolved_macros().end());
REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(b_resolved_itr->first == b_macro_name);
REQUIRE(b_resolved_itr->second == b_macro_pos);

REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(filter->is_equal(expected_filter.get()));

Expand All @@ -170,18 +208,20 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
TEST_CASE("Should find unknown macros", "[rule_loader]")
{
string macro_name = "test_macro";
pos_info macro_pos = create_pos(9, 4, 2);

SECTION("in the general case")
{
std::vector<std::unique_ptr<expr>> filter_and;
filter_and.push_back(unary_check_expr::create("evt.name", "", "exists"));
filter_and.push_back(not_expr::create(value_expr::create(macro_name)));
filter_and.push_back(not_expr::create(value_expr::create(macro_name, macro_pos)));
std::shared_ptr<expr> filter = std::move(and_expr::create(filter_and));

filter_macro_resolver resolver;
REQUIRE(resolver.run(filter) == false);
REQUIRE(resolver.get_unknown_macros().size() == 1);
REQUIRE(*resolver.get_unknown_macros().begin() == macro_name);
REQUIRE(resolver.get_unknown_macros().begin()->first == macro_name);
REQUIRE(resolver.get_unknown_macros().begin()->second == macro_pos);
REQUIRE(resolver.get_resolved_macros().empty());
}

Expand All @@ -190,12 +230,15 @@ TEST_CASE("Should find unknown macros", "[rule_loader]")
string a_macro_name = macro_name + "_1";
string b_macro_name = macro_name + "_2";

pos_info a_macro_pos = create_pos(32, 84, 9);
pos_info b_macro_pos = create_pos(1, 0, 5);

std::vector<std::unique_ptr<expr>> a_macro_and;
a_macro_and.push_back(unary_check_expr::create("one.field", "", "exists"));
a_macro_and.push_back(value_expr::create(b_macro_name));
a_macro_and.push_back(value_expr::create(b_macro_name, b_macro_pos));
std::shared_ptr<expr> a_macro = std::move(and_expr::create(a_macro_and));

std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name));
std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name, a_macro_pos));
auto expected_filter = clone(a_macro.get());

filter_macro_resolver resolver;
Expand All @@ -204,47 +247,56 @@ TEST_CASE("Should find unknown macros", "[rule_loader]")
// first run
REQUIRE(resolver.run(filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 1);
REQUIRE(*resolver.get_resolved_macros().begin() == a_macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->first == a_macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->second == a_macro_pos);
REQUIRE(resolver.get_unknown_macros().size() == 1);
REQUIRE(*resolver.get_unknown_macros().begin() == b_macro_name);
REQUIRE(resolver.get_unknown_macros().begin()->first == b_macro_name);
REQUIRE(resolver.get_unknown_macros().begin()->second == b_macro_pos);
REQUIRE(filter->is_equal(expected_filter.get()));
}
}

TEST_CASE("Should undefine macro", "[rule_loader]")
{
string macro_name = "test_macro";
pos_info macro_pos_1 = create_pos(12, 9, 3);
pos_info macro_pos_2 = create_pos(9, 6, 3);

std::shared_ptr<expr> macro = std::move(unary_check_expr::create("test.field", "", "exists"));
std::shared_ptr<expr> a_filter = std::move(value_expr::create(macro_name));
std::shared_ptr<expr> b_filter = std::move(value_expr::create(macro_name));
std::shared_ptr<expr> a_filter = std::move(value_expr::create(macro_name, macro_pos_1));
std::shared_ptr<expr> b_filter = std::move(value_expr::create(macro_name, macro_pos_2));
filter_macro_resolver resolver;

resolver.set_macro(macro_name, macro);
REQUIRE(resolver.run(a_filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 1);
REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos_1);
REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(a_filter->is_equal(macro.get()));

resolver.set_macro(macro_name, NULL);
REQUIRE(resolver.run(b_filter) == false);
REQUIRE(resolver.get_resolved_macros().empty());
REQUIRE(resolver.get_unknown_macros().size() == 1);
REQUIRE(*resolver.get_unknown_macros().begin() == macro_name);
REQUIRE(resolver.get_unknown_macros().begin()->first == macro_name);
REQUIRE(resolver.get_unknown_macros().begin()->second == macro_pos_2);
}

// checks that the macro AST is cloned and not shared across resolved filters
TEST_CASE("Should clone macro AST", "[rule_loader]")
{
string macro_name = "test_macro";
pos_info macro_pos = create_pos(5, 2, 8888);
std::shared_ptr<unary_check_expr> macro = std::move(unary_check_expr::create("test.field", "", "exists"));
std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name));
std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name, macro_pos));
filter_macro_resolver resolver;

resolver.set_macro(macro_name, macro);
REQUIRE(resolver.run(filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 1);
REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos);
REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(filter->is_equal(macro.get()));

Expand Down
45 changes: 34 additions & 11 deletions tests/engine/test_rulesets.cpp
Expand Up @@ -27,30 +27,51 @@ static uint16_t other_non_default_ruleset = 2;
static std::set<std::string> tags = {"some_tag", "some_other_tag"};
static std::set<uint16_t> evttypes = { ppm_event_type::PPME_GENERIC_E };

static std::shared_ptr<libsinsp::filter::ast::expr> create_filter()
static std::shared_ptr<gen_event_filter_factory> create_factory()
{
std::shared_ptr<gen_event_filter_factory> ret(new sinsp_filter_factory(NULL));

return ret;
}

static std::shared_ptr<libsinsp::filter::ast::expr> create_ast(
std::shared_ptr<gen_event_filter_factory> f)
{
libsinsp::filter::parser parser("evt.type=open");
std::shared_ptr<libsinsp::filter::ast::expr> ret(parser.parse());

return ret;
}

static std::shared_ptr<filter_ruleset> create_ruleset()
static std::shared_ptr<gen_event_filter> create_filter(
std::shared_ptr<gen_event_filter_factory> f,
std::shared_ptr<libsinsp::filter::ast::expr> ast)
{
sinsp_filter_compiler compiler(f, ast.get());
std::shared_ptr<gen_event_filter> filter(compiler.compile());

return filter;
}

static std::shared_ptr<filter_ruleset> create_ruleset(
std::shared_ptr<gen_event_filter_factory> f)
{
std::shared_ptr<gen_event_filter_factory> f(new sinsp_filter_factory(NULL));
std::shared_ptr<filter_ruleset> ret(new evttype_index_ruleset(f));
return ret;
}

TEST_CASE("Should enable/disable on ruleset", "[rulesets]")
{
auto r = create_ruleset();
auto filter = create_filter();
auto f = create_factory();
auto r = create_ruleset(f);
auto ast = create_ast(f);
auto filter = create_filter(f, ast);
falco_rule rule;
rule.name = "one_rule";
rule.source = falco_common::syscall_source;
rule.tags = tags;

r->add(rule, filter);
r->add(rule, filter, ast);

SECTION("Should enable/disable for exact match w/ default ruleset")
{
Expand Down Expand Up @@ -184,21 +205,23 @@ TEST_CASE("Should enable/disable on ruleset", "[rulesets]")

TEST_CASE("Should enable/disable on ruleset for incremental adding tags", "[rulesets]")
{
auto r = create_ruleset();
auto f = create_factory();
auto r = create_ruleset(f);
auto ast = create_ast(f);

auto rule1_filter = create_filter();
auto rule1_filter = create_filter(f, ast);
falco_rule rule1;
rule1.name = "one_rule";
rule1.source = falco_common::syscall_source;
rule1.tags = {"rule1_tag"};
r->add(rule1, rule1_filter);
r->add(rule1, rule1_filter, ast);

auto rule2_filter = create_filter();
auto rule2_filter = create_filter(f, ast);
falco_rule rule2;
rule2.name = "two_rule";
rule2.source = falco_common::syscall_source;
rule2.tags = {"rule2_tag"};
r->add(rule2, rule2_filter);
r->add(rule2, rule2_filter, ast);

std::set<std::string> want_tags;

Expand Down
3 changes: 1 addition & 2 deletions userspace/engine/evttype_index_ruleset.cpp
Expand Up @@ -153,12 +153,11 @@ void evttype_index_ruleset::ruleset_filters::evttypes_for_ruleset(std::set<uint1

void evttype_index_ruleset::add(
const falco_rule& rule,
std::shared_ptr<gen_event_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition)
{
try
{
sinsp_filter_compiler compiler(m_filter_factory, condition.get());
shared_ptr<gen_event_filter> filter(compiler.compile());
std::shared_ptr<filter_wrapper> wrap(new filter_wrapper());
wrap->rule = rule;
wrap->filter = filter;
Expand Down
1 change: 1 addition & 0 deletions userspace/engine/evttype_index_ruleset.h
Expand Up @@ -41,6 +41,7 @@ class evttype_index_ruleset: public filter_ruleset

void add(
const falco_rule& rule,
std::shared_ptr<gen_event_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition) override;

void clear() override;
Expand Down