From 803b2ab594c42606879de3b78f5ae2b5798ca93b Mon Sep 17 00:00:00 2001 From: Jason Dellaluce Date: Thu, 31 Aug 2023 14:56:13 +0000 Subject: [PATCH] fix(userspace/engine): support appending to unknown sources Signed-off-by: Jason Dellaluce --- userspace/engine/falco_engine.cpp | 4 +- userspace/engine/rule_loader.cpp | 4 +- userspace/engine/rule_loader.h | 1 + userspace/engine/rule_loader_collector.cpp | 59 +++++++++++++--------- userspace/engine/rule_loader_compiler.cpp | 11 ++-- 5 files changed, 48 insertions(+), 31 deletions(-) diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index 3b7969a9974..e1465c5779d 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -568,12 +568,12 @@ void falco_engine::describe_rule(std::string *rule, bool json) const output["lists"] = lists_array; json_str = writer.write(output); - } + } else { // build json information for just the specified rule auto ri = m_rule_collector.rules().at(*rule); - if(ri == nullptr) + if(ri == nullptr || ri->unknown_source) { throw falco_exception("Rule \"" + *rule + "\" is not loaded"); } diff --git a/userspace/engine/rule_loader.cpp b/userspace/engine/rule_loader.cpp index e8b46dbcfc8..68b427e99b1 100644 --- a/userspace/engine/rule_loader.cpp +++ b/userspace/engine/rule_loader.cpp @@ -547,8 +547,8 @@ rule_loader::rule_exception_info::rule_exception_info(context &ctx) rule_loader::rule_info::rule_info(context &ctx) : ctx(ctx), cond_ctx(ctx), output_ctx(ctx), index(0), visibility(0), - priority(falco_common::PRIORITY_DEBUG), enabled(true), - warn_evttypes(true), skip_if_unknown_filter(false) + unknown_source(false), priority(falco_common::PRIORITY_DEBUG), + enabled(true), warn_evttypes(true), skip_if_unknown_filter(false) { } diff --git a/userspace/engine/rule_loader.h b/userspace/engine/rule_loader.h index 3663fea022c..3fcabb81556 100644 --- a/userspace/engine/rule_loader.h +++ b/userspace/engine/rule_loader.h @@ -449,6 +449,7 @@ namespace rule_loader context output_ctx; size_t index; size_t visibility; + bool unknown_source; std::string name; std::string cond; std::string source; diff --git a/userspace/engine/rule_loader_collector.cpp b/userspace/engine/rule_loader_collector.cpp index 3a87fcf7697..89ed49a4546 100644 --- a/userspace/engine/rule_loader_collector.cpp +++ b/userspace/engine/rule_loader_collector.cpp @@ -54,7 +54,7 @@ static inline void append_info(T* prev, T& info, uint32_t id) } static void validate_exception_info( - const falco_source& source, + const falco_source* source, rule_loader::rule_exception_info &ex) { if (ex.fields.is_list) @@ -76,11 +76,14 @@ static void validate_exception_info( std::string("'") + v.item + "' is not a supported comparison operator", ex.ctx); } - for (auto &v : ex.fields.items) + if (source) { - THROW(!source.is_field_defined(v.item), - std::string("'") + v.item + "' is not a supported filter field", - ex.ctx); + for (auto &v : ex.fields.items) + { + THROW(!source->is_field_defined(v.item), + std::string("'") + v.item + "' is not a supported filter field", + ex.ctx); + } } } else @@ -96,9 +99,12 @@ static void validate_exception_info( THROW((ex.comps.item != "in" && ex.comps.item != "pmatch" && ex.comps.item != "intersects"), "When fields is a single value, comps must be one of (in, pmatch, intersects)", ex.ctx); - THROW(!source.is_field_defined(ex.fields.item), - std::string("'") + ex.fields.item + "' is not a supported filter field", - ex.ctx); + if (source) + { + THROW(!source->is_field_defined(ex.fields.item), + std::string("'") + ex.fields.item + "' is not a supported filter field", + ex.ctx); + } } } @@ -200,26 +206,25 @@ void rule_loader::collector::append(configuration& cfg, macro_info& info) void rule_loader::collector::define(configuration& cfg, rule_info& info) { + auto prev = m_rule_infos.at(info.name); + THROW(prev && prev->source != info.source, + "Rule has been re-defined with a different source", + info.ctx); + auto source = cfg.sources.at(info.source); if (!source) { + info.unknown_source = true; cfg.res->add_warning(falco::load_result::LOAD_UNKNOWN_SOURCE, "Unknown source " + info.source + ", skipping", info.ctx); - return; } - - auto prev = m_rule_infos.at(info.name); - THROW(prev && prev->source != info.source, - "Rule has been re-defined with a different source", - info.ctx); - for (auto &ex : info.exceptions) { THROW(!ex.fields.is_valid(), - "Rule exception item must have fields property with a list of fields", - ex.ctx); - validate_exception_info(*source, ex); + "Rule exception item must have fields property with a list of fields", + ex.ctx); + validate_exception_info(source, ex); } define_info(m_rule_infos, info, m_cur_index++); @@ -236,11 +241,17 @@ void rule_loader::collector::append(configuration& cfg, rule_info& info) "Appended rule must have exceptions or condition property", info.ctx); - auto source = cfg.sources.at(prev->source); - // note: this is not supposed to happen - THROW(!source, - std::string("Unknown source ") + prev->source, - info.ctx); + // note: source can be nullptr in case we've collected a + // rule for which the source is unknown + falco_source* source = nullptr; + if (!prev->unknown_source) + { + // note: if the source is not unknown, this should not return nullptr + source = cfg.sources.at(prev->source); + THROW(!source, + std::string("Unknown source ") + prev->source, + info.ctx); + } if (!info.cond.empty()) { @@ -261,7 +272,7 @@ void rule_loader::collector::append(configuration& cfg, rule_info& info) THROW(ex.values.empty(), "Rule exception must have values property with a list of values", ex.ctx); - validate_exception_info(*source, ex); + validate_exception_info(source, ex); prev->exceptions.push_back(ex); } else diff --git a/userspace/engine/rule_loader_compiler.cpp b/userspace/engine/rule_loader_compiler.cpp index 6be6b2192b5..713a070e3c2 100644 --- a/userspace/engine/rule_loader_compiler.cpp +++ b/userspace/engine/rule_loader_compiler.cpp @@ -388,17 +388,22 @@ void rule_loader::compiler::compile_rule_infos( filter_warning_resolver warn_resolver; for (auto &r : col.rules()) { + // skip the rule if it has an unknown source + if (r.unknown_source) + { + continue; + } + // skip the rule if below the minimum priority if (r.priority > cfg.min_priority) { continue; } + // note: this should not be nullptr if the source is not unknown auto source = cfg.sources.at(r.source); - // note: this is not supposed to happen - THROW(!source, - std::string("Unknown source ") + r.source, + std::string("Unknown source at compile-time") + r.source, r.ctx); // build filter AST by parsing the condition, building exceptions,