From 1e0430dff98cf696a742c50471b50f9283bcdb55 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Thu, 11 Jan 2024 13:06:03 -0800 Subject: [PATCH] Make compile_condition() a protected method for use in subclasses Move the part of compile_rule_infos that actually compiled a condition string into a sinsp_filter into a standalone method compile_condition(). That way it can be used by classes that derive from rule_loader::compiler() and want to compile condition strings. This implementation also saves the compiled filter as a part of the falco_rule object so it does not need to be compiled again wihin the falco engine after rules loading. Signed-off-by: Mark Stemm --- userspace/engine/rule_loader_compiler.cpp | 119 ++++++++++++++-------- userspace/engine/rule_loader_compiler.h | 21 ++++ 2 files changed, 96 insertions(+), 44 deletions(-) diff --git a/userspace/engine/rule_loader_compiler.cpp b/userspace/engine/rule_loader_compiler.cpp index 27ab2271..67ef7dea 100644 --- a/userspace/engine/rule_loader_compiler.cpp +++ b/userspace/engine/rule_loader_compiler.cpp @@ -405,17 +405,72 @@ static bool err_is_unknown_type_or_field(const std::string& err) || err.find("unknown event type") != std::string::npos; } -void rule_loader::compiler::compile_rule_infos( - configuration& cfg, - const collector& col, - indexed_vector& lists, - indexed_vector& macros, - indexed_vector& out) const +bool rule_loader::compiler::compile_condition( + configuration& cfg, + indexed_vector& lists, + const indexed_vector& macros, + const std::string& condition, + std::shared_ptr filter_factory, + rule_loader::context cond_ctx, + rule_loader::context parent_ctx, + bool allow_unknown_fields, + indexed_vector& macros_out, + std::shared_ptr& ast_out, + std::shared_ptr& filter_out) const { - std::string err, condition; std::set warn_codes; filter_warning_resolver warn_resolver; - for (const auto &r : col.rules()) + ast_out = parse_condition(condition, lists, cond_ctx); + resolve_macros(macros, macros_out, ast_out, condition, MAX_VISIBILITY, parent_ctx); + + // check for warnings in the filtering condition + if(warn_resolver.run(ast_out.get(), warn_codes)) + { + for(const auto& w : warn_codes) + { + cfg.res->add_warning(w, "", parent_ctx); + } + } + + // validate the rule's condition: we compile it into a sinsp filter + // on-the-fly and we throw an exception with details on failure + sinsp_filter_compiler compiler(filter_factory, ast_out.get()); + try + { + filter_out.reset(compiler.compile()); + } + catch(const sinsp_exception& e) + { + // skip the rule silently if skip_if_unknown_filter is true and + // we encountered some specific kind of errors + std::string err = e.what(); + if(err_is_unknown_type_or_field(err) && allow_unknown_fields) + { + cfg.res->add_warning( + falco::load_result::load_result::LOAD_UNKNOWN_FILTER, + err, + cond_ctx); + return false; + } + rule_loader::context ctx(compiler.get_pos(), condition, cond_ctx); + throw rule_loader::rule_load_exception( + falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION, + err, + ctx); + } + + return true; +} + +void rule_loader::compiler::compile_rule_infos( + configuration& cfg, + const collector& col, + indexed_vector& lists, + indexed_vector& macros, + indexed_vector& out) const +{ + std::string err, condition; + for(const auto& r : col.rules()) { // skip the rule if it has an unknown source if (r.unknown_source) @@ -439,18 +494,6 @@ void rule_loader::compiler::compile_rule_infos( build_rule_exception_infos( r.exceptions, rule.exception_fields, condition); } - rule.condition = parse_condition(condition, lists, r.cond_ctx); - resolve_macros(col.macros(), macros, rule.condition, condition, MAX_VISIBILITY, r.ctx); - - // check for warnings in the filtering condition - warn_codes.clear(); - if (warn_resolver.run(rule.condition.get(), warn_codes)) - { - for (const auto &w : warn_codes) - { - cfg.res->add_warning(w, "", r.ctx); - } - } // build rule output message rule.output = r.output; @@ -478,31 +521,19 @@ void rule_loader::compiler::compile_rule_infos( r.output_ctx); } - // validate the rule's condition: we compile it into a sinsp filter - // on-the-fly and we throw an exception with details on failure - sinsp_filter_compiler compiler(cfg.sources.at(r.source)->filter_factory, rule.condition.get()); - try + if (!compile_condition(cfg, + lists, + col.macros(), + condition, + cfg.sources.at(r.source)->filter_factory, + r.cond_ctx, + r.ctx, + r.skip_if_unknown_filter, + macros, + rule.condition, + rule.filter)) { - std::shared_ptr sfPtr(compiler.compile()); - } - catch (const sinsp_exception& e) - { - // skip the rule silently if skip_if_unknown_filter is true and - // we encountered some specific kind of errors - std::string err = e.what(); - if (err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter) - { - cfg.res->add_warning( - falco::load_result::load_result::LOAD_UNKNOWN_FILTER, - err, - r.cond_ctx); - continue; - } - rule_loader::context ctx(compiler.get_pos(), condition, r.cond_ctx); - throw rule_loader::rule_load_exception( - falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION, - err, - ctx); + continue; } // populate set of event types and emit an special warning diff --git a/userspace/engine/rule_loader_compiler.h b/userspace/engine/rule_loader_compiler.h index 533a4013..47e8ad14 100644 --- a/userspace/engine/rule_loader_compiler.h +++ b/userspace/engine/rule_loader_compiler.h @@ -50,6 +50,27 @@ public: configuration& cfg, const collector& col, compile_output& out) const; +protected: + /*! + \brief Compile a single condition expression, + including expanding macro and list references. + + returns true if the condition could be compiled, and sets + ast_out/filter_out with the compiled filter + ast. Returns false if + the condition could not be compiled and should be skipped. + */ + bool compile_condition( + configuration& cfg, + indexed_vector& lists, + const indexed_vector& macros, + const std::string& condition, + std::shared_ptr filter_factory, + rule_loader::context cond_ctx, + rule_loader::context parent_ctx, + bool allow_unknown_fields, + indexed_vector& macros_out, + std::shared_ptr& ast_out, + std::shared_ptr& filter_out) const; private: void compile_list_infos(