Compare commits

...

3 Commits

Author SHA1 Message Date
Mark Stemm
c2011ac9c6 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_ruleset::wrapper contains a falco rule and filter,
and run_wrappers() evaluate the filter as before, without the
segregation by ruleset id/event type.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-06-18 10:26:49 -07:00
Mark Stemm
7dfc4e3447 Actually add indexable_ruleset to build
Done separately just in case we ever have github checks that track
files separate from cmake changes.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-06-14 11:39:32 -07:00
Mark Stemm
605e69cf0e 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 base class indexable_ruleset that
takes a generic filter_wrapper object that can return a name, tags,
and sc/event codes, and segregates the filters by ruleset. It also
optionally segregates filters by event type.

The main interfaces are:

- an implementation of filter_wrapper to provide a name/tags/event
  codes.
- add_wrapper(), which provides a filter_wrapper to the
  indexable_ruleset.
- 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 <mark.stemm@gmail.com>
2024-06-14 11:39:32 -07:00
5 changed files with 600 additions and 464 deletions

View File

@@ -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

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<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");
}

View File

@@ -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

View 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;
}

View 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;
};