diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index 9b2b427fbfa..5ff5df21254 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -208,7 +208,7 @@ void falco_engine::enable_rule(const string &substring, bool enabled, const stri for(auto &it : m_rulesets) { - it.second->enable(substring, match_exact, enabled, ruleset_id); + it.ruleset->enable(substring, match_exact, enabled, ruleset_id); } } @@ -219,7 +219,7 @@ void falco_engine::enable_rule_exact(const string &rule_name, bool enabled, cons for(auto &it : m_rulesets) { - it.second->enable(rule_name, match_exact, enabled, ruleset_id); + it.ruleset->enable(rule_name, match_exact, enabled, ruleset_id); } } @@ -229,7 +229,7 @@ void falco_engine::enable_rule_by_tag(const set &tags, bool enabled, con for(auto &it : m_rulesets) { - it.second->enable_tags(tags, enabled, ruleset_id); + it.ruleset->enable_tags(tags, enabled, ruleset_id); } } @@ -259,7 +259,7 @@ uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset) uint64_t ret = 0; for(auto &it : m_rulesets) { - ret += it.second->num_rules_for_ruleset(ruleset_id); + ret += it.ruleset->num_rules_for_ruleset(ruleset_id); } return ret; @@ -269,14 +269,14 @@ void falco_engine::evttypes_for_ruleset(std::string &source, std::set { uint16_t ruleset_id = find_ruleset_id(ruleset); - auto it = m_rulesets.find(source); + auto it = find_ruleset(source); if(it == m_rulesets.end()) { string err = "Unknown event source " + source; throw falco_exception(err); } - it->second->evttypes_for_ruleset(evttypes, ruleset_id); + it->ruleset->evttypes_for_ruleset(evttypes, ruleset_id); } @@ -294,47 +294,51 @@ std::shared_ptr falco_engine::create_formatter(const std::s return it->second->create_formatter(output); } -unique_ptr falco_engine::process_event(std::string &source, gen_event *ev, uint16_t ruleset_id) +unique_ptr falco_engine::process_event(std::size_t source_idx, gen_event *ev, uint16_t ruleset_id) { if(should_drop_evt()) { return unique_ptr(); } - 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)) + try { - return unique_ptr(); - } + auto &r = m_rulesets.at(source_idx); + if(!r.ruleset->run(ev, ruleset_id)) + { + return unique_ptr(); + } - unique_ptr res(new rule_result()); - res->source = source; + unique_ptr res(new rule_result()); + res->source = r.source; - populate_rule_result(res, ev); + populate_rule_result(res, ev); - return res; + return res; + } + catch(std::out_of_range const &exc) + { + std::string err = "Unknown event source index " + std::to_string(source_idx); + throw falco_exception(err); + } } -unique_ptr falco_engine::process_event(std::string &source, gen_event *ev) +unique_ptr falco_engine::process_event(std::size_t source_idx, gen_event *ev) { - return process_event(source, ev, m_default_ruleset_id); + return process_event(source_idx, ev, m_default_ruleset_id); } -void falco_engine::add_source(const std::string &source, - std::shared_ptr filter_factory, - std::shared_ptr formatter_factory) +std::size_t falco_engine::add_source(const std::string &source, + std::shared_ptr filter_factory, + std::shared_ptr formatter_factory) { m_filter_factories[source] = filter_factory; m_format_factories[source] = formatter_factory; - std::shared_ptr ruleset(new falco_ruleset()); - m_rulesets[source] = ruleset; + auto idx = m_rulesets.size(); + m_rulesets.emplace_back(source, new falco_ruleset); + // here we just trust the caller they won't add the same source more than once + return idx; } void falco_engine::populate_rule_result(unique_ptr &res, gen_event *ev) @@ -418,19 +422,19 @@ void falco_engine::add_filter(std::shared_ptr filter, std::string &source, std::set &tags) { - auto it = m_rulesets.find(source); + auto it = find_ruleset(source); if(it == m_rulesets.end()) { string err = "Unknown event source " + source; throw falco_exception(err); } - it->second->add(source, rule, tags, filter); + it->ruleset->add(source, rule, tags, filter); } bool falco_engine::is_source_valid(const std::string &source) { - return (m_rulesets.find(source) != m_rulesets.end()); + return (find_ruleset(source) != m_rulesets.end()); } bool falco_engine::is_plugin_compatible(const std::string &name, @@ -465,12 +469,9 @@ bool falco_engine::is_plugin_compatible(const std::string &name, void falco_engine::clear_filters() { - m_rulesets.clear(); - - for(auto &it : m_filter_factories) + for(auto &it : m_rulesets) { - std::shared_ptr ruleset(new falco_ruleset()); - m_rulesets[it.first] = ruleset; + it.ruleset.reset(new falco_ruleset); } m_required_plugin_versions.clear(); @@ -507,3 +508,17 @@ inline bool falco_engine::should_drop_evt() double coin = (random() * (1.0/RAND_MAX)); return (coin >= (1.0/(m_sampling_multiplier * m_sampling_ratio))); } + +inline std::vector::iterator falco_engine::find_ruleset(const std::string &source) +{ + return std::find_if( + m_rulesets.begin(), m_rulesets.end(), + [&source](const ruleset_node &r) { return r.source == source; }); +} + +inline std::vector::const_iterator falco_engine::find_ruleset(const std::string &source) const +{ + return std::find_if( + m_rulesets.cbegin(), m_rulesets.cend(), + [&source](const ruleset_node &r) { return r.source == source; }); +} diff --git a/userspace/engine/falco_engine.h b/userspace/engine/falco_engine.h index b2d16d3d146..664be16d3af 100644 --- a/userspace/engine/falco_engine.h +++ b/userspace/engine/falco_engine.h @@ -163,20 +163,21 @@ class falco_engine : public falco_common // with a ruleset string. // // the returned rule_result is allocated and must be delete()d. - std::unique_ptr process_event(std::string &source, gen_event *ev, uint16_t ruleset_id); + std::unique_ptr process_event(std::size_t source_idx, gen_event *ev, uint16_t ruleset_id); // // Wrapper assuming the default ruleset // - std::unique_ptr process_event(std::string &source, gen_event *ev); + std::unique_ptr process_event(std::size_t source_idx, gen_event *ev); // // Configure the engine to support events with the provided // source, with the provided filter factory and formatter factory. + // Return source index for fast lookup. // - void add_source(const std::string &source, - std::shared_ptr filter_factory, - std::shared_ptr formatter_factory); + std::size_t add_source(const std::string &source, + std::shared_ptr filter_factory, + std::shared_ptr formatter_factory); // Return whether or not there is a valid filter/formatter // factory for this source. @@ -213,6 +214,14 @@ class falco_engine : public falco_common bool is_plugin_compatible(const std::string &name, const std::string &version, std::string &required_version); private: + struct ruleset_node + { + ruleset_node(const std::string &n, falco_ruleset *p): + source(n), ruleset(p) {} + + std::string source; + mutable std::shared_ptr ruleset; + }; // // Determine whether the given event should be matched at all @@ -221,6 +230,9 @@ class falco_engine : public falco_common // inline bool should_drop_evt(); + inline std::vector::iterator find_ruleset(const std::string &source); + inline std::vector::const_iterator find_ruleset(const std::string &source) const; + // Maps from event source to object that can generate filters from rules std::map> m_filter_factories; @@ -228,7 +240,7 @@ class falco_engine : public falco_common std::map> m_format_factories; // Maps from event source to the set of rules for that event source - std::map> m_rulesets; + std::vector m_rulesets; std::unique_ptr m_rules; uint16_t m_next_ruleset_id; diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index 8574356e37f..213d79ffffe 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -62,7 +62,9 @@ bool g_restart = false; bool g_daemonized = false; static std::string syscall_source = "syscall"; +static std::size_t syscall_source_idx; static std::string k8s_audit_source = "k8s_audit"; +static std::size_t k8s_audit_source_idx; // // Helper functions @@ -118,7 +120,7 @@ void read_k8s_audit_trace_file(falco_engine *engine, continue; } - if(!k8s_audit_handler::accept_data(engine, outputs, line, errstr)) + if(!k8s_audit_handler::accept_data(engine, outputs, k8s_audit_source_idx, line, errstr)) { falco_logger::log(LOG_ERR, "Could not read k8s audit event line #" + to_string(line_num) + ", \"" + line + "\": " + errstr + ", stopping"); return; @@ -140,16 +142,16 @@ static std::string read_file(std::string filename) // Event processing loop // uint64_t do_inspect(falco_engine *engine, - falco_outputs *outputs, - sinsp* inspector, - std::string &event_source, - falco_configuration &config, - syscall_evt_drop_mgr &sdropmgr, - uint64_t duration_to_tot_ns, - string &stats_filename, - uint64_t stats_interval, - bool all_events, - int &result) + falco_outputs *outputs, + sinsp *inspector, + std::size_t event_source_idx, + falco_configuration &config, + syscall_evt_drop_mgr &sdropmgr, + uint64_t duration_to_tot_ns, + string &stats_filename, + uint64_t stats_interval, + bool all_events, + int &result) { uint64_t num_evts = 0; int32_t rc; @@ -207,7 +209,7 @@ uint64_t do_inspect(falco_engine *engine, if(unlikely(ev == nullptr)) { timeouts_since_last_success_or_msg++; - if(event_source == syscall_source && + if(event_source_idx == syscall_source_idx && (timeouts_since_last_success_or_msg > config.m_syscall_evt_timeout_max_consecutives)) { std::string rule = "Falco internal: timeouts notification"; @@ -272,7 +274,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_event(event_source, ev); + unique_ptr res = engine->process_event(event_source_idx, ev); if(res) { outputs->handle_event(res->evt, res->rule, res->source, res->priority_num, res->format, res->tags); @@ -517,8 +519,8 @@ int falco_init(int argc, char **argv) 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)); - 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); + syscall_source_idx = engine->add_source(syscall_source, syscall_filter_factory, syscall_formatter_factory); + k8s_audit_source_idx = engine->add_source(k8s_audit_source, k8s_audit_filter_factory, k8s_audit_formatter_factory); for(const auto &src : app.options().disable_sources) { @@ -581,6 +583,7 @@ int falco_init(int argc, char **argv) // plugin was found, the source is the source of that // plugin. std::string event_source = syscall_source; + std::size_t event_source_idx = syscall_source_idx; // All filterchecks created by plugins go in this // list. If we ever support multiple event sources at @@ -628,7 +631,7 @@ int falco_init(int argc, char **argv) inspector->set_input_plugin_open_params(p.m_open_params.c_str()); } - engine->add_source(event_source, plugin_filter_factory, plugin_formatter_factory); + event_source_idx = engine->add_source(event_source, plugin_filter_factory, plugin_formatter_factory); } else { extractor_plugins.push_back(plugin); @@ -1151,7 +1154,7 @@ int falco_init(int argc, char **argv) { std::string ssl_option = (config.m_webserver_ssl_enabled ? " (SSL)" : ""); falco_logger::log(LOG_INFO, "Starting internal webserver, listening on port " + to_string(config.m_webserver_listen_port) + ssl_option + "\n"); - webserver.init(&config, engine, outputs); + webserver.init(&config, engine, outputs, k8s_audit_source_idx); webserver.start(); } @@ -1190,7 +1193,7 @@ int falco_init(int argc, char **argv) num_evts = do_inspect(engine, outputs, inspector, - event_source, + event_source_idx, config, sdropmgr, uint64_t(app.options().duration_to_tot*ONE_SECOND_IN_NS), diff --git a/userspace/falco/webserver.cpp b/userspace/falco/webserver.cpp index 927f2452901..0f78436476f 100644 --- a/userspace/falco/webserver.cpp +++ b/userspace/falco/webserver.cpp @@ -25,10 +25,8 @@ limitations under the License. using json = nlohmann::json; using namespace std; -string k8s_audit_handler::m_k8s_audit_event_source = "k8s_audit"; - -k8s_audit_handler::k8s_audit_handler(falco_engine *engine, falco_outputs *outputs): - m_engine(engine), m_outputs(outputs) +k8s_audit_handler::k8s_audit_handler(falco_engine *engine, falco_outputs *outputs, std::size_t k8s_audit_event_source_idx): + m_engine(engine), m_outputs(outputs), m_k8s_audit_event_source_idx(k8s_audit_event_source_idx) { } @@ -47,6 +45,7 @@ bool k8s_healthz_handler::handleGet(CivetServer *server, struct mg_connection *c bool k8s_audit_handler::accept_data(falco_engine *engine, falco_outputs *outputs, + std::size_t k8s_audit_event_source_idx, std::string &data, std::string &errstr) { @@ -89,7 +88,7 @@ bool k8s_audit_handler::accept_data(falco_engine *engine, try { - res = engine->process_event(m_k8s_audit_event_source, &jev); + res = engine->process_event(k8s_audit_event_source_idx, &jev); } catch(...) { @@ -120,7 +119,7 @@ bool k8s_audit_handler::accept_data(falco_engine *engine, bool k8s_audit_handler::accept_uploaded_data(std::string &post_data, std::string &errstr) { - return k8s_audit_handler::accept_data(m_engine, m_outputs, post_data, errstr); + return k8s_audit_handler::accept_data(m_engine, m_outputs, m_k8s_audit_event_source_idx, post_data, errstr); } bool k8s_audit_handler::handleGet(CivetServer *server, struct mg_connection *conn) @@ -189,11 +188,13 @@ falco_webserver::~falco_webserver() void falco_webserver::init(falco_configuration *config, falco_engine *engine, - falco_outputs *outputs) + falco_outputs *outputs, + std::size_t k8s_audit_event_source_idx) { m_config = config; m_engine = engine; m_outputs = outputs; + m_k8s_audit_event_source_idx = k8s_audit_event_source_idx; } template @@ -253,7 +254,7 @@ void falco_webserver::start() throw falco_exception("Could not create embedded webserver"); } - m_k8s_audit_handler = make_unique(m_engine, m_outputs); + m_k8s_audit_handler = make_unique(m_engine, m_outputs, m_k8s_audit_event_source_idx); m_server->addHandler(m_config->m_webserver_k8s_audit_endpoint, *m_k8s_audit_handler); m_k8s_healthz_handler = make_unique(); m_server->addHandler(m_config->m_webserver_k8s_healthz_endpoint, *m_k8s_healthz_handler); diff --git a/userspace/falco/webserver.h b/userspace/falco/webserver.h index c7310cb7917..2144d16e4ed 100644 --- a/userspace/falco/webserver.h +++ b/userspace/falco/webserver.h @@ -25,7 +25,7 @@ limitations under the License. class k8s_audit_handler : public CivetHandler { public: - k8s_audit_handler(falco_engine *engine, falco_outputs *outputs); + k8s_audit_handler(falco_engine *engine, falco_outputs *outputs, std::size_t k8s_audit_event_source_idx); virtual ~k8s_audit_handler(); bool handleGet(CivetServer *server, struct mg_connection *conn); @@ -33,13 +33,13 @@ class k8s_audit_handler : public CivetHandler static bool accept_data(falco_engine *engine, falco_outputs *outputs, + std::size_t k8s_audit_event_source_idx, std::string &post_data, std::string &errstr); - static std::string m_k8s_audit_event_source; - private: falco_engine *m_engine; falco_outputs *m_outputs; + std::size_t m_k8s_audit_event_source_idx; bool accept_uploaded_data(std::string &post_data, std::string &errstr); }; @@ -65,7 +65,8 @@ class falco_webserver void init(falco_configuration *config, falco_engine *engine, - falco_outputs *outputs); + falco_outputs *outputs, + std::size_t k8s_audit_event_source_idx); void start(); void stop(); @@ -74,6 +75,7 @@ class falco_webserver falco_engine *m_engine; falco_configuration *m_config; falco_outputs *m_outputs; + std::size_t m_k8s_audit_event_source_idx; unique_ptr m_server; unique_ptr m_k8s_audit_handler; unique_ptr m_k8s_healthz_handler;