mirror of
https://github.com/falcosecurity/falco.git
synced 2025-07-31 22:16:49 +00:00
update(userspace/engine): allow the engine to match and handle multiple rules while processing events
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
This commit is contained in:
parent
46e8f2c14b
commit
1705c0dab3
@ -138,6 +138,45 @@ bool evttype_index_ruleset::ruleset_filters::run(gen_event *evt, falco_rule& mat
|
||||
return false;
|
||||
}
|
||||
|
||||
bool evttype_index_ruleset::ruleset_filters::run(gen_event *evt, std::vector<falco_rule>& matches)
|
||||
{
|
||||
bool match_found = false;
|
||||
|
||||
if(evt->get_type() < m_filter_by_event_type.size())
|
||||
{
|
||||
for(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(auto &wrap : m_filter_all_event_types)
|
||||
{
|
||||
if(wrap->filter->run(evt))
|
||||
{
|
||||
matches.push_back(wrap->rule);
|
||||
match_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(match_found)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
libsinsp::events::set<ppm_sc_code> evttype_index_ruleset::ruleset_filters::sc_codes()
|
||||
{
|
||||
libsinsp::events::set<ppm_sc_code> res;
|
||||
@ -308,6 +347,16 @@ bool evttype_index_ruleset::run(gen_event *evt, falco_rule& match, uint16_t rule
|
||||
return m_rulesets[ruleset_id]->run(evt, match);
|
||||
}
|
||||
|
||||
bool evttype_index_ruleset::run(gen_event *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();
|
||||
|
@ -46,7 +46,8 @@ public:
|
||||
|
||||
void clear() override;
|
||||
|
||||
bool run(gen_event *evt, falco_rule& match, uint16_t rulset_id);
|
||||
bool run(gen_event *evt, falco_rule& match, uint16_t ruleset_id) override;
|
||||
bool run(gen_event *evt, std::vector<falco_rule>&matches, uint16_t ruleset_id) override;
|
||||
|
||||
uint64_t enabled_count(uint16_t ruleset_id) override;
|
||||
|
||||
@ -118,8 +119,14 @@ private:
|
||||
|
||||
uint64_t num_filters();
|
||||
|
||||
// Evaluate an event against the ruleset and return the first rule
|
||||
// that matched.
|
||||
bool run(gen_event *evt, falco_rule& match);
|
||||
|
||||
// Evaluate an event against the ruleset and return all the
|
||||
// matching rules.
|
||||
bool run(gen_event *evt, std::vector<falco_rule>& matches);
|
||||
|
||||
libsinsp::events::set<ppm_sc_code> sc_codes();
|
||||
|
||||
libsinsp::events::set<ppm_event_code> event_codes();
|
||||
|
@ -56,6 +56,7 @@ falco_engine::falco_engine(bool seed_rng)
|
||||
m_syscall_source_idx(SIZE_MAX),
|
||||
m_next_ruleset_id(0),
|
||||
m_min_priority(falco_common::PRIORITY_DEBUG),
|
||||
m_rule_matching(falco_common::FIRST),
|
||||
m_sampling_ratio(1), m_sampling_multiplier(0),
|
||||
m_replace_container_info(false)
|
||||
{
|
||||
@ -310,6 +311,11 @@ void falco_engine::set_min_priority(falco_common::priority_type priority)
|
||||
m_min_priority = priority;
|
||||
}
|
||||
|
||||
void falco_engine::set_rule_matching(falco_common::rule_matching rule_matching)
|
||||
{
|
||||
m_rule_matching = rule_matching;
|
||||
}
|
||||
|
||||
uint16_t falco_engine::find_ruleset_id(const std::string &ruleset)
|
||||
{
|
||||
auto it = m_known_rulesets.lower_bound(ruleset);
|
||||
@ -353,7 +359,7 @@ std::shared_ptr<gen_event_formatter> falco_engine::create_formatter(const std::s
|
||||
return find_source(source)->formatter_factory->create_formatter(output);
|
||||
}
|
||||
|
||||
std::unique_ptr<falco_engine::rule_result> falco_engine::process_event(std::size_t source_idx, gen_event *ev, uint16_t ruleset_id)
|
||||
std::unique_ptr<std::vector<falco_engine::rule_result>> falco_engine::process_event(std::size_t source_idx, gen_event *ev, uint16_t ruleset_id)
|
||||
{
|
||||
// note: there are no thread-safety guarantees on the filter_ruleset::run()
|
||||
// method, but the thread-safety assumptions of falco_engine::process_event()
|
||||
@ -377,24 +383,51 @@ std::unique_ptr<falco_engine::rule_result> falco_engine::process_event(std::size
|
||||
source = find_source(source_idx);
|
||||
}
|
||||
|
||||
if(should_drop_evt() || !source || !source->ruleset->run(ev, source->m_rule, ruleset_id))
|
||||
if(should_drop_evt() || !source)
|
||||
{
|
||||
return std::unique_ptr<struct rule_result>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<struct rule_result> res(new rule_result());
|
||||
res->evt = ev;
|
||||
res->rule = source->m_rule.name;
|
||||
res->source = source->m_rule.source;
|
||||
res->format = source->m_rule.output;
|
||||
res->priority_num = source->m_rule.priority;
|
||||
res->tags = source->m_rule.tags;
|
||||
res->exception_fields = source->m_rule.exception_fields;
|
||||
m_rule_stats_manager.on_event(source->m_rule);
|
||||
if (m_rule_matching == falco_common::rule_matching::ALL)
|
||||
{
|
||||
if (!source->ruleset->run(ev, source->m_rules, ruleset_id))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if (m_rule_matching == falco_common::rule_matching::FIRST)
|
||||
{
|
||||
falco_rule rule;
|
||||
if (!source->ruleset->run(ev, rule, ruleset_id))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
source->m_rules.push_back(rule);
|
||||
}
|
||||
|
||||
auto res = std::make_unique<std::vector<falco_engine::rule_result>>();
|
||||
for(auto rule : source->m_rules)
|
||||
{
|
||||
rule_result rule_result;
|
||||
rule_result.evt = ev;
|
||||
rule_result.rule = rule.name;
|
||||
rule_result.source = rule.source;
|
||||
rule_result.format = rule.output;
|
||||
rule_result.priority_num = rule.priority;
|
||||
rule_result.tags = rule.tags;
|
||||
rule_result.exception_fields = rule.exception_fields;
|
||||
m_rule_stats_manager.on_event(rule);
|
||||
res->push_back(rule_result);
|
||||
}
|
||||
|
||||
if (source->m_rules.size() > 0)
|
||||
{
|
||||
source->m_rules.clear();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::unique_ptr<falco_engine::rule_result> falco_engine::process_event(std::size_t source_idx, gen_event *ev)
|
||||
std::unique_ptr<std::vector<falco_engine::rule_result>> falco_engine::process_event(std::size_t source_idx, gen_event *ev)
|
||||
{
|
||||
return process_event(source_idx, ev, m_default_ruleset_id);
|
||||
}
|
||||
|
@ -106,6 +106,11 @@ public:
|
||||
// Only load rules having this priority or more severe.
|
||||
void set_min_priority(falco_common::priority_type priority);
|
||||
|
||||
// Whether or not continuing to evaluate rules for other potential matches
|
||||
// even if a match already occurred. This option can be set to avoid shadowing
|
||||
// of rules.
|
||||
void set_rule_matching(falco_common::rule_matching rule_matching);
|
||||
|
||||
//
|
||||
// Return the ruleset id corresponding to this ruleset name,
|
||||
// creating a new one if necessary. If you provide any ruleset
|
||||
@ -189,14 +194,14 @@ public:
|
||||
// event source is not thread-safe of its own, so invoking this method
|
||||
// concurrently with the same source_idx would inherently cause data races
|
||||
// and lead to undefined behavior.
|
||||
std::unique_ptr<rule_result> process_event(std::size_t source_idx, gen_event *ev, uint16_t ruleset_id);
|
||||
std::unique_ptr<std::vector<rule_result>> process_event(std::size_t source_idx, gen_event *ev, uint16_t ruleset_id);
|
||||
|
||||
//
|
||||
// Wrapper assuming the default ruleset.
|
||||
//
|
||||
// This inherits the same thread-safety guarantees.
|
||||
//
|
||||
std::unique_ptr<rule_result> process_event(std::size_t source_idx, gen_event *ev);
|
||||
std::unique_ptr<std::vector<rule_result>> process_event(std::size_t source_idx, gen_event *ev);
|
||||
|
||||
//
|
||||
// Configure the engine to support events with the provided
|
||||
@ -320,6 +325,7 @@ private:
|
||||
uint16_t m_next_ruleset_id;
|
||||
std::map<std::string, uint16_t> m_known_rulesets;
|
||||
falco_common::priority_type m_min_priority;
|
||||
falco_common::rule_matching m_rule_matching;
|
||||
|
||||
//
|
||||
// Here's how the sampling ratio and multiplier influence
|
||||
|
@ -53,7 +53,7 @@ struct falco_source
|
||||
|
||||
// Used by the filter_ruleset interface. Filled in when a rule
|
||||
// matches an event.
|
||||
mutable falco_rule m_rule;
|
||||
mutable std::vector<falco_rule> m_rules;
|
||||
|
||||
inline bool is_field_defined(const std::string& field) const
|
||||
{
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
\brief Processes an event and tries to find a match in a given ruleset.
|
||||
\return true if a match is found, false otherwise
|
||||
\param evt The event to be processed
|
||||
\param match If true is returned, this is filled-out with the rule
|
||||
\param match If true is returned, this is filled-out with the first rule
|
||||
that matched the event
|
||||
\param ruleset_id The id of the ruleset to be used
|
||||
*/
|
||||
@ -73,6 +73,19 @@ public:
|
||||
gen_event *evt,
|
||||
falco_rule& match,
|
||||
uint16_t ruleset_id) = 0;
|
||||
|
||||
/*!
|
||||
\brief Processes an event and tries to find a match in a given ruleset.
|
||||
\return true if a match is found, false otherwise
|
||||
\param evt The event to be processed
|
||||
\param matches If true is returned, this is filled-out with all the rules
|
||||
that matched the event
|
||||
\param ruleset_id The id of the ruleset to be used
|
||||
*/
|
||||
virtual bool run(
|
||||
gen_event *evt,
|
||||
std::vector<falco_rule>& matches,
|
||||
uint16_t ruleset_id) = 0;
|
||||
|
||||
/*!
|
||||
\brief Returns the number of rules enabled in a given ruleset
|
||||
|
@ -330,19 +330,22 @@ static falco::app::run_result do_inspect(
|
||||
// engine, which will match the event against the set
|
||||
// of rules. If a match is found, pass the event to
|
||||
// the outputs.
|
||||
std::unique_ptr<falco_engine::rule_result> res = s.engine->process_event(source_engine_idx, ev);
|
||||
if(res)
|
||||
auto res = s.engine->process_event(source_engine_idx, ev);
|
||||
if(res != nullptr)
|
||||
{
|
||||
if (!rate_limiter_enabled || rate_limiter.claim())
|
||||
for(auto& rule_res : *res.get())
|
||||
{
|
||||
s.outputs->handle_event(res->evt, res->rule, res->source, res->priority_num, res->format, res->tags);
|
||||
}
|
||||
else
|
||||
{
|
||||
falco_logger::log(LOG_DEBUG, "Skipping rate-limited notification for rule " + res->rule + "\n");
|
||||
if (!rate_limiter_enabled || rate_limiter.claim())
|
||||
{
|
||||
s.outputs->handle_event(rule_res.evt, rule_res.rule, rule_res.source, rule_res.priority_num, rule_res.format, rule_res.tags);
|
||||
}
|
||||
else
|
||||
{
|
||||
falco_logger::log(LOG_DEBUG, "Skipping rate-limited notification for rule " + rule_res.rule + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
num_evts++;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user