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 <mark.stemm@gmail.com>
This commit is contained in:
Mark Stemm 2024-06-13 15:22:16 -07:00 committed by poiana
parent bbcfa61d82
commit adeca79d1c
2 changed files with 72 additions and 467 deletions

View File

@ -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<evttype_index_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,46 @@ 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)
{
if(wrap->m_filter->run(evt))
{
match = wrap->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)
{
if(wrap->m_filter->run(evt))
{
matches.push_back(wrap->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<evttype_index_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");
}

View File

@ -17,151 +17,54 @@ 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
struct evttype_index_wrapper
{
const std::string &name() { return m_rule.name; }
const std::set<std::string> &tags() { return m_rule.tags; }
const libsinsp::events::set<ppm_sc_code> &sc_codes() { return m_sc_codes; }
const libsinsp::events::set<ppm_event_code> &event_codes() { 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;
};
class evttype_index_ruleset : public indexable_ruleset<evttype_index_wrapper>
{
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
{
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;
};
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