diff --git a/userspace/engine/CMakeLists.txt b/userspace/engine/CMakeLists.txt index 89202e52..d08f83dd 100644 --- a/userspace/engine/CMakeLists.txt +++ b/userspace/engine/CMakeLists.txt @@ -15,7 +15,7 @@ set(FALCO_ENGINE_SOURCE_FILES falco_engine.cpp falco_utils.cpp json_evt.cpp - ruleset.cpp + evttype_index_ruleset.cpp formats.cpp filter_macro_resolver.cpp filter_evttype_resolver.cpp diff --git a/userspace/engine/ruleset.cpp b/userspace/engine/evttype_index_ruleset.cpp similarity index 55% rename from userspace/engine/ruleset.cpp rename to userspace/engine/evttype_index_ruleset.cpp index 00b8838b..04aef217 100644 --- a/userspace/engine/ruleset.cpp +++ b/userspace/engine/evttype_index_ruleset.cpp @@ -14,30 +14,32 @@ See the License for the specific language governing permissions and limitations under the License. */ -#include "ruleset.h" +#include "evttype_index_ruleset.h" +#include "filter_evttype_resolver.h" #include "banned.h" // This raises a compilation error when certain functions are used #include using namespace std; -falco_ruleset::falco_ruleset() +evttype_index_ruleset::evttype_index_ruleset( + std::shared_ptr f): m_filter_factory(f) { } -falco_ruleset::~falco_ruleset() +evttype_index_ruleset::~evttype_index_ruleset() { } -falco_ruleset::ruleset_filters::ruleset_filters() +evttype_index_ruleset::ruleset_filters::ruleset_filters() { } -falco_ruleset::ruleset_filters::~ruleset_filters() +evttype_index_ruleset::ruleset_filters::~ruleset_filters() { } -void falco_ruleset::ruleset_filters::add_wrapper_to_list(filter_wrapper_list &wrappers, std::shared_ptr wrap) +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). @@ -51,7 +53,7 @@ void falco_ruleset::ruleset_filters::add_wrapper_to_list(filter_wrapper_list &wr } } -void falco_ruleset::ruleset_filters::remove_wrapper_from_list(filter_wrapper_list &wrappers, std::shared_ptr 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). @@ -64,7 +66,7 @@ void falco_ruleset::ruleset_filters::remove_wrapper_from_list(filter_wrapper_lis } } -void falco_ruleset::ruleset_filters::add_filter(std::shared_ptr wrap) +void evttype_index_ruleset::ruleset_filters::add_filter(std::shared_ptr wrap) { if(wrap->evttypes.empty()) { @@ -87,7 +89,7 @@ void falco_ruleset::ruleset_filters::add_filter(std::shared_ptr m_filters.insert(wrap); } -void falco_ruleset::ruleset_filters::remove_filter(std::shared_ptr wrap) +void evttype_index_ruleset::ruleset_filters::remove_filter(std::shared_ptr wrap) { if(wrap->evttypes.empty()) { @@ -107,12 +109,12 @@ void falco_ruleset::ruleset_filters::remove_filter(std::shared_ptrget_type() < m_filter_by_event_type.size()) { @@ -120,6 +122,7 @@ bool falco_ruleset::ruleset_filters::run(gen_event *evt) { if(wrap->filter->run(evt)) { + match = wrap->rule; return true; } } @@ -130,6 +133,7 @@ bool falco_ruleset::ruleset_filters::run(gen_event *evt) { if(wrap->filter->run(evt)) { + match = wrap->rule; return true; } } @@ -137,7 +141,7 @@ bool falco_ruleset::ruleset_filters::run(gen_event *evt) return false; } -void falco_ruleset::ruleset_filters::evttypes_for_ruleset(std::set &evttypes) +void evttype_index_ruleset::ruleset_filters::evttypes_for_ruleset(std::set &evttypes) { evttypes.clear(); @@ -147,23 +151,54 @@ void falco_ruleset::ruleset_filters::evttypes_for_ruleset(std::set &ev } } -void falco_ruleset::add(string &source, - string &name, - set &tags, - set &evttypes, - std::shared_ptr filter) +void evttype_index_ruleset::add( + const falco_rule& rule, + std::shared_ptr condition) { - std::shared_ptr wrap(new filter_wrapper()); - wrap->source = source; - wrap->name = name; - wrap->tags = tags; - wrap->filter = filter; - wrap->evttypes = evttypes; - - m_filters.insert(wrap); + try + { + sinsp_filter_compiler compiler(m_filter_factory, condition.get()); + shared_ptr filter(compiler.compile()); + std::shared_ptr wrap(new filter_wrapper()); + filter_evttype_resolver resolver; + wrap->rule = rule; + wrap->filter = filter; + resolver.evttypes(condition, wrap->evttypes); + m_filters.insert(wrap); + } + catch (const sinsp_exception& e) + { + throw falco_exception(string(e.what())); + } } -void falco_ruleset::enable(const string &substring, bool match_exact, bool enabled, uint16_t ruleset) +uint16_t evttype_index_ruleset::ruleset_id(const std::string &name) +{ + auto it = find(m_ruleset_names.begin(), m_ruleset_names.end(), name); + if (it != m_ruleset_names.end()) + { + return it - m_ruleset_names.begin(); + } + m_ruleset_names.push_back(name); + return m_ruleset_names.size() - 1; +} + +void evttype_index_ruleset::on_loading_complete() +{ + // nothing to do for now +} + +void evttype_index_ruleset::clear() +{ + for (size_t i = 0; i < m_rulesets.size(); i++) + { + std::shared_ptr r(new ruleset_filters()); + m_rulesets[i] = r; + } + m_filters.clear(); +} + +void evttype_index_ruleset::enable(const string &substring, bool match_exact, bool enabled, uint16_t ruleset) { while(m_rulesets.size() < (size_t)ruleset + 1) { @@ -176,14 +211,14 @@ void falco_ruleset::enable(const string &substring, bool match_exact, bool enabl if(match_exact) { - size_t pos = wrap->name.find(substring); + size_t pos = wrap->rule.name.find(substring); matches = (substring == "" || (pos == 0 && - substring.size() == wrap->name.size())); + substring.size() == wrap->rule.name.size())); } else { - matches = (substring == "" || (wrap->name.find(substring) != string::npos)); + matches = (substring == "" || (wrap->rule.name.find(substring) != string::npos)); } if(matches) @@ -200,7 +235,7 @@ void falco_ruleset::enable(const string &substring, bool match_exact, bool enabl } } -void falco_ruleset::enable_tags(const set &tags, bool enabled, uint16_t ruleset) +void evttype_index_ruleset::enable_tags(const set &tags, bool enabled, uint16_t ruleset) { while(m_rulesets.size() < (size_t)ruleset + 1) { @@ -212,7 +247,7 @@ void falco_ruleset::enable_tags(const set &tags, bool enabled, uint16_t std::set intersect; set_intersection(tags.begin(), tags.end(), - wrap->tags.begin(), wrap->tags.end(), + wrap->rule.tags.begin(), wrap->rule.tags.end(), inserter(intersect, intersect.begin())); if(!intersect.empty()) @@ -229,7 +264,7 @@ void falco_ruleset::enable_tags(const set &tags, bool enabled, uint16_t } } -uint64_t falco_ruleset::num_rules_for_ruleset(uint16_t ruleset) +uint64_t evttype_index_ruleset::enabled_count(uint16_t ruleset) { while(m_rulesets.size() < (size_t)ruleset + 1) { @@ -239,17 +274,17 @@ uint64_t falco_ruleset::num_rules_for_ruleset(uint16_t ruleset) return m_rulesets[ruleset]->num_filters(); } -bool falco_ruleset::run(gen_event *evt, uint16_t ruleset) +bool evttype_index_ruleset::run(gen_event *evt, falco_rule& match, uint16_t ruleset) { if(m_rulesets.size() < (size_t)ruleset + 1) { return false; } - return m_rulesets[ruleset]->run(evt); + return m_rulesets[ruleset]->run(evt, match); } -void falco_ruleset::evttypes_for_ruleset(set &evttypes, uint16_t ruleset) +void evttype_index_ruleset::enabled_evttypes(set &evttypes, uint16_t ruleset) { if(m_rulesets.size() < (size_t)ruleset + 1) { diff --git a/userspace/engine/evttype_index_ruleset.h b/userspace/engine/evttype_index_ruleset.h new file mode 100644 index 00000000..9ae94456 --- /dev/null +++ b/userspace/engine/evttype_index_ruleset.h @@ -0,0 +1,140 @@ +/* +Copyright (C) 2019 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. +*/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "ruleset.h" +#include "sinsp.h" +#include "filter.h" +#include "event.h" + +#include "gen_filter.h" + +/*! + \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 +{ +public: + evttype_index_ruleset(std::shared_ptr factory); + virtual ~evttype_index_ruleset(); + + void add( + const falco_rule& rule, + std::shared_ptr condition) override; + + void clear() override; + + uint16_t ruleset_id(const std::string &name) override; + + bool run(gen_event *evt, falco_rule& match, uint16_t ruleset = 0); + + uint64_t enabled_count(uint16_t ruleset = 0) override; + + void on_loading_complete() override; + + void enable( + const std::string &substring, + bool match_exact, + bool enabled, + uint16_t ruleset = 0) override; + + void enable_tags( + const std::set &tags, + bool enabled, + uint16_t ruleset = 0) override; + + // evttypes for a ruleset + void enabled_evttypes( + std::set &evttypes, + uint16_t ruleset) override; + +private: + + struct filter_wrapper + { + falco_rule rule; + std::set evttypes; + 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(); + + bool run(gen_event *evt, falco_rule& match); + + void evttypes_for_ruleset(std::set &evttypes); + + 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 +{ +public: + inline evttype_index_ruleset_factory( + std::shared_ptr factory + ): m_filter_factory(factory) { } + + inline std::shared_ptr new_ruleset() override + { + std::shared_ptr ret( + new evttype_index_ruleset(m_filter_factory)); + return ret; + } + +private: + std::shared_ptr m_filter_factory; +}; \ No newline at end of file diff --git a/userspace/engine/falco_rule.h b/userspace/engine/falco_rule.h index b998771f..77aa8c79 100644 --- a/userspace/engine/falco_rule.h +++ b/userspace/engine/falco_rule.h @@ -22,6 +22,7 @@ limitations under the License. struct falco_rule { + size_t id; std::string source; std::string name; std::string description;