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:
Jason Dellaluce
2022-04-11 11:41:40 +00:00
committed by poiana
parent dd3d235d7f
commit b8a95d262f
5 changed files with 58 additions and 43 deletions

View File

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

View File

@@ -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);
// //

View File

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

View File

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

View File

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