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,
std::string &rule,
std::string &source,
std::set<uint16_t> &evttypes,
std::set<std::string> &tags)
{
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);
}
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)

View File

@@ -203,6 +203,7 @@ public:
void add_filter(std::shared_ptr<gen_event_filter> filter,
std::string &rule,
std::string &source,
std::set<uint16_t> &evttypes,
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";
}
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)
{
// 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;
for(uint16_t i = 2; i < PPM_EVENT_MAX; i++)
{
// Skip "old" event versions that have been replaced
// by newer event versions, or events that are unused.
// Skip "old" event versions, unused events, or events not matching
// the requested evtname
if(!(etable[i].flags & (EF_OLD_VERSION | EF_UNUSED))
&& (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_last_node_evttypes.clear();
filter->accept(this);
copy(m_last_node_evttypes.begin(),
m_last_node_evttypes.end(),
inserter(out, out.begin()));
out.insert(m_last_node_evttypes.begin(), m_last_node_evttypes.end());
}
void filter_evttype_resolver::evttypes(
@@ -60,57 +72,47 @@ void filter_evttype_resolver::evttypes(
m_expect_value = false;
m_last_node_evttypes.clear();
filter.get()->accept(this);
copy(m_last_node_evttypes.begin(),
m_last_node_evttypes.end(),
inserter(out, out.begin()));
out.insert(m_last_node_evttypes.begin(), m_last_node_evttypes.end());
}
// "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)
{
set<uint16_t> nodetypes;
evttypes("", nodetypes);
set<uint16_t> types, inters;
evttypes("", types);
m_last_node_evttypes.clear();
for (auto &c : e->children)
{
set<uint16_t> inters;
inters.clear();
c->accept(this);
set_intersection(
nodetypes.begin(), nodetypes.end(),
types.begin(), types.end(),
m_last_node_evttypes.begin(), m_last_node_evttypes.end(),
std::inserter(inters, inters.begin()));
nodetypes = inters;
inserter(inters, inters.begin()));
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)
{
set<uint16_t> nodetypes;
set<uint16_t> types;
m_last_node_evttypes.clear();
for (auto &c : e->children)
{
c->accept(this);
copy(m_last_node_evttypes.begin(),
m_last_node_evttypes.end(),
inserter(nodetypes, nodetypes.begin()));
types.insert(m_last_node_evttypes.begin(), m_last_node_evttypes.end());
}
m_last_node_evttypes = nodetypes;
m_last_node_evttypes = types;
}
void filter_evttype_resolver::visit(ast::not_expr* e)
{
set<uint16_t> diff, all_types;
m_last_node_evttypes.clear();
e->child->accept(this);
evttypes("", all_types);
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()));
}
inversion(m_last_node_evttypes);
}
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;
if (e->op == "!=")
{
set<uint16_t> all_types;
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()));
inversion(m_last_node_evttypes);
}
return;
}

View File

@@ -62,6 +62,7 @@ private:
void visit(libsinsp::filter::ast::list_expr* e) override;
void visit(libsinsp::filter::ast::unary_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;
std::set<uint16_t> m_last_node_evttypes;

View File

@@ -17,6 +17,7 @@ limitations under the License.
#include "falco_engine.h"
#include "rule_loader.h"
#include "filter_macro_resolver.h"
#include "filter_evttype_resolver.h"
#define MAX_VISIBILITY ((uint32_t) -1)
#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);
}
}
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();
if (evttypes.size() == 0 || evttypes.size() > 100)
filter_evttype_resolver resolver;
resolver.evttypes(ast, evttypes);
if ((evttypes.empty() || evttypes.size() > 100)
&& r.warn_evttypes)
{
cfg.warnings.push_back(
"Rule " + rule.name + ": warning (no-evttype):\n" +
@@ -713,6 +717,18 @@ void rule_loader::compile_rule_infos(
+ " 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);
}
catch (exception& e)