From 228e965f1bfa374c3e0e165d7225ad061af11c8c Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Thu, 13 Jun 2024 15:04:30 -0700 Subject: [PATCH 1/2] Add an indexable ruleset that can split filters by ruleset/evttype Now that custom rules loading implementations (and related, custom rulesets) can be swapped into falco in a customizable way, there is some functionality in evttype_index_ruleset that could be used by other rulesets, specifically the part that segregates filters by ruleset and enables/disables filters based on name substring + tags. To allow for this, create a new template indexable_ruleset which derives from filter_ruleset and segregates the filter_wrappers by ruleset. It also optionally segregates filter_wrappers by event type. The filter_wrapper class is an object that can return a name, tags, and sc/event codes. The main interfaces for classes that derive from indexable_ruleset are: - add_wrapper(), which provides a filter_wrapper to the indexable_ruleset. This is generally called from add()/add_compile_output(), which must be implemented by the derived class. - run_wrappers(), which must be implemented by the derived class and is called for event processing. Most of the methods required by filter_ruleset are implemented by indexable_ruleset and do not need to be implemented by the derived class. Signed-off-by: Mark Stemm --- userspace/engine/indexable_ruleset.h | 454 +++++++++++++++++++++++++++ 1 file changed, 454 insertions(+) create mode 100644 userspace/engine/indexable_ruleset.h diff --git a/userspace/engine/indexable_ruleset.h b/userspace/engine/indexable_ruleset.h new file mode 100644 index 00000000000..debfe15787b --- /dev/null +++ b/userspace/engine/indexable_ruleset.h @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2024 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* This describes the interface for an "indexable" ruleset, that is, a + * ruleset that can enable/disable abstract filters for various + * ruleset ids. + * + * It's used by evttype_index_ruleset as well as other rulesets that + * need the same functionality but don't want to copy the same code. + */ + +#pragma once + +#include "falco_utils.h" +#include "filter_ruleset.h" + +#include +#include +#include + +#include +#include +#include + +// A filter_wrapper should implement these methods: +// const std::string &filter_wrapper::name(); +// const std::set &filter_wrapper::tags(); +// const libsinsp::events::set &filter_wrapper::sc_codes(); +// const libsinsp::events::set &filter_wrapper::event_codes(); + +template +class indexable_ruleset : public filter_ruleset +{ +public: + indexable_ruleset() = default; + virtual ~indexable_ruleset() = default; + + // Required to implement filter_ruleset + void clear() override + { + for(size_t i = 0; i < m_rulesets.size(); i++) + { + m_rulesets[i] = std::make_shared(i); + } + m_filters.clear(); + } + + uint64_t enabled_count(uint16_t ruleset_id) override + { + while(m_rulesets.size() < (size_t)ruleset_id + 1) + { + m_rulesets.emplace_back(std::make_shared(m_rulesets.size())); + } + + return m_rulesets[ruleset_id]->num_filters(); + } + + void enabled_evttypes( + std::set &evttypes, + uint16_t ruleset_id) override + { + evttypes.clear(); + for(const auto &e : enabled_event_codes(ruleset_id)) + { + evttypes.insert((uint16_t)e); + } + } + + libsinsp::events::set enabled_sc_codes( + uint16_t ruleset_id) override + { + if(m_rulesets.size() < (size_t)ruleset_id + 1) + { + return {}; + } + return m_rulesets[ruleset_id]->sc_codes(); + } + + libsinsp::events::set enabled_event_codes( + uint16_t ruleset_id) override + { + if(m_rulesets.size() < (size_t)ruleset_id + 1) + { + return {}; + } + return m_rulesets[ruleset_id]->event_codes(); + } + + void enable( + const std::string &pattern, + match_type match, + uint16_t ruleset_id) override + { + enable_disable(pattern, match, true, ruleset_id); + } + + void disable( + const std::string &pattern, + match_type match, + uint16_t ruleset_id) override + { + enable_disable(pattern, match, false, ruleset_id); + } + + void enable_tags( + const std::set &tags, + uint16_t ruleset_id) override + { + enable_disable_tags(tags, true, ruleset_id); + } + + void disable_tags( + const std::set &tags, + uint16_t ruleset_id) override + { + enable_disable_tags(tags, false, ruleset_id); + } + + // Note that subclasses do *not* implement run. Instead, they + // implement run_wrappers. + bool run(sinsp_evt *evt, falco_rule &match, uint16_t ruleset_id) override + { + if(m_rulesets.size() < (size_t)ruleset_id + 1) + { + return false; + } + + return m_rulesets[ruleset_id]->run(*this, evt, match); + } + + bool run(sinsp_evt *evt, std::vector &matches, uint16_t ruleset_id) override + { + if(m_rulesets.size() < (size_t)ruleset_id + 1) + { + return false; + } + + return m_rulesets[ruleset_id]->run(*this, evt, matches); + } + + typedef std::list> + filter_wrapper_list; + + // Subclasses should call add_wrapper (most likely from + // filter_ruleset::add or ::add_compile_output) to add filters. + void add_wrapper(std::shared_ptr wrap) + { + m_filters.insert(wrap); + } + + // If a subclass needs to iterate over all filters, they can + // call iterate with this function, which will be called for + // all filters. + typedef std::function &wrap)> filter_wrapper_func; + uint64_t iterate(filter_wrapper_func func) + { + uint64_t num_filters = 0; + + for(const auto &ruleset_ptr : m_rulesets) + { + if(ruleset_ptr) + { + for(const auto &wrap : ruleset_ptr->get_filters()) + { + num_filters++; + func(wrap); + } + } + } + + return num_filters; + } + + // A subclass must implement these methods. They are analogous + // to run() but take care of selecting filters that match a + // ruleset and possibly an event type. + virtual bool run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, std::vector &matches) = 0; + virtual bool run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, falco_rule &match) = 0; + +private: + // Helper used by enable()/disable() + void enable_disable( + const std::string &pattern, + match_type match, + bool enabled, + uint16_t ruleset_id) + { + while(m_rulesets.size() < (size_t)ruleset_id + 1) + { + m_rulesets.emplace_back(std::make_shared(m_rulesets.size())); + } + + for(const auto &wrap : m_filters) + { + bool matches; + std::string::size_type pos; + + switch(match) + { + case match_type::exact: + pos = wrap->name().find(pattern); + + matches = (pattern == "" || (pos == 0 && + pattern.size() == wrap->name().size())); + break; + case match_type::substring: + matches = (pattern == "" || (wrap->name().find(pattern) != std::string::npos)); + break; + case match_type::wildcard: + matches = falco::utils::matches_wildcard(pattern, wrap->name()); + break; + default: + // should never happen + matches = false; + } + + if(matches) + { + if(enabled) + { + m_rulesets[ruleset_id]->add_filter(wrap); + } + else + { + m_rulesets[ruleset_id]->remove_filter(wrap); + } + } + } + } + + // Helper used by enable_tags()/disable_tags() + void enable_disable_tags( + const std::set &tags, + bool enabled, + uint16_t ruleset_id) + { + while(m_rulesets.size() < (size_t)ruleset_id + 1) + { + m_rulesets.emplace_back(std::make_shared(m_rulesets.size())); + } + + for(const auto &wrap : m_filters) + { + std::set intersect; + + set_intersection(tags.begin(), tags.end(), + wrap->tags().begin(), wrap->tags().end(), + inserter(intersect, intersect.begin())); + + if(!intersect.empty()) + { + if(enabled) + { + m_rulesets[ruleset_id]->add_filter(wrap); + } + else + { + m_rulesets[ruleset_id]->remove_filter(wrap); + } + } + } + } + + // A group of filters all having the same ruleset + class ruleset_filters + { + public: + ruleset_filters(uint16_t ruleset_id): + m_ruleset_id(ruleset_id) {} + + virtual ~ruleset_filters(){}; + + void add_filter(std::shared_ptr wrap) + { + if(wrap->event_codes().empty()) + { + // Should run for all event types + add_wrapper_to_list(m_filter_all_event_types, wrap); + } + else + { + for(auto &etype : wrap->event_codes()) + { + if(m_filter_by_event_type.size() <= etype) + { + m_filter_by_event_type.resize(etype + 1); + } + + add_wrapper_to_list(m_filter_by_event_type[etype], wrap); + } + } + + m_filters.insert(wrap); + } + + void remove_filter(std::shared_ptr wrap) + { + if(wrap->event_codes().empty()) + { + remove_wrapper_from_list(m_filter_all_event_types, wrap); + } + else + { + for(auto &etype : wrap->event_codes()) + { + if(etype < m_filter_by_event_type.size()) + { + remove_wrapper_from_list(m_filter_by_event_type[etype], wrap); + } + } + } + + m_filters.erase(wrap); + } + + uint64_t num_filters() + { + return m_filters.size(); + } + + inline const std::set> &get_filters() const + { + return m_filters; + } + + // Evaluate an event against the ruleset and return the first rule + // that matched. + bool run(indexable_ruleset &ruleset, sinsp_evt *evt, falco_rule &match) + { + if(evt->get_type() < m_filter_by_event_type.size() && + m_filter_by_event_type[evt->get_type()].size() > 0) + { + if(ruleset.run_wrappers(evt, m_filter_by_event_type[evt->get_type()], m_ruleset_id, match)) + { + return true; + } + } + + // Finally, try filters that are not specific to an event type. + if(m_filter_all_event_types.size() > 0) + { + if(ruleset.run_wrappers(evt, m_filter_all_event_types, m_ruleset_id, match)) + { + return true; + } + } + + return false; + } + + // Evaluate an event against the ruleset and return all the + // matching rules. + bool run(indexable_ruleset &ruleset, sinsp_evt *evt, std::vector &matches) + { + if(evt->get_type() < m_filter_by_event_type.size() && + m_filter_by_event_type[evt->get_type()].size() > 0) + { + if(ruleset.run_wrappers(evt, m_filter_by_event_type[evt->get_type()], m_ruleset_id, matches)) + { + return true; + } + } + + // Finally, try filters that are not specific to an event type. + if(m_filter_all_event_types.size() > 0) + { + if(ruleset.run_wrappers(evt, m_filter_all_event_types, m_ruleset_id, matches)) + { + return true; + } + } + + return false; + } + + libsinsp::events::set sc_codes() + { + libsinsp::events::set res; + for(const auto &wrap : m_filters) + { + res.insert(wrap->sc_codes().begin(), wrap->sc_codes().end()); + } + return res; + } + libsinsp::events::set event_codes() + { + libsinsp::events::set res; + for(const auto &wrap : m_filters) + { + res.insert(wrap->event_codes().begin(), wrap->event_codes().end()); + } + return res; + } + + private: + void add_wrapper_to_list(filter_wrapper_list &wrappers, std::shared_ptr wrap) + { + // This is O(n) but it's also uncommon + // (when loading rules only). + auto pos = std::find(wrappers.begin(), + wrappers.end(), + wrap); + + if(pos == wrappers.end()) + { + wrappers.push_back(wrap); + } + } + + void remove_wrapper_from_list(filter_wrapper_list &wrappers, std::shared_ptr wrap) + { + // This is O(n) but it's also uncommon + // (when loading rules only). + auto pos = std::find(wrappers.begin(), + wrappers.end(), + wrap); + if(pos != wrappers.end()) + { + wrappers.erase(pos); + } + } + uint16_t m_ruleset_id; + + // Vector indexes from event type to a set of filters. There can + // be multiple filters for a given event type. + // NOTE: This is used only when the event sub-type is 0. + std::vector m_filter_by_event_type; + + filter_wrapper_list m_filter_all_event_types; + + // All filters added. Used to make num_filters() fast. + std::set> m_filters; + }; + + // Vector indexes from ruleset id to set of rules. + std::vector> m_rulesets; + + // All filters added. The set of enabled filters is held in m_rulesets + std::set> m_filters; +}; From d8a8a59011c9538a2a11c2231db687c8e3b2178f Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Thu, 13 Jun 2024 15:22:16 -0700 Subject: [PATCH 2/2] Modify evttype_index_ruleset to derive from indexable_ruleset Modify evttype_index_ruleset to derive from indexable_ruleset instead of having its own implementation of segregating filters by ruleset id/event type. An evttype_index_wrapper contains a falco rule and filter, and implements the methods required by the template. run_wrappers() evaluate the filter as before, without the segregation by ruleset id/event type. Signed-off-by: Mark Stemm --- userspace/engine/evttype_index_ruleset.cpp | 362 ++------------------- userspace/engine/evttype_index_ruleset.h | 141 ++------ 2 files changed, 54 insertions(+), 449 deletions(-) diff --git a/userspace/engine/evttype_index_ruleset.cpp b/userspace/engine/evttype_index_ruleset.cpp index 47e1891cd07..c6386c6ed31 100644 --- a/userspace/engine/evttype_index_ruleset.cpp +++ b/userspace/engine/evttype_index_ruleset.cpp @@ -17,14 +17,13 @@ limitations under the License. #include "evttype_index_ruleset.h" -#include "falco_utils.h" - #include "logger.h" #include evttype_index_ruleset::evttype_index_ruleset( - std::shared_ptr f): m_filter_factory(f) + std::shared_ptr f): + m_filter_factory(f) { } @@ -32,170 +31,6 @@ evttype_index_ruleset::~evttype_index_ruleset() { } -evttype_index_ruleset::ruleset_filters::ruleset_filters() -{ -} - -evttype_index_ruleset::ruleset_filters::~ruleset_filters() -{ -} - -void evttype_index_ruleset::ruleset_filters::add_wrapper_to_list(filter_wrapper_list &wrappers, std::shared_ptr wrap) -{ - // This is O(n) but it's also uncommon - // (when loading rules only). - auto pos = std::find(wrappers.begin(), - wrappers.end(), - wrap); - - if(pos == wrappers.end()) - { - wrappers.push_back(wrap); - } -} - -void evttype_index_ruleset::ruleset_filters::remove_wrapper_from_list(filter_wrapper_list &wrappers, std::shared_ptr wrap) -{ - // This is O(n) but it's also uncommon - // (when loading rules only). - auto pos = std::find(wrappers.begin(), - wrappers.end(), - wrap); - if(pos != wrappers.end()) - { - wrappers.erase(pos); - } -} - -void evttype_index_ruleset::ruleset_filters::add_filter(std::shared_ptr wrap) -{ - if(wrap->event_codes.empty()) - { - // Should run for all event types - add_wrapper_to_list(m_filter_all_event_types, wrap); - } - else - { - for(auto &etype : wrap->event_codes) - { - if(m_filter_by_event_type.size() <= etype) - { - m_filter_by_event_type.resize(etype + 1); - } - - add_wrapper_to_list(m_filter_by_event_type[etype], wrap); - } - } - - m_filters.insert(wrap); -} - -void evttype_index_ruleset::ruleset_filters::remove_filter(std::shared_ptr wrap) -{ - if(wrap->event_codes.empty()) - { - remove_wrapper_from_list(m_filter_all_event_types, wrap); - } - else - { - for(auto &etype : wrap->event_codes) - { - if( etype < m_filter_by_event_type.size() ) - { - remove_wrapper_from_list(m_filter_by_event_type[etype], wrap); - } - } - } - - m_filters.erase(wrap); -} - -uint64_t evttype_index_ruleset::ruleset_filters::num_filters() -{ - return m_filters.size(); -} - -bool evttype_index_ruleset::ruleset_filters::run(sinsp_evt *evt, falco_rule& match) -{ - if(evt->get_type() < m_filter_by_event_type.size()) - { - for(const auto &wrap : m_filter_by_event_type[evt->get_type()]) - { - if(wrap->filter->run(evt)) - { - match = wrap->rule; - return true; - } - } - } - - // Finally, try filters that are not specific to an event type. - for(const auto &wrap : m_filter_all_event_types) - { - if(wrap->filter->run(evt)) - { - match = wrap->rule; - return true; - } - } - - return false; -} - -bool evttype_index_ruleset::ruleset_filters::run(sinsp_evt *evt, std::vector& matches) -{ - bool match_found = false; - - if(evt->get_type() < m_filter_by_event_type.size()) - { - for(const auto &wrap : m_filter_by_event_type[evt->get_type()]) - { - if(wrap->filter->run(evt)) - { - matches.push_back(wrap->rule); - match_found = true; - } - } - } - - if(match_found) - { - return true; - } - - // Finally, try filters that are not specific to an event type. - for(const auto &wrap : m_filter_all_event_types) - { - if(wrap->filter->run(evt)) - { - matches.push_back(wrap->rule); - match_found = true; - } - } - - return match_found; -} - -libsinsp::events::set evttype_index_ruleset::ruleset_filters::sc_codes() -{ - libsinsp::events::set res; - for(const auto &wrap : m_filters) - { - res.insert(wrap->sc_codes.begin(), wrap->sc_codes.end()); - } - return res; -} - -libsinsp::events::set evttype_index_ruleset::ruleset_filters::event_codes() -{ - libsinsp::events::set res; - for(const auto &wrap : m_filters) - { - res.insert(wrap->event_codes.begin(), wrap->event_codes.end()); - } - return res; -} - void evttype_index_ruleset::add( const falco_rule& rule, std::shared_ptr filter, @@ -203,21 +38,22 @@ void evttype_index_ruleset::add( { try { - auto wrap = std::make_shared(); - wrap->rule = rule; - wrap->filter = filter; + auto wrap = std::make_shared(); + wrap->m_rule = rule; + wrap->m_filter = filter; if(rule.source == falco_common::syscall_source) { - wrap->sc_codes = libsinsp::filter::ast::ppm_sc_codes(condition.get()); - wrap->event_codes = libsinsp::filter::ast::ppm_event_codes(condition.get()); + wrap->m_sc_codes = libsinsp::filter::ast::ppm_sc_codes(condition.get()); + wrap->m_event_codes = libsinsp::filter::ast::ppm_event_codes(condition.get()); } else { - wrap->sc_codes = { }; - wrap->event_codes = { ppm_event_code::PPME_PLUGINEVENT_E }; + wrap->m_sc_codes = {}; + wrap->m_event_codes = {ppm_event_code::PPME_PLUGINEVENT_E}; } - wrap->event_codes.insert(ppm_event_code::PPME_ASYNCEVENT_E); - m_filters.insert(wrap); + wrap->m_event_codes.insert(ppm_event_code::PPME_ASYNCEVENT_E); + + add_wrapper(wrap); } catch (const sinsp_exception& e) { @@ -230,180 +66,46 @@ void evttype_index_ruleset::on_loading_complete() print_enabled_rules_falco_logger(); } -void evttype_index_ruleset::print_enabled_rules_falco_logger() -{ - falco_logger::log(falco_logger::level::DEBUG, "Enabled rules:\n"); - int n = 0; - for (const auto& ruleset_ptr : m_rulesets) - { - if (ruleset_ptr) - { - for (const auto& wrap : ruleset_ptr->get_filters()) - { - n++; - falco_logger::log(falco_logger::level::DEBUG, std::string(" ") + wrap->rule.name + "\n"); - } - } - } - falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(n) + ") enabled rules in total\n"); -} - -void evttype_index_ruleset::clear() -{ - for (size_t i = 0; i < m_rulesets.size(); i++) - { - m_rulesets[i] = std::make_shared(); - } - m_filters.clear(); -} - -void evttype_index_ruleset::enable(const std::string &pattern, match_type match, uint16_t ruleset_id) -{ - enable_disable(pattern, match, true, ruleset_id); -} - -void evttype_index_ruleset::disable(const std::string &pattern, match_type match, uint16_t ruleset_id) +bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, falco_rule &match) { - enable_disable(pattern, match, false, ruleset_id); -} - -void evttype_index_ruleset::enable_disable(const std::string &pattern, match_type match, bool enabled, uint16_t ruleset_id) -{ - while(m_rulesets.size() < (size_t)ruleset_id + 1) + for(auto &wrap : wrappers) { - m_rulesets.emplace_back(std::make_shared()); - } - - for(const auto &wrap : m_filters) - { - bool matches; - std::string::size_type pos; - - switch(match) + if(wrap->m_filter->run(evt)) { - case match_type::exact: - pos = wrap->rule.name.find(pattern); - - matches = (pattern == "" || (pos == 0 && - pattern.size() == wrap->rule.name.size())); - break; - case match_type::substring: - matches = (pattern == "" || (wrap->rule.name.find(pattern) != std::string::npos)); - break; - case match_type::wildcard: - matches = falco::utils::matches_wildcard(pattern, wrap->rule.name); - break; - default: - // should never happen - matches = false; - } - - if(matches) - { - if(enabled) - { - m_rulesets[ruleset_id]->add_filter(wrap); - } - else - { - m_rulesets[ruleset_id]->remove_filter(wrap); - } + match = wrap->m_rule; + return true; } } -} - -void evttype_index_ruleset::enable_tags(const std::set &tags, uint16_t ruleset_id) -{ - enable_disable_tags(tags, true, ruleset_id); -} -void evttype_index_ruleset::disable_tags(const std::set &tags, uint16_t ruleset_id) -{ - enable_disable_tags(tags, false, ruleset_id); + return false; } -void evttype_index_ruleset::enable_disable_tags(const std::set &tags, bool enabled, uint16_t ruleset_id) +bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, std::vector &matches) { - while(m_rulesets.size() < (size_t)ruleset_id + 1) - { - m_rulesets.emplace_back(std::make_shared()); - } + bool match_found = false; - for(const auto &wrap : m_filters) + for(auto &wrap : wrappers) { - std::set intersect; - - set_intersection(tags.begin(), tags.end(), - wrap->rule.tags.begin(), wrap->rule.tags.end(), - inserter(intersect, intersect.begin())); - - if(!intersect.empty()) + if(wrap->m_filter->run(evt)) { - if(enabled) - { - m_rulesets[ruleset_id]->add_filter(wrap); - } - else - { - m_rulesets[ruleset_id]->remove_filter(wrap); - } + matches.push_back(wrap->m_rule); + match_found = true; } } -} - -uint64_t evttype_index_ruleset::enabled_count(uint16_t ruleset_id) -{ - while(m_rulesets.size() < (size_t)ruleset_id + 1) - { - m_rulesets.emplace_back(std::make_shared()); - } - - return m_rulesets[ruleset_id]->num_filters(); -} - -bool evttype_index_ruleset::run(sinsp_evt *evt, falco_rule& match, uint16_t ruleset_id) -{ - if(m_rulesets.size() < (size_t)ruleset_id + 1) - { - return false; - } - return m_rulesets[ruleset_id]->run(evt, match); + return match_found; } -bool evttype_index_ruleset::run(sinsp_evt *evt, std::vector& matches, uint16_t ruleset_id) +void evttype_index_ruleset::print_enabled_rules_falco_logger() { - if(m_rulesets.size() < (size_t)ruleset_id + 1) - { - return false; - } - - return m_rulesets[ruleset_id]->run(evt, matches); -} + falco_logger::log(falco_logger::level::DEBUG, "Enabled rules:\n"); -void evttype_index_ruleset::enabled_evttypes(std::set &evttypes, uint16_t ruleset_id) -{ - evttypes.clear(); - for (const auto& e : enabled_event_codes(ruleset_id)) + auto logger = [](std::shared_ptr wrap) { - evttypes.insert((uint16_t) e); - } -} + falco_logger::log(falco_logger::level::DEBUG, std::string(" ") + wrap->name() + "\n"); + }; -libsinsp::events::set evttype_index_ruleset::enabled_sc_codes(uint16_t ruleset) -{ - if(m_rulesets.size() < (size_t)ruleset + 1) - { - return {}; - } - return m_rulesets[ruleset]->sc_codes(); -} + uint64_t num_filters = iterate(logger); -libsinsp::events::set evttype_index_ruleset::enabled_event_codes(uint16_t ruleset) -{ - if(m_rulesets.size() < (size_t)ruleset + 1) - { - return {}; - } - return m_rulesets[ruleset]->event_codes(); + falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(num_filters) + ") enabled rules in total\n"); } diff --git a/userspace/engine/evttype_index_ruleset.h b/userspace/engine/evttype_index_ruleset.h index 01ac4e3000c..b721dd6427d 100644 --- a/userspace/engine/evttype_index_ruleset.h +++ b/userspace/engine/evttype_index_ruleset.h @@ -17,151 +17,54 @@ limitations under the License. #pragma once +#include "indexable_ruleset.h" + #include #include #include -#include -#include - -#include "filter_ruleset.h" -#include -#include -#include /*! \brief A filter_ruleset that indexes enabled rules by event type, and performs linear search on each event type bucket */ -class evttype_index_ruleset: public filter_ruleset + +struct evttype_index_wrapper +{ + const std::string &name() { return m_rule.name; } + const std::set &tags() { return m_rule.tags; } + const libsinsp::events::set &sc_codes() { return m_sc_codes; } + const libsinsp::events::set &event_codes() { return m_event_codes; } + + falco_rule m_rule; + libsinsp::events::set m_sc_codes; + libsinsp::events::set m_event_codes; + std::shared_ptr m_filter; +}; + +class evttype_index_ruleset : public indexable_ruleset { public: explicit evttype_index_ruleset(std::shared_ptr factory); virtual ~evttype_index_ruleset(); + // From filter_ruleset void add( const falco_rule& rule, std::shared_ptr filter, std::shared_ptr condition) override; - void clear() override; - - bool run(sinsp_evt *evt, falco_rule& match, uint16_t ruleset_id) override; - bool run(sinsp_evt *evt, std::vector&matches, uint16_t ruleset_id) override; - - uint64_t enabled_count(uint16_t ruleset_id) override; - void on_loading_complete() override; + // From indexable_ruleset + bool run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, falco_rule &match) override; + bool run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, std::vector &matches) override; + // Print each enabled rule when running Falco with falco logger // log_level=debug; invoked within on_loading_complete() void print_enabled_rules_falco_logger(); - void enable( - const std::string &pattern, - match_type match, - uint16_t rulset_id) override; - - void disable( - const std::string &pattern, - match_type match, - uint16_t rulset_id) override; - - void enable_tags( - const std::set &tags, - uint16_t rulset_id) override; - - void disable_tags( - const std::set &tags, - uint16_t rulset_id) override; - - // note(jasondellaluce): this is deprecated, must use the new - // typing-improved `enabled_event_codes` and `enabled_sc_codes` instead - // todo(jasondellaluce): remove this in future code refactors - void enabled_evttypes( - std::set &evttypes, - uint16_t ruleset) override; - - libsinsp::events::set enabled_sc_codes(uint16_t ruleset) override; - - libsinsp::events::set enabled_event_codes(uint16_t ruleset) override; - private: - - // Helper used by enable()/disable() - void enable_disable( - const std::string &pattern, - match_type match, - bool enabled, - uint16_t rulset_id); - - // Helper used by enable_tags()/disable_tags() - void enable_disable_tags( - const std::set &tags, - bool enabled, - uint16_t rulset_id); - - struct filter_wrapper - { - falco_rule rule; - libsinsp::events::set sc_codes; - libsinsp::events::set event_codes; - std::shared_ptr filter; - }; - - typedef std::list> filter_wrapper_list; - - // A group of filters all having the same ruleset - class ruleset_filters { - public: - ruleset_filters(); - - virtual ~ruleset_filters(); - - void add_filter(std::shared_ptr wrap); - void remove_filter(std::shared_ptr wrap); - - uint64_t num_filters(); - - inline const std::set>& get_filters() const - { - return m_filters; - } - - // Evaluate an event against the ruleset and return the first rule - // that matched. - bool run(sinsp_evt *evt, falco_rule& match); - - // Evaluate an event against the ruleset and return all the - // matching rules. - bool run(sinsp_evt *evt, std::vector& matches); - - libsinsp::events::set sc_codes(); - - libsinsp::events::set event_codes(); - - private: - void add_wrapper_to_list(filter_wrapper_list &wrappers, std::shared_ptr wrap); - void remove_wrapper_from_list(filter_wrapper_list &wrappers, std::shared_ptr wrap); - - // Vector indexes from event type to a set of filters. There can - // be multiple filters for a given event type. - // NOTE: This is used only when the event sub-type is 0. - std::vector m_filter_by_event_type; - - filter_wrapper_list m_filter_all_event_types; - - // All filters added. Used to make num_filters() fast. - std::set> m_filters; - }; - - // Vector indexes from ruleset id to set of rules. - std::vector> m_rulesets; - - // All filters added. The set of enabled filters is held in m_rulesets - std::set> m_filters; - std::shared_ptr m_filter_factory; - std::vector m_ruleset_names; }; class evttype_index_ruleset_factory: public filter_ruleset_factory