From b8a95d262f9a0e782d9d28775195cf8220c92f8e Mon Sep 17 00:00:00 2001 From: Jason Dellaluce Date: Mon, 11 Apr 2022 11:41:40 +0000 Subject: [PATCH] refactor(userspace/engine): polish evttype resolver and use it in rule loader Signed-off-by: Jason Dellaluce --- userspace/engine/falco_engine.cpp | 3 +- userspace/engine/falco_engine.h | 1 + userspace/engine/filter_evttype_resolver.cpp | 72 +++++++++----------- userspace/engine/filter_evttype_resolver.h | 1 + userspace/engine/rule_loader.cpp | 24 +++++-- 5 files changed, 58 insertions(+), 43 deletions(-) diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index 1a03d59f..ace30b7a 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -412,6 +412,7 @@ void falco_engine::print_stats() void falco_engine::add_filter(std::shared_ptr filter, std::string &rule, std::string &source, + std::set &evttypes, std::set &tags) { auto it = find_ruleset(source); @@ -421,7 +422,7 @@ void falco_engine::add_filter(std::shared_ptr filter, throw falco_exception(err); } - it->ruleset->add(source, rule, tags, filter); + it->ruleset->add(source, rule, tags, evttypes, filter); } bool falco_engine::is_source_valid(const std::string &source) diff --git a/userspace/engine/falco_engine.h b/userspace/engine/falco_engine.h index 8a558f51..adbf61df 100644 --- a/userspace/engine/falco_engine.h +++ b/userspace/engine/falco_engine.h @@ -203,6 +203,7 @@ public: void add_filter(std::shared_ptr filter, std::string &rule, std::string &source, + std::set &evttypes, std::set &tags); // diff --git a/userspace/engine/filter_evttype_resolver.cpp b/userspace/engine/filter_evttype_resolver.cpp index cc8befd7..6934a41f 100644 --- a/userspace/engine/filter_evttype_resolver.cpp +++ b/userspace/engine/filter_evttype_resolver.cpp @@ -27,15 +27,29 @@ static bool is_evttype_operator(const string& op) return op == "==" || op == "=" || op == "!=" || op == "in"; } +void filter_evttype_resolver::inversion(set& types) +{ + set all_types; + evttypes("", all_types); + if (types != all_types) // we don't invert the "all types" set + { + set diff = types; + types.clear(); + set_difference( + all_types.begin(), all_types.end(), diff.begin(), diff.end(), + inserter(types, types.begin())); + } +} + void filter_evttype_resolver::evttypes(string evtname, set& out) { // Fill in from 2 to PPM_EVENT_MAX-1. 0 and 1 are excluded as - // those are PPM_GENERIC_E/PPME_GENERIC_X. + // those are PPM_GENERIC_E/PPME_GENERIC_X const struct ppm_event_info* etable = g_infotables.m_event_info; for(uint16_t i = 2; i < PPM_EVENT_MAX; i++) { - // Skip "old" event versions that have been replaced - // by newer event versions, or events that are unused. + // Skip "old" event versions, unused events, or events not matching + // the requested evtname if(!(etable[i].flags & (EF_OLD_VERSION | EF_UNUSED)) && (evtname.empty() || string(etable[i].name) == evtname)) { @@ -49,9 +63,7 @@ void filter_evttype_resolver::evttypes(ast::expr* filter, set& out) m_expect_value = false; m_last_node_evttypes.clear(); filter->accept(this); - copy(m_last_node_evttypes.begin(), - m_last_node_evttypes.end(), - inserter(out, out.begin())); + out.insert(m_last_node_evttypes.begin(), m_last_node_evttypes.end()); } void filter_evttype_resolver::evttypes( @@ -60,57 +72,47 @@ void filter_evttype_resolver::evttypes( m_expect_value = false; m_last_node_evttypes.clear(); filter.get()->accept(this); - copy(m_last_node_evttypes.begin(), - m_last_node_evttypes.end(), - inserter(out, out.begin())); + out.insert(m_last_node_evttypes.begin(), m_last_node_evttypes.end()); } +// "and" nodes evttypes are the intersection of the evttypes of their children. +// we initialize the set with "all event types" void filter_evttype_resolver::visit(ast::and_expr* e) { - set nodetypes; - evttypes("", nodetypes); + set types, inters; + evttypes("", types); m_last_node_evttypes.clear(); for (auto &c : e->children) { - set inters; + inters.clear(); c->accept(this); set_intersection( - nodetypes.begin(), nodetypes.end(), + types.begin(), types.end(), m_last_node_evttypes.begin(), m_last_node_evttypes.end(), - std::inserter(inters, inters.begin())); - nodetypes = inters; + inserter(inters, inters.begin())); + types = inters; } - m_last_node_evttypes = nodetypes; + m_last_node_evttypes = types; } +// "or" nodes evttypes are the union of the evttypes their children void filter_evttype_resolver::visit(ast::or_expr* e) { - set nodetypes; + set types; m_last_node_evttypes.clear(); for (auto &c : e->children) { c->accept(this); - copy(m_last_node_evttypes.begin(), - m_last_node_evttypes.end(), - inserter(nodetypes, nodetypes.begin())); + types.insert(m_last_node_evttypes.begin(), m_last_node_evttypes.end()); } - m_last_node_evttypes = nodetypes; + m_last_node_evttypes = types; } void filter_evttype_resolver::visit(ast::not_expr* e) { - set diff, all_types; m_last_node_evttypes.clear(); e->child->accept(this); - evttypes("", all_types); - if (all_types != m_last_node_evttypes) - { - diff = m_last_node_evttypes; - m_last_node_evttypes.clear(); - set_difference( - all_types.begin(), all_types.end(), diff.begin(), diff.end(), - inserter(m_last_node_evttypes, m_last_node_evttypes.begin())); - } + inversion(m_last_node_evttypes); } void filter_evttype_resolver::visit(ast::binary_check_expr* e) @@ -123,13 +125,7 @@ void filter_evttype_resolver::visit(ast::binary_check_expr* e) m_expect_value = false; if (e->op == "!=") { - set all_types; - set diff = m_last_node_evttypes; - m_last_node_evttypes.clear(); - evttypes("", all_types); - set_difference( - all_types.begin(), all_types.end(), diff.begin(), diff.end(), - inserter(m_last_node_evttypes, m_last_node_evttypes.begin())); + inversion(m_last_node_evttypes); } return; } diff --git a/userspace/engine/filter_evttype_resolver.h b/userspace/engine/filter_evttype_resolver.h index c55dbe07..57401861 100644 --- a/userspace/engine/filter_evttype_resolver.h +++ b/userspace/engine/filter_evttype_resolver.h @@ -62,6 +62,7 @@ private: void visit(libsinsp::filter::ast::list_expr* e) override; void visit(libsinsp::filter::ast::unary_check_expr* e) override; void visit(libsinsp::filter::ast::binary_check_expr* e) override; + void inversion(std::set& types); bool m_expect_value; std::set m_last_node_evttypes; diff --git a/userspace/engine/rule_loader.cpp b/userspace/engine/rule_loader.cpp index 81d05135..6abcaf39 100644 --- a/userspace/engine/rule_loader.cpp +++ b/userspace/engine/rule_loader.cpp @@ -17,6 +17,7 @@ limitations under the License. #include "falco_engine.h" #include "rule_loader.h" #include "filter_macro_resolver.h" +#include "filter_evttype_resolver.h" #define MAX_VISIBILITY ((uint32_t) -1) #define THROW(cond, err) { if (cond) { throw falco_exception(err); } } @@ -701,11 +702,14 @@ void rule_loader::compile_rule_infos( throw falco_exception("Rule " + rule.name + ": error " + err); } } - cfg.engine->add_filter(filter, rule.name, rule.source, rule.tags); - if (rule.source == falco_common::syscall_source && r.warn_evttypes) + + set evttypes; + if(rule.source == falco_common::syscall_source) { - auto evttypes = filter->evttypes(); - if (evttypes.size() == 0 || evttypes.size() > 100) + filter_evttype_resolver resolver; + resolver.evttypes(ast, evttypes); + if ((evttypes.empty() || evttypes.size() > 100) + && r.warn_evttypes) { cfg.warnings.push_back( "Rule " + rule.name + ": warning (no-evttype):\n" + @@ -713,6 +717,18 @@ void rule_loader::compile_rule_infos( + " This has a significant performance penalty."); } } + else if (rule.source == "k8s_audit") + { + // todo(jasondellaluce): remove this case once k8saudit + // gets ported to a plugin + evttypes = { ppm_event_type::PPME_GENERIC_X }; + } + else + { + evttypes = { ppm_event_type::PPME_PLUGINEVENT_E }; + } + + cfg.engine->add_filter(filter, rule.name, rule.source, evttypes, rule.tags); cfg.engine->enable_rule(rule.name, r.enabled); } catch (exception& e)