new(userspace/engine): add a resolver class to search evttypes from filters and event names

Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
Jason Dellaluce 2022-04-05 15:09:14 +00:00 committed by poiana
parent f638706ba3
commit b5870a8656
3 changed files with 237 additions and 0 deletions

View File

@ -18,6 +18,7 @@ set(FALCO_ENGINE_SOURCE_FILES
ruleset.cpp
formats.cpp
filter_macro_resolver.cpp
filter_evttype_resolver.cpp
rule_loader.cpp
rule_reader.cpp
stats_manager.cpp)

View File

@ -0,0 +1,168 @@
/*
Copyright (C) 2022 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 "filter_evttype_resolver.h"
#include <sinsp.h>
using namespace std;
using namespace libsinsp::filter;
extern sinsp_evttables g_infotables;
static bool is_evttype_operator(const string& op)
{
return op == "==" || op == "=" || op == "!=" || op == "in";
}
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.
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.
if(!(etable[i].flags & (EF_OLD_VERSION | EF_UNUSED))
&& (evtname.empty() || string(etable[i].name) == evtname))
{
out.insert(i);
}
}
}
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()));
}
void filter_evttype_resolver::evttypes(
shared_ptr<ast::expr> filter, set<uint16_t>& out)
{
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()));
}
void filter_evttype_resolver::visit(ast::and_expr* e)
{
set<uint16_t> nodetypes;
evttypes("", nodetypes);
m_last_node_evttypes.clear();
for (auto &c : e->children)
{
set<uint16_t> inters;
c->accept(this);
set_intersection(
nodetypes.begin(), nodetypes.end(),
m_last_node_evttypes.begin(), m_last_node_evttypes.end(),
std::inserter(inters, inters.begin()));
nodetypes = inters;
}
m_last_node_evttypes = nodetypes;
}
void filter_evttype_resolver::visit(ast::or_expr* e)
{
set<uint16_t> nodetypes;
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()));
}
m_last_node_evttypes = nodetypes;
}
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()));
}
}
void filter_evttype_resolver::visit(ast::binary_check_expr* e)
{
m_last_node_evttypes.clear();
if (e->field == "evt.type" && is_evttype_operator(e->op))
{
m_expect_value = true;
e->value->accept(this);
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()));
}
return;
}
evttypes("", m_last_node_evttypes);
}
void filter_evttype_resolver::visit(ast::unary_check_expr* e)
{
m_last_node_evttypes.clear();
evttypes("", m_last_node_evttypes);
}
void filter_evttype_resolver::visit(ast::value_expr* e)
{
m_last_node_evttypes.clear();
if (m_expect_value)
{
evttypes(e->value, m_last_node_evttypes);
return;
}
evttypes("", m_last_node_evttypes);
}
void filter_evttype_resolver::visit(ast::list_expr* e)
{
m_last_node_evttypes.clear();
if (m_expect_value)
{
for (auto &v : e->values)
{
evttypes(v, m_last_node_evttypes);
}
return;
}
evttypes("", m_last_node_evttypes);
}

View File

@ -0,0 +1,68 @@
/*
Copyright (C) 2022 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.
*/
#pragma once
#include <filter/parser.h>
#include <string>
#include <set>
#include <memory>
/*!
\brief Helper class for finding event types
*/
class filter_evttype_resolver: private libsinsp::filter::ast::expr_visitor
{
public:
/*!
\brief Collects the evttypes related to the provided event name.
The event types are inserted in the set provided as parameter.
The set is not cleared before inserting the elements.
\param evtname The event name used to search event types. If an empty
string is passed, all the available evttypes are collected
\param out The set to be filled with the evttypes
*/
void evttypes(std::string evtname, std::set<uint16_t>& out);
/*!
\brief Visits a filter AST and collects all the evttypes for which
the filter expression can be evaluated as true. The event types are
inserted in the set provided as parameter. The set is not cleared before
inserting the elements.
\param filter The filter AST to be explored
\param out The set to be filled with the evttypes
*/
void evttypes(libsinsp::filter::ast::expr* filter, std::set<uint16_t>& out);
/*!
\brief Overloaded version of evttypes() that supports filters wrapped
in shared pointers
*/
void evttypes(std::shared_ptr<libsinsp::filter::ast::expr> filter,
std::set<uint16_t>& out);
private:
void visit(libsinsp::filter::ast::and_expr* e) override;
void visit(libsinsp::filter::ast::or_expr* e) override;
void visit(libsinsp::filter::ast::not_expr* e) override;
void visit(libsinsp::filter::ast::value_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::binary_check_expr* e) override;
bool m_expect_value;
std::set<uint16_t> m_last_node_evttypes;
};