mirror of
https://github.com/falcosecurity/falco.git
synced 2025-09-06 01:00:36 +00:00
refactor(userspace/engine): polish evttype resolver and use it in rule loader
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
@@ -412,6 +412,7 @@ void falco_engine::print_stats()
|
|||||||
void falco_engine::add_filter(std::shared_ptr<gen_event_filter> filter,
|
void falco_engine::add_filter(std::shared_ptr<gen_event_filter> filter,
|
||||||
std::string &rule,
|
std::string &rule,
|
||||||
std::string &source,
|
std::string &source,
|
||||||
|
std::set<uint16_t> &evttypes,
|
||||||
std::set<std::string> &tags)
|
std::set<std::string> &tags)
|
||||||
{
|
{
|
||||||
auto it = find_ruleset(source);
|
auto it = find_ruleset(source);
|
||||||
@@ -421,7 +422,7 @@ void falco_engine::add_filter(std::shared_ptr<gen_event_filter> filter,
|
|||||||
throw falco_exception(err);
|
throw falco_exception(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
it->ruleset->add(source, rule, tags, filter);
|
it->ruleset->add(source, rule, tags, evttypes, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool falco_engine::is_source_valid(const std::string &source)
|
bool falco_engine::is_source_valid(const std::string &source)
|
||||||
|
@@ -203,6 +203,7 @@ public:
|
|||||||
void add_filter(std::shared_ptr<gen_event_filter> filter,
|
void add_filter(std::shared_ptr<gen_event_filter> filter,
|
||||||
std::string &rule,
|
std::string &rule,
|
||||||
std::string &source,
|
std::string &source,
|
||||||
|
std::set<uint16_t> &evttypes,
|
||||||
std::set<std::string> &tags);
|
std::set<std::string> &tags);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@@ -27,15 +27,29 @@ static bool is_evttype_operator(const string& op)
|
|||||||
return op == "==" || op == "=" || op == "!=" || op == "in";
|
return op == "==" || op == "=" || op == "!=" || op == "in";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void filter_evttype_resolver::inversion(set<uint16_t>& types)
|
||||||
|
{
|
||||||
|
set<uint16_t> all_types;
|
||||||
|
evttypes("", all_types);
|
||||||
|
if (types != all_types) // we don't invert the "all types" set
|
||||||
|
{
|
||||||
|
set<uint16_t> diff = types;
|
||||||
|
types.clear();
|
||||||
|
set_difference(
|
||||||
|
all_types.begin(), all_types.end(), diff.begin(), diff.end(),
|
||||||
|
inserter(types, types.begin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void filter_evttype_resolver::evttypes(string evtname, set<uint16_t>& out)
|
void filter_evttype_resolver::evttypes(string evtname, set<uint16_t>& out)
|
||||||
{
|
{
|
||||||
// Fill in from 2 to PPM_EVENT_MAX-1. 0 and 1 are excluded as
|
// Fill in from 2 to PPM_EVENT_MAX-1. 0 and 1 are excluded as
|
||||||
// those are PPM_GENERIC_E/PPME_GENERIC_X.
|
// those are PPM_GENERIC_E/PPME_GENERIC_X
|
||||||
const struct ppm_event_info* etable = g_infotables.m_event_info;
|
const struct ppm_event_info* etable = g_infotables.m_event_info;
|
||||||
for(uint16_t i = 2; i < PPM_EVENT_MAX; i++)
|
for(uint16_t i = 2; i < PPM_EVENT_MAX; i++)
|
||||||
{
|
{
|
||||||
// Skip "old" event versions that have been replaced
|
// Skip "old" event versions, unused events, or events not matching
|
||||||
// by newer event versions, or events that are unused.
|
// the requested evtname
|
||||||
if(!(etable[i].flags & (EF_OLD_VERSION | EF_UNUSED))
|
if(!(etable[i].flags & (EF_OLD_VERSION | EF_UNUSED))
|
||||||
&& (evtname.empty() || string(etable[i].name) == evtname))
|
&& (evtname.empty() || string(etable[i].name) == evtname))
|
||||||
{
|
{
|
||||||
@@ -49,9 +63,7 @@ void filter_evttype_resolver::evttypes(ast::expr* filter, set<uint16_t>& out)
|
|||||||
m_expect_value = false;
|
m_expect_value = false;
|
||||||
m_last_node_evttypes.clear();
|
m_last_node_evttypes.clear();
|
||||||
filter->accept(this);
|
filter->accept(this);
|
||||||
copy(m_last_node_evttypes.begin(),
|
out.insert(m_last_node_evttypes.begin(), m_last_node_evttypes.end());
|
||||||
m_last_node_evttypes.end(),
|
|
||||||
inserter(out, out.begin()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter_evttype_resolver::evttypes(
|
void filter_evttype_resolver::evttypes(
|
||||||
@@ -60,57 +72,47 @@ void filter_evttype_resolver::evttypes(
|
|||||||
m_expect_value = false;
|
m_expect_value = false;
|
||||||
m_last_node_evttypes.clear();
|
m_last_node_evttypes.clear();
|
||||||
filter.get()->accept(this);
|
filter.get()->accept(this);
|
||||||
copy(m_last_node_evttypes.begin(),
|
out.insert(m_last_node_evttypes.begin(), m_last_node_evttypes.end());
|
||||||
m_last_node_evttypes.end(),
|
|
||||||
inserter(out, out.begin()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "and" nodes evttypes are the intersection of the evttypes of their children.
|
||||||
|
// we initialize the set with "all event types"
|
||||||
void filter_evttype_resolver::visit(ast::and_expr* e)
|
void filter_evttype_resolver::visit(ast::and_expr* e)
|
||||||
{
|
{
|
||||||
set<uint16_t> nodetypes;
|
set<uint16_t> types, inters;
|
||||||
evttypes("", nodetypes);
|
evttypes("", types);
|
||||||
m_last_node_evttypes.clear();
|
m_last_node_evttypes.clear();
|
||||||
for (auto &c : e->children)
|
for (auto &c : e->children)
|
||||||
{
|
{
|
||||||
set<uint16_t> inters;
|
inters.clear();
|
||||||
c->accept(this);
|
c->accept(this);
|
||||||
set_intersection(
|
set_intersection(
|
||||||
nodetypes.begin(), nodetypes.end(),
|
types.begin(), types.end(),
|
||||||
m_last_node_evttypes.begin(), m_last_node_evttypes.end(),
|
m_last_node_evttypes.begin(), m_last_node_evttypes.end(),
|
||||||
std::inserter(inters, inters.begin()));
|
inserter(inters, inters.begin()));
|
||||||
nodetypes = inters;
|
types = inters;
|
||||||
}
|
}
|
||||||
m_last_node_evttypes = nodetypes;
|
m_last_node_evttypes = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "or" nodes evttypes are the union of the evttypes their children
|
||||||
void filter_evttype_resolver::visit(ast::or_expr* e)
|
void filter_evttype_resolver::visit(ast::or_expr* e)
|
||||||
{
|
{
|
||||||
set<uint16_t> nodetypes;
|
set<uint16_t> types;
|
||||||
m_last_node_evttypes.clear();
|
m_last_node_evttypes.clear();
|
||||||
for (auto &c : e->children)
|
for (auto &c : e->children)
|
||||||
{
|
{
|
||||||
c->accept(this);
|
c->accept(this);
|
||||||
copy(m_last_node_evttypes.begin(),
|
types.insert(m_last_node_evttypes.begin(), m_last_node_evttypes.end());
|
||||||
m_last_node_evttypes.end(),
|
|
||||||
inserter(nodetypes, nodetypes.begin()));
|
|
||||||
}
|
}
|
||||||
m_last_node_evttypes = nodetypes;
|
m_last_node_evttypes = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter_evttype_resolver::visit(ast::not_expr* e)
|
void filter_evttype_resolver::visit(ast::not_expr* e)
|
||||||
{
|
{
|
||||||
set<uint16_t> diff, all_types;
|
|
||||||
m_last_node_evttypes.clear();
|
m_last_node_evttypes.clear();
|
||||||
e->child->accept(this);
|
e->child->accept(this);
|
||||||
evttypes("", all_types);
|
inversion(m_last_node_evttypes);
|
||||||
if (all_types != m_last_node_evttypes)
|
|
||||||
{
|
|
||||||
diff = m_last_node_evttypes;
|
|
||||||
m_last_node_evttypes.clear();
|
|
||||||
set_difference(
|
|
||||||
all_types.begin(), all_types.end(), diff.begin(), diff.end(),
|
|
||||||
inserter(m_last_node_evttypes, m_last_node_evttypes.begin()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter_evttype_resolver::visit(ast::binary_check_expr* e)
|
void filter_evttype_resolver::visit(ast::binary_check_expr* e)
|
||||||
@@ -123,13 +125,7 @@ void filter_evttype_resolver::visit(ast::binary_check_expr* e)
|
|||||||
m_expect_value = false;
|
m_expect_value = false;
|
||||||
if (e->op == "!=")
|
if (e->op == "!=")
|
||||||
{
|
{
|
||||||
set<uint16_t> all_types;
|
inversion(m_last_node_evttypes);
|
||||||
set<uint16_t> diff = m_last_node_evttypes;
|
|
||||||
m_last_node_evttypes.clear();
|
|
||||||
evttypes("", all_types);
|
|
||||||
set_difference(
|
|
||||||
all_types.begin(), all_types.end(), diff.begin(), diff.end(),
|
|
||||||
inserter(m_last_node_evttypes, m_last_node_evttypes.begin()));
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -62,6 +62,7 @@ private:
|
|||||||
void visit(libsinsp::filter::ast::list_expr* e) override;
|
void visit(libsinsp::filter::ast::list_expr* e) override;
|
||||||
void visit(libsinsp::filter::ast::unary_check_expr* e) override;
|
void visit(libsinsp::filter::ast::unary_check_expr* e) override;
|
||||||
void visit(libsinsp::filter::ast::binary_check_expr* e) override;
|
void visit(libsinsp::filter::ast::binary_check_expr* e) override;
|
||||||
|
void inversion(std::set<uint16_t>& types);
|
||||||
|
|
||||||
bool m_expect_value;
|
bool m_expect_value;
|
||||||
std::set<uint16_t> m_last_node_evttypes;
|
std::set<uint16_t> m_last_node_evttypes;
|
||||||
|
@@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
#include "falco_engine.h"
|
#include "falco_engine.h"
|
||||||
#include "rule_loader.h"
|
#include "rule_loader.h"
|
||||||
#include "filter_macro_resolver.h"
|
#include "filter_macro_resolver.h"
|
||||||
|
#include "filter_evttype_resolver.h"
|
||||||
|
|
||||||
#define MAX_VISIBILITY ((uint32_t) -1)
|
#define MAX_VISIBILITY ((uint32_t) -1)
|
||||||
#define THROW(cond, err) { if (cond) { throw falco_exception(err); } }
|
#define THROW(cond, err) { if (cond) { throw falco_exception(err); } }
|
||||||
@@ -701,11 +702,14 @@ void rule_loader::compile_rule_infos(
|
|||||||
throw falco_exception("Rule " + rule.name + ": error " + err);
|
throw falco_exception("Rule " + rule.name + ": error " + err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cfg.engine->add_filter(filter, rule.name, rule.source, rule.tags);
|
|
||||||
if (rule.source == falco_common::syscall_source && r.warn_evttypes)
|
set<uint16_t> evttypes;
|
||||||
|
if(rule.source == falco_common::syscall_source)
|
||||||
{
|
{
|
||||||
auto evttypes = filter->evttypes();
|
filter_evttype_resolver resolver;
|
||||||
if (evttypes.size() == 0 || evttypes.size() > 100)
|
resolver.evttypes(ast, evttypes);
|
||||||
|
if ((evttypes.empty() || evttypes.size() > 100)
|
||||||
|
&& r.warn_evttypes)
|
||||||
{
|
{
|
||||||
cfg.warnings.push_back(
|
cfg.warnings.push_back(
|
||||||
"Rule " + rule.name + ": warning (no-evttype):\n" +
|
"Rule " + rule.name + ": warning (no-evttype):\n" +
|
||||||
@@ -713,6 +717,18 @@ void rule_loader::compile_rule_infos(
|
|||||||
+ " This has a significant performance penalty.");
|
+ " This has a significant performance penalty.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (rule.source == "k8s_audit")
|
||||||
|
{
|
||||||
|
// todo(jasondellaluce): remove this case once k8saudit
|
||||||
|
// gets ported to a plugin
|
||||||
|
evttypes = { ppm_event_type::PPME_GENERIC_X };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
evttypes = { ppm_event_type::PPME_PLUGINEVENT_E };
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.engine->add_filter(filter, rule.name, rule.source, evttypes, rule.tags);
|
||||||
cfg.engine->enable_rule(rule.name, r.enabled);
|
cfg.engine->enable_rule(rule.name, r.enabled);
|
||||||
}
|
}
|
||||||
catch (exception& e)
|
catch (exception& e)
|
||||||
|
Reference in New Issue
Block a user