diff --git a/userspace/engine/falco_common.cpp b/userspace/engine/falco_common.cpp index e64bca21..69068f65 100644 --- a/userspace/engine/falco_common.cpp +++ b/userspace/engine/falco_common.cpp @@ -48,11 +48,6 @@ falco_common::~falco_common() } } -void falco_common::set_inspector(sinsp *inspector) -{ - m_inspector = inspector; -} - void falco_common::init(const char *lua_main_filename, const char *alternate_lua_dir) { ifstream is; diff --git a/userspace/engine/falco_common.h b/userspace/engine/falco_common.h index 6f231490..494072a8 100644 --- a/userspace/engine/falco_common.h +++ b/userspace/engine/falco_common.h @@ -71,8 +71,6 @@ public: void init(const char *lua_main_filename, const char *alternate_lua_dir); - void set_inspector(sinsp *inspector); - // Priority levels, as a vector of strings static std::vector priority_names; @@ -94,8 +92,6 @@ protected: std::mutex m_ls_semaphore; - sinsp *m_inspector; - private: void add_lua_path(std::string &path); -}; \ No newline at end of file +}; diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index 54a79d3e..39ab9f0b 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -40,10 +40,8 @@ string lua_print_stats = "print_stats"; using namespace std; -nlohmann::json::json_pointer falco_engine::k8s_audit_time = "/stageTimestamp"_json_pointer; - falco_engine::falco_engine(bool seed_rng, const std::string& alternate_lua_dir) - : m_rules(NULL), m_next_ruleset_id(0), + : m_next_ruleset_id(0), m_min_priority(falco_common::PRIORITY_DEBUG), m_sampling_ratio(1), m_sampling_multiplier(0), m_replace_container_info(false) @@ -54,26 +52,16 @@ falco_engine::falco_engine(bool seed_rng, const std::string& alternate_lua_dir) falco_common::init(m_lua_main_filename.c_str(), alternate_lua_dir.c_str()); falco_rules::init(m_ls); - m_sinsp_rules.reset(new falco_sinsp_ruleset()); - m_k8s_audit_rules.reset(new falco_ruleset()); - if(seed_rng) { srandom((unsigned) getpid()); } m_default_ruleset_id = find_ruleset_id(m_default_ruleset); - - // Create this now so we can potentially list filters and exit - m_json_factory = make_shared(); } falco_engine::~falco_engine() { - if (m_rules) - { - delete m_rules; - } } uint32_t falco_engine::engine_version() @@ -153,32 +141,16 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al void falco_engine::load_rules(const string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version) { - // The engine must have been given an inspector by now. - if(! m_inspector) - { - throw falco_exception("No inspector provided"); - } - - if(!m_sinsp_factory) - { - m_sinsp_factory = make_shared(m_inspector); - } - if(!m_rules) { - m_rules = new falco_rules(m_inspector, - this, - m_ls); - } + m_rules.reset(new falco_rules(this, + m_ls)); - // Note that falco_formats is added to the lua state used - // by the falco engine only. Within the engine, only - // formats.formatter is used, so we can unconditionally set - // json_output to false. - bool json_output = false; - bool json_include_output_property = false; - bool json_include_tags_property = false; - falco_formats::init(m_inspector, this, m_ls, json_output, json_include_output_property, json_include_tags_property); + for(auto const &it : m_filter_factories) + { + m_rules->add_filter_factory(it.first, it.second); + } + } m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, required_engine_version); } @@ -213,8 +185,10 @@ void falco_engine::enable_rule(const string &substring, bool enabled, const stri uint16_t ruleset_id = find_ruleset_id(ruleset); bool match_exact = false; - m_sinsp_rules->enable(substring, match_exact, enabled, ruleset_id); - m_k8s_audit_rules->enable(substring, match_exact, enabled, ruleset_id); + for(auto &it : m_rulesets) + { + it.second->enable(substring, match_exact, enabled, ruleset_id); + } } void falco_engine::enable_rule(const string &substring, bool enabled) @@ -227,8 +201,10 @@ void falco_engine::enable_rule_exact(const string &rule_name, bool enabled, cons uint16_t ruleset_id = find_ruleset_id(ruleset); bool match_exact = true; - m_sinsp_rules->enable(rule_name, match_exact, enabled, ruleset_id); - m_k8s_audit_rules->enable(rule_name, match_exact, enabled, ruleset_id); + for(auto &it : m_rulesets) + { + it.second->enable(rule_name, match_exact, enabled, ruleset_id); + } } void falco_engine::enable_rule_exact(const string &rule_name, bool enabled) @@ -240,8 +216,10 @@ void falco_engine::enable_rule_by_tag(const set &tags, bool enabled, con { uint16_t ruleset_id = find_ruleset_id(ruleset); - m_sinsp_rules->enable_tags(tags, enabled, ruleset_id); - m_k8s_audit_rules->enable_tags(tags, enabled, ruleset_id); + for(auto &it : m_rulesets) + { + it.second->enable_tags(tags, enabled, ruleset_id); + } } void falco_engine::enable_rule_by_tag(const set &tags, bool enabled) @@ -272,68 +250,85 @@ uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset) { uint16_t ruleset_id = find_ruleset_id(ruleset); - return m_sinsp_rules->num_rules_for_ruleset(ruleset_id) + - m_k8s_audit_rules->num_rules_for_ruleset(ruleset_id); + uint64_t ret = 0; + for(auto &it : m_rulesets) + { + ret += it.second->num_rules_for_ruleset(ruleset_id); + } + + return ret; } -void falco_engine::evttypes_for_ruleset(std::vector &evttypes, const std::string &ruleset) +void falco_engine::evttypes_for_ruleset(std::string &source, std::set &evttypes, const std::string &ruleset) { uint16_t ruleset_id = find_ruleset_id(ruleset); - return m_sinsp_rules->evttypes_for_ruleset(evttypes, ruleset_id); + auto it = m_rulesets.find(source); + if(it == m_rulesets.end()) + { + string err = "Unknown event source " + source; + throw falco_exception(err); + } + + it->second->evttypes_for_ruleset(evttypes, ruleset_id); + } -void falco_engine::syscalls_for_ruleset(std::vector &syscalls, const std::string &ruleset) +std::shared_ptr falco_engine::create_formatter(const std::string &source, + const std::string &output) { - uint16_t ruleset_id = find_ruleset_id(ruleset); + auto it = m_format_factories.find(source); - return m_sinsp_rules->syscalls_for_ruleset(syscalls, ruleset_id); + if(it == m_format_factories.end()) + { + string err = "Unknown event source " + source; + throw falco_exception(err); + } + + return it->second->create_formatter(output); } -unique_ptr falco_engine::process_sinsp_event(sinsp_evt *ev, uint16_t ruleset_id) +unique_ptr falco_engine::process_event(std::string &source, gen_event *ev, uint16_t ruleset_id) { if(should_drop_evt()) { return unique_ptr(); } - if(!m_sinsp_rules->run(ev, ruleset_id)) + auto it = m_rulesets.find(source); + if(it == m_rulesets.end()) + { + string err = "Unknown event source " + source; + throw falco_exception(err); + } + + if (!it->second->run(ev, ruleset_id)) { return unique_ptr(); } unique_ptr res(new rule_result()); - res->source = "syscall"; + res->source = source; populate_rule_result(res, ev); return res; } -unique_ptr falco_engine::process_sinsp_event(sinsp_evt *ev) +unique_ptr falco_engine::process_event(std::string &source, gen_event *ev) { - return process_sinsp_event(ev, m_default_ruleset_id); + return process_event(source, ev, m_default_ruleset_id); } -unique_ptr falco_engine::process_k8s_audit_event(json_event *ev, uint16_t ruleset_id) +void falco_engine::add_source(std::string &source, + std::shared_ptr filter_factory, + std::shared_ptr formatter_factory) { - if(should_drop_evt()) - { - return unique_ptr(); - } + m_filter_factories[source] = filter_factory; + m_format_factories[source] = formatter_factory; - // All k8s audit events have the single tag "1". - if(!m_k8s_audit_rules->run((gen_event *) ev, 1, ruleset_id)) - { - return unique_ptr(); - } - - unique_ptr res(new rule_result()); - res->source = "k8s_audit"; - - populate_rule_result(res, ev); - - return res; + std::shared_ptr ruleset(new falco_ruleset()); + m_rulesets[source] = ruleset; } void falco_engine::populate_rule_result(unique_ptr &res, gen_event *ev) @@ -412,29 +407,30 @@ void falco_engine::print_stats() } -void falco_engine::add_sinsp_filter(string &rule, - set &evttypes, - set &syscalls, - set &tags, - sinsp_filter* filter) +void falco_engine::add_filter(std::shared_ptr filter, + std::string &rule, + std::string &source, + std::set &tags) { - m_sinsp_rules->add(rule, evttypes, syscalls, tags, filter); -} + auto it = m_rulesets.find(source); + if(it == m_rulesets.end()) + { + string err = "Unknown event source " + source; + throw falco_exception(err); + } -void falco_engine::add_k8s_audit_filter(string &rule, - set &tags, - json_event_filter* filter) -{ - // All k8s audit events have a single tag "1". - std::set event_tags = {1}; - - m_k8s_audit_rules->add(rule, tags, event_tags, filter); + it->second->add(rule, tags, filter); } void falco_engine::clear_filters() { - m_sinsp_rules.reset(new falco_sinsp_ruleset()); - m_k8s_audit_rules.reset(new falco_ruleset()); + m_rulesets.clear(); + + for(auto &it : m_filter_factories) + { + std::shared_ptr ruleset(new falco_ruleset()); + m_rulesets[it.first] = ruleset; + } } void falco_engine::set_sampling_ratio(uint32_t sampling_ratio) @@ -468,23 +464,3 @@ inline bool falco_engine::should_drop_evt() double coin = (random() * (1.0/RAND_MAX)); return (coin >= (1.0/(m_sampling_multiplier * m_sampling_ratio))); } - -sinsp_filter_factory &falco_engine::sinsp_factory() -{ - if(!m_sinsp_factory) - { - throw falco_exception("No sinsp factory created yet"); - } - - return *(m_sinsp_factory.get()); -} - -json_event_filter_factory &falco_engine::json_factory() -{ - if(!m_json_factory) - { - throw falco_exception("No json factory created yet"); - } - - return *(m_json_factory.get()); -} diff --git a/userspace/engine/falco_engine.h b/userspace/engine/falco_engine.h index 21c15525..352bcb67 100644 --- a/userspace/engine/falco_engine.h +++ b/userspace/engine/falco_engine.h @@ -28,10 +28,7 @@ limitations under the License. #include -#include "sinsp.h" -#include "filter.h" - -#include "json_evt.h" +#include "gen_filter.h" #include "rules.h" #include "ruleset.h" @@ -153,8 +150,8 @@ public: // void set_extra(string &extra, bool replace_container_info); - // **Methods Related to k8s audit log events, which are - // **represented as json objects. + // Represents the result of matching an event against a set of + // rules. struct rule_result { gen_event *evt; std::string rule; @@ -176,85 +173,68 @@ public: // with a ruleset string. // // the returned rule_result is allocated and must be delete()d. - std::unique_ptr process_k8s_audit_event(json_event *ev, uint16_t ruleset_id); + std::unique_ptr process_event(std::string &source, gen_event *ev, uint16_t ruleset_id); // // Wrapper assuming the default ruleset // - std::unique_ptr process_k8s_audit_event(json_event *ev); + std::unique_ptr process_event(std::string &source, gen_event *ev); // - // Add a k8s_audit filter to the engine + // Configure the engine to support events with the provided + // source, with the provided filter factory and formatter factory. // - void add_k8s_audit_filter(std::string &rule, - std::set &tags, - json_event_filter* filter); - - // **Methods Related to Sinsp Events e.g system calls - // - // Given a ruleset, fill in a bitset containing the event - // types for which this ruleset can run. - // - void evttypes_for_ruleset(std::vector &evttypes, const std::string &ruleset); + void add_source(std::string &source, + std::shared_ptr filter_factory, + std::shared_ptr formatter_factory); // - // Given a ruleset, fill in a bitset containing the syscalls - // for which this ruleset can run. + // Add a filter for the provided event source to the engine // - void syscalls_for_ruleset(std::vector &syscalls, const std::string &ruleset); + void add_filter(std::shared_ptr filter, + std::string &rule, + std::string &source, + std::set &tags); // - // Given an event, check it against the set of rules in the - // engine and if a matching rule is found, return details on - // the rule that matched. If no rule matched, returns NULL. + // Given an event source and ruleset, fill in a bitset + // containing the event types for which this ruleset can run. // - // When ruleset_id is provided, use the enabled/disabled status - // associated with the provided ruleset. This is only useful - // when you have previously called enable_rule/enable_rule_by_tag - // with a ruleset string. - // - // the returned rule_result is allocated and must be delete()d. - std::unique_ptr process_sinsp_event(sinsp_evt *ev, uint16_t ruleset_id); + void evttypes_for_ruleset(std::string &source, + std::set &evttypes, + const std::string &ruleset); // - // Wrapper assuming the default ruleset + // Given a source and output string, return an + // gen_event_formatter that can format output strings for an + // event. // - std::unique_ptr process_sinsp_event(sinsp_evt *ev); - - // - // Add a filter, which is related to the specified set of - // event types/syscalls, to the engine. - // - void add_sinsp_filter(std::string &rule, - std::set &evttypes, - std::set &syscalls, - std::set &tags, - sinsp_filter* filter); - - sinsp_filter_factory &sinsp_factory(); - json_event_filter_factory &json_factory(); + std::shared_ptr create_formatter(const std::string &source, + const std::string &output); private: - static nlohmann::json::json_pointer k8s_audit_time; - // // Determine whether the given event should be matched at all // against the set of rules, given the current sampling // ratio/multiplier. // inline bool should_drop_evt(); - shared_ptr m_sinsp_factory; - shared_ptr m_json_factory; - falco_rules *m_rules; + // Maps from event source to object that can generate filters from rules + std::map> m_filter_factories; + + // Maps from event source to object that can format output strings in rules + std::map> m_format_factories; + + // Maps from event source to the set of rules for that event source + std::map> m_rulesets; + + std::unique_ptr m_rules; uint16_t m_next_ruleset_id; std::map m_known_rulesets; falco_common::priority_type m_min_priority; - std::unique_ptr m_sinsp_rules; - std::unique_ptr m_k8s_audit_rules; - void populate_rule_result(unique_ptr &res, gen_event *ev); // diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index 83a5bd1f..826e459a 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -33,6 +33,7 @@ limitations under the License. #include #include +#include #include "logger.h" #include "utils.h" @@ -258,6 +259,8 @@ uint64_t do_inspect(falco_engine *engine, uint64_t duration_start = 0; uint32_t timeouts_since_last_success_or_msg = 0; + std::string syscall_source = "syscall"; + sdropmgr.init(inspector, outputs, config.m_syscall_evt_drop_actions, @@ -371,7 +374,7 @@ uint64_t do_inspect(falco_engine *engine, // engine, which will match the event against the set // of rules. If a match is found, pass the event to // the outputs. - unique_ptr res = engine->process_sinsp_event(ev); + unique_ptr res = engine->process_event(syscall_source, ev); if(res) { outputs->handle_event(res->evt, res->rule, res->source, res->priority_num, res->format, res->tags); @@ -769,9 +772,21 @@ int falco_init(int argc, char **argv) } engine = new falco_engine(true, alternate_lua_dir); - engine->set_inspector(inspector); engine->set_extra(output_format, replace_container_info); + // Create "factories" that can create filters/formatters for + // syscalls and k8s audit events. + std::shared_ptr syscall_filter_factory(new sinsp_filter_factory(inspector)); + std::shared_ptr k8s_audit_filter_factory(new json_event_filter_factory()); + + std::shared_ptr syscall_formatter_factory(new sinsp_evt_formatter_factory(inspector)); + std::shared_ptr k8s_audit_formatter_factory(new json_event_formatter_factory(k8s_audit_filter_factory)); + + string syscall_source = "syscall"; + string k8s_audit_source = "k8s_audit"; + engine->add_source(syscall_source, syscall_filter_factory, syscall_formatter_factory); + engine->add_source(k8s_audit_source, k8s_audit_filter_factory, k8s_audit_formatter_factory); + if(list_flds) { list_source_fields(engine, names_only, list_flds_source); @@ -872,6 +887,12 @@ int falco_init(int argc, char **argv) throw std::runtime_error("Could not find configuration file at " + conf_filename); } + if(config.m_json_output) + { + syscall_formatter_factory->set_output_format(gen_event_formatter::OF_JSON); + k8s_audit_formatter_factory->set_output_format(gen_event_formatter::OF_JSON); + } + if (rules_filenames.size()) { config.m_rules_filenames = rules_filenames;