mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-22 12:43:24 +00:00
Compare commits
3 Commits
master
...
generalize
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2011ac9c6 | ||
|
|
7dfc4e3447 | ||
|
|
605e69cf0e |
@@ -22,6 +22,7 @@ add_library(falco_engine STATIC
|
||||
filter_details_resolver.cpp
|
||||
filter_macro_resolver.cpp
|
||||
filter_warning_resolver.cpp
|
||||
indexable_ruleset.cpp
|
||||
logger.cpp
|
||||
stats_manager.cpp
|
||||
rule_loader.cpp
|
||||
|
||||
@@ -17,14 +17,13 @@ limitations under the License.
|
||||
|
||||
#include "evttype_index_ruleset.h"
|
||||
|
||||
#include "falco_utils.h"
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
evttype_index_ruleset::evttype_index_ruleset(
|
||||
std::shared_ptr<sinsp_filter_factory> f): m_filter_factory(f)
|
||||
std::shared_ptr<sinsp_filter_factory> 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<filter_wrapper> 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<filter_wrapper> 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<filter_wrapper> 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<filter_wrapper> 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<falco_rule>& 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<ppm_sc_code> evttype_index_ruleset::ruleset_filters::sc_codes()
|
||||
{
|
||||
libsinsp::events::set<ppm_sc_code> res;
|
||||
for(const auto &wrap : m_filters)
|
||||
{
|
||||
res.insert(wrap->sc_codes.begin(), wrap->sc_codes.end());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
libsinsp::events::set<ppm_event_code> evttype_index_ruleset::ruleset_filters::event_codes()
|
||||
{
|
||||
libsinsp::events::set<ppm_event_code> 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<sinsp_filter> filter,
|
||||
@@ -203,21 +38,22 @@ void evttype_index_ruleset::add(
|
||||
{
|
||||
try
|
||||
{
|
||||
auto wrap = std::make_shared<filter_wrapper>();
|
||||
wrap->rule = rule;
|
||||
wrap->filter = filter;
|
||||
auto wrap = std::make_shared<wrapper>();
|
||||
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,48 @@ void evttype_index_ruleset::on_loading_complete()
|
||||
print_enabled_rules_falco_logger();
|
||||
}
|
||||
|
||||
bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, falco_rule &match)
|
||||
{
|
||||
for(auto &wrap : wrappers)
|
||||
{
|
||||
wrapper *derived = static_cast<wrapper *>(wrap.get());
|
||||
if(derived->m_filter->run(evt))
|
||||
{
|
||||
match = derived->m_rule;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, std::vector<falco_rule> &matches)
|
||||
{
|
||||
bool match_found = false;
|
||||
|
||||
for(auto &wrap : wrappers)
|
||||
{
|
||||
wrapper *derived = static_cast<wrapper *>(wrap.get());
|
||||
if(derived->m_filter->run(evt))
|
||||
{
|
||||
matches.push_back(derived->m_rule);
|
||||
match_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return match_found;
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
auto logger = [](std::shared_ptr<filter_wrapper> wrap)
|
||||
{
|
||||
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<ruleset_filters>();
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_rulesets.emplace_back(std::make_shared<ruleset_filters>());
|
||||
}
|
||||
|
||||
for(const auto &wrap : m_filters)
|
||||
{
|
||||
bool matches;
|
||||
std::string::size_type pos;
|
||||
|
||||
switch(match)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void evttype_index_ruleset::enable_tags(const std::set<std::string> &tags, uint16_t ruleset_id)
|
||||
{
|
||||
enable_disable_tags(tags, true, ruleset_id);
|
||||
}
|
||||
|
||||
void evttype_index_ruleset::disable_tags(const std::set<std::string> &tags, uint16_t ruleset_id)
|
||||
{
|
||||
enable_disable_tags(tags, false, ruleset_id);
|
||||
}
|
||||
|
||||
void evttype_index_ruleset::enable_disable_tags(const std::set<std::string> &tags, bool enabled, uint16_t ruleset_id)
|
||||
{
|
||||
while(m_rulesets.size() < (size_t)ruleset_id + 1)
|
||||
{
|
||||
m_rulesets.emplace_back(std::make_shared<ruleset_filters>());
|
||||
}
|
||||
|
||||
for(const auto &wrap : m_filters)
|
||||
{
|
||||
std::set<std::string> intersect;
|
||||
|
||||
set_intersection(tags.begin(), tags.end(),
|
||||
wrap->rule.tags.begin(), wrap->rule.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<ruleset_filters>());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool evttype_index_ruleset::run(sinsp_evt *evt, std::vector<falco_rule>& matches, uint16_t ruleset_id)
|
||||
{
|
||||
if(m_rulesets.size() < (size_t)ruleset_id + 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_rulesets[ruleset_id]->run(evt, matches);
|
||||
}
|
||||
|
||||
void evttype_index_ruleset::enabled_evttypes(std::set<uint16_t> &evttypes, uint16_t ruleset_id)
|
||||
{
|
||||
evttypes.clear();
|
||||
for (const auto& e : enabled_event_codes(ruleset_id))
|
||||
{
|
||||
evttypes.insert((uint16_t) e);
|
||||
}
|
||||
}
|
||||
|
||||
libsinsp::events::set<ppm_sc_code> evttype_index_ruleset::enabled_sc_codes(uint16_t ruleset)
|
||||
{
|
||||
if(m_rulesets.size() < (size_t)ruleset + 1)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return m_rulesets[ruleset]->sc_codes();
|
||||
}
|
||||
|
||||
libsinsp::events::set<ppm_event_code> 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::string(" ") + wrap->name() + "\n");
|
||||
};
|
||||
|
||||
uint64_t num_filters = iterate(logger);
|
||||
|
||||
falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(num_filters) + ") enabled rules in total\n");
|
||||
}
|
||||
|
||||
@@ -17,151 +17,53 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "indexable_ruleset.h"
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "filter_ruleset.h"
|
||||
#include <libsinsp/sinsp.h>
|
||||
#include <libsinsp/filter.h>
|
||||
#include <libsinsp/event.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
|
||||
class evttype_index_ruleset : public indexable_ruleset
|
||||
{
|
||||
public:
|
||||
explicit evttype_index_ruleset(std::shared_ptr<sinsp_filter_factory> factory);
|
||||
virtual ~evttype_index_ruleset();
|
||||
|
||||
// From filter_ruleset
|
||||
void add(
|
||||
const falco_rule& rule,
|
||||
std::shared_ptr<sinsp_filter> filter,
|
||||
std::shared_ptr<libsinsp::filter::ast::expr> 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<falco_rule>&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<falco_rule> &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<std::string> &tags,
|
||||
uint16_t rulset_id) override;
|
||||
|
||||
void disable_tags(
|
||||
const std::set<std::string> &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<uint16_t> &evttypes,
|
||||
uint16_t ruleset) override;
|
||||
|
||||
libsinsp::events::set<ppm_sc_code> enabled_sc_codes(uint16_t ruleset) override;
|
||||
|
||||
libsinsp::events::set<ppm_event_code> 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<std::string> &tags,
|
||||
bool enabled,
|
||||
uint16_t rulset_id);
|
||||
|
||||
struct filter_wrapper
|
||||
struct wrapper : public indexable_ruleset::filter_wrapper
|
||||
{
|
||||
falco_rule rule;
|
||||
libsinsp::events::set<ppm_sc_code> sc_codes;
|
||||
libsinsp::events::set<ppm_event_code> event_codes;
|
||||
std::shared_ptr<sinsp_filter> filter;
|
||||
const std::string &name() override { return m_rule.name; }
|
||||
const std::set<std::string> &tags() override { return m_rule.tags; }
|
||||
const libsinsp::events::set<ppm_sc_code> &sc_codes() override { return m_sc_codes; }
|
||||
const libsinsp::events::set<ppm_event_code> &event_codes() override { return m_event_codes; }
|
||||
|
||||
falco_rule m_rule;
|
||||
libsinsp::events::set<ppm_sc_code> m_sc_codes;
|
||||
libsinsp::events::set<ppm_event_code> m_event_codes;
|
||||
std::shared_ptr<sinsp_filter> m_filter;
|
||||
};
|
||||
|
||||
typedef std::list<std::shared_ptr<filter_wrapper>> 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<filter_wrapper> wrap);
|
||||
void remove_filter(std::shared_ptr<filter_wrapper> wrap);
|
||||
|
||||
uint64_t num_filters();
|
||||
|
||||
inline const std::set<std::shared_ptr<filter_wrapper>>& 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<falco_rule>& matches);
|
||||
|
||||
libsinsp::events::set<ppm_sc_code> sc_codes();
|
||||
|
||||
libsinsp::events::set<ppm_event_code> event_codes();
|
||||
|
||||
private:
|
||||
void add_wrapper_to_list(filter_wrapper_list &wrappers, std::shared_ptr<filter_wrapper> wrap);
|
||||
void remove_wrapper_from_list(filter_wrapper_list &wrappers, std::shared_ptr<filter_wrapper> 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<filter_wrapper_list> m_filter_by_event_type;
|
||||
|
||||
filter_wrapper_list m_filter_all_event_types;
|
||||
|
||||
// All filters added. Used to make num_filters() fast.
|
||||
std::set<std::shared_ptr<filter_wrapper>> m_filters;
|
||||
};
|
||||
|
||||
// Vector indexes from ruleset id to set of rules.
|
||||
std::vector<std::shared_ptr<ruleset_filters>> m_rulesets;
|
||||
|
||||
// All filters added. The set of enabled filters is held in m_rulesets
|
||||
std::set<std::shared_ptr<filter_wrapper>> m_filters;
|
||||
|
||||
std::shared_ptr<sinsp_filter_factory> m_filter_factory;
|
||||
std::vector<std::string> m_ruleset_names;
|
||||
};
|
||||
|
||||
class evttype_index_ruleset_factory: public filter_ruleset_factory
|
||||
|
||||
347
userspace/engine/indexable_ruleset.cpp
Normal file
347
userspace/engine/indexable_ruleset.cpp
Normal file
@@ -0,0 +1,347 @@
|
||||
// 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.
|
||||
*/
|
||||
|
||||
#include "indexable_ruleset.h"
|
||||
|
||||
#include "falco_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void indexable_ruleset::clear()
|
||||
{
|
||||
for(size_t i = 0; i < m_rulesets.size(); i++)
|
||||
{
|
||||
m_rulesets[i] = std::make_shared<ruleset_filters>(i);
|
||||
}
|
||||
m_filters.clear();
|
||||
}
|
||||
|
||||
uint64_t indexable_ruleset::enabled_count(uint16_t ruleset_id)
|
||||
{
|
||||
while(m_rulesets.size() < (size_t)ruleset_id + 1)
|
||||
{
|
||||
m_rulesets.emplace_back(std::make_shared<ruleset_filters>(m_rulesets.size()));
|
||||
}
|
||||
|
||||
return m_rulesets[ruleset_id]->num_filters();
|
||||
}
|
||||
|
||||
void indexable_ruleset::enabled_evttypes(std::set<uint16_t> &evttypes, uint16_t ruleset_id)
|
||||
{
|
||||
evttypes.clear();
|
||||
for(const auto &e : enabled_event_codes(ruleset_id))
|
||||
{
|
||||
evttypes.insert((uint16_t)e);
|
||||
}
|
||||
}
|
||||
|
||||
libsinsp::events::set<ppm_sc_code> indexable_ruleset::enabled_sc_codes(uint16_t ruleset)
|
||||
{
|
||||
if(m_rulesets.size() < (size_t)ruleset + 1)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return m_rulesets[ruleset]->sc_codes();
|
||||
}
|
||||
|
||||
libsinsp::events::set<ppm_event_code> indexable_ruleset::enabled_event_codes(uint16_t ruleset)
|
||||
{
|
||||
if(m_rulesets.size() < (size_t)ruleset + 1)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return m_rulesets[ruleset]->event_codes();
|
||||
}
|
||||
|
||||
void indexable_ruleset::enable(const std::string &pattern, match_type match, uint16_t ruleset_id)
|
||||
{
|
||||
enable_disable(pattern, match, true, ruleset_id);
|
||||
}
|
||||
|
||||
void indexable_ruleset::disable(const std::string &pattern, match_type match, uint16_t ruleset_id)
|
||||
{
|
||||
enable_disable(pattern, match, false, ruleset_id);
|
||||
}
|
||||
|
||||
void indexable_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)
|
||||
{
|
||||
m_rulesets.emplace_back(std::make_shared<ruleset_filters>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void indexable_ruleset::enable_tags(const std::set<std::string> &tags, uint16_t ruleset_id)
|
||||
{
|
||||
enable_disable_tags(tags, true, ruleset_id);
|
||||
}
|
||||
|
||||
void indexable_ruleset::disable_tags(const std::set<std::string> &tags, uint16_t ruleset_id)
|
||||
{
|
||||
enable_disable_tags(tags, false, ruleset_id);
|
||||
}
|
||||
|
||||
void indexable_ruleset::enable_disable_tags(const std::set<std::string> &tags, bool enabled, uint16_t ruleset_id)
|
||||
{
|
||||
while(m_rulesets.size() < (size_t)ruleset_id + 1)
|
||||
{
|
||||
m_rulesets.emplace_back(std::make_shared<ruleset_filters>(m_rulesets.size()));
|
||||
}
|
||||
|
||||
for(const auto &wrap : m_filters)
|
||||
{
|
||||
std::set<std::string> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool indexable_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(*this, evt, match);
|
||||
}
|
||||
|
||||
bool indexable_ruleset::run(sinsp_evt *evt, std::vector<falco_rule> &matches, uint16_t ruleset_id)
|
||||
{
|
||||
if(m_rulesets.size() < (size_t)ruleset_id + 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_rulesets[ruleset_id]->run(*this, evt, matches);
|
||||
}
|
||||
|
||||
void indexable_ruleset::add_wrapper(std::shared_ptr<filter_wrapper> wrap)
|
||||
{
|
||||
m_filters.insert(wrap);
|
||||
}
|
||||
|
||||
uint64_t indexable_ruleset::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;
|
||||
}
|
||||
|
||||
void indexable_ruleset::ruleset_filters::add_wrapper_to_list(filter_wrapper_list &wrappers, std::shared_ptr<filter_wrapper> 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 indexable_ruleset::ruleset_filters::remove_wrapper_from_list(filter_wrapper_list &wrappers, std::shared_ptr<filter_wrapper> 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 indexable_ruleset::ruleset_filters::add_filter(std::shared_ptr<filter_wrapper> 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 indexable_ruleset::ruleset_filters::remove_filter(std::shared_ptr<filter_wrapper> 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 indexable_ruleset::ruleset_filters::num_filters()
|
||||
{
|
||||
return m_filters.size();
|
||||
}
|
||||
|
||||
bool indexable_ruleset::ruleset_filters::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;
|
||||
}
|
||||
|
||||
bool indexable_ruleset::ruleset_filters::run(indexable_ruleset &ruleset, sinsp_evt *evt, std::vector<falco_rule> &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<ppm_sc_code> indexable_ruleset::ruleset_filters::sc_codes()
|
||||
{
|
||||
libsinsp::events::set<ppm_sc_code> res;
|
||||
for(const auto &wrap : m_filters)
|
||||
{
|
||||
res.insert(wrap->sc_codes().begin(), wrap->sc_codes().end());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
libsinsp::events::set<ppm_event_code> indexable_ruleset::ruleset_filters::event_codes()
|
||||
{
|
||||
libsinsp::events::set<ppm_event_code> res;
|
||||
for(const auto &wrap : m_filters)
|
||||
{
|
||||
res.insert(wrap->event_codes().begin(), wrap->event_codes().end());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
182
userspace/engine/indexable_ruleset.h
Normal file
182
userspace/engine/indexable_ruleset.h
Normal file
@@ -0,0 +1,182 @@
|
||||
// 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 "filter_ruleset.h"
|
||||
|
||||
#include <libsinsp/sinsp.h>
|
||||
#include <libsinsp/filter.h>
|
||||
#include <libsinsp/event.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class indexable_ruleset : public filter_ruleset
|
||||
{
|
||||
public:
|
||||
indexable_ruleset() = default;
|
||||
virtual ~indexable_ruleset() = default;
|
||||
|
||||
// Required to implement filter_ruleset
|
||||
void clear() override;
|
||||
|
||||
uint64_t enabled_count(uint16_t ruleset_id) override;
|
||||
|
||||
void enabled_evttypes(
|
||||
std::set<uint16_t> &evttypes,
|
||||
uint16_t ruleset) override;
|
||||
|
||||
libsinsp::events::set<ppm_sc_code> enabled_sc_codes(
|
||||
uint16_t ruleset) override;
|
||||
|
||||
libsinsp::events::set<ppm_event_code> enabled_event_codes(
|
||||
uint16_t ruleset) override;
|
||||
|
||||
void enable(
|
||||
const std::string &pattern,
|
||||
match_type match,
|
||||
uint16_t ruleset_id) override;
|
||||
|
||||
void disable(
|
||||
const std::string &pattern,
|
||||
match_type match,
|
||||
uint16_t ruleset_id) override;
|
||||
|
||||
void enable_tags(
|
||||
const std::set<std::string> &tags,
|
||||
uint16_t ruleset_id) override;
|
||||
|
||||
void disable_tags(
|
||||
const std::set<std::string> &tags,
|
||||
uint16_t ruleset_id) override;
|
||||
|
||||
// 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;
|
||||
bool run(sinsp_evt *evt, std::vector<falco_rule> &matches, uint16_t ruleset_id) override;
|
||||
|
||||
// Methods for working with filter wrappers
|
||||
|
||||
// A derived class should add "filter wrappers" that implement
|
||||
// these methods. They return the necessary information
|
||||
// required to segregate filters by name, tags, and event
|
||||
// types.
|
||||
struct filter_wrapper
|
||||
{
|
||||
virtual const std::string &name() = 0;
|
||||
virtual const std::set<std::string> &tags() = 0;
|
||||
virtual const libsinsp::events::set<ppm_sc_code> &sc_codes() = 0;
|
||||
virtual const libsinsp::events::set<ppm_event_code> &event_codes() = 0;
|
||||
};
|
||||
|
||||
typedef std::list<std::shared_ptr<filter_wrapper>>
|
||||
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<filter_wrapper> 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<void(const std::shared_ptr<filter_wrapper> &wrap)> filter_wrapper_func;
|
||||
uint64_t iterate(filter_wrapper_func func);
|
||||
|
||||
// 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<falco_rule> &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);
|
||||
|
||||
// Helper used by enable_tags()/disable_tags()
|
||||
void enable_disable_tags(
|
||||
const std::set<std::string> &tags,
|
||||
bool enabled,
|
||||
uint16_t ruleset_id);
|
||||
|
||||
// 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<filter_wrapper> wrap);
|
||||
void remove_filter(std::shared_ptr<filter_wrapper> wrap);
|
||||
|
||||
uint64_t num_filters();
|
||||
|
||||
inline const std::set<std::shared_ptr<filter_wrapper>> &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);
|
||||
|
||||
// Evaluate an event against the ruleset and return all the
|
||||
// matching rules.
|
||||
bool run(indexable_ruleset &ruleset, sinsp_evt *evt, std::vector<falco_rule> &matches);
|
||||
|
||||
libsinsp::events::set<ppm_sc_code> sc_codes();
|
||||
|
||||
libsinsp::events::set<ppm_event_code> event_codes();
|
||||
|
||||
private:
|
||||
void add_wrapper_to_list(filter_wrapper_list &wrappers, std::shared_ptr<filter_wrapper> wrap);
|
||||
void remove_wrapper_from_list(filter_wrapper_list &wrappers, std::shared_ptr<filter_wrapper> wrap);
|
||||
|
||||
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<filter_wrapper_list> m_filter_by_event_type;
|
||||
|
||||
filter_wrapper_list m_filter_all_event_types;
|
||||
|
||||
// All filters added. Used to make num_filters() fast.
|
||||
std::set<std::shared_ptr<filter_wrapper>> m_filters;
|
||||
};
|
||||
|
||||
// Vector indexes from ruleset id to set of rules.
|
||||
std::vector<std::shared_ptr<ruleset_filters>> m_rulesets;
|
||||
|
||||
// All filters added. The set of enabled filters is held in m_rulesets
|
||||
std::set<std::shared_ptr<filter_wrapper>> m_filters;
|
||||
};
|
||||
Reference in New Issue
Block a user