mirror of
https://github.com/falcosecurity/falco.git
synced 2025-09-15 22:38:26 +00:00
refactor(userspace/libsinsp): support new filter ast structure in falco engine
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
@@ -17,9 +17,11 @@ limitations under the License.
|
||||
|
||||
#include "filter_details_resolver.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace libsinsp::filter;
|
||||
|
||||
std::string get_field_name(const std::string& name, const std::string& arg)
|
||||
static inline std::string get_field_name(const std::string& name, const std::string& arg)
|
||||
{
|
||||
std::string fld = name;
|
||||
if (!arg.empty())
|
||||
@@ -41,30 +43,22 @@ void filter_details::reset()
|
||||
void filter_details_resolver::run(ast::expr* filter, filter_details& details)
|
||||
{
|
||||
visitor v(details);
|
||||
// note: we may have ASTs composed on only one macro ref
|
||||
v.m_expect_macro = true;
|
||||
filter->accept(&v);
|
||||
}
|
||||
|
||||
void filter_details_resolver::visitor::visit(ast::and_expr* e)
|
||||
{
|
||||
m_expect_macro = false;
|
||||
for(size_t i = 0; i < e->children.size(); i++)
|
||||
{
|
||||
m_expect_macro = true;
|
||||
e->children[i]->accept(this);
|
||||
m_expect_macro = false;
|
||||
}
|
||||
}
|
||||
|
||||
void filter_details_resolver::visitor::visit(ast::or_expr* e)
|
||||
{
|
||||
m_expect_macro = false;
|
||||
for(size_t i = 0; i < e->children.size(); i++)
|
||||
{
|
||||
m_expect_macro = true;
|
||||
e->children[i]->accept(this);
|
||||
m_expect_macro = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,36 +93,56 @@ void filter_details_resolver::visitor::visit(ast::list_expr* e)
|
||||
|
||||
void filter_details_resolver::visitor::visit(ast::binary_check_expr* e)
|
||||
{
|
||||
m_expect_macro = false;
|
||||
m_details.fields.insert(get_field_name(e->field, e->arg));
|
||||
m_last_node_field_name.clear();
|
||||
e->left->accept(this);
|
||||
if (m_last_node_field_name.empty())
|
||||
{
|
||||
throw std::runtime_error("can't find field info in binary check expression");
|
||||
}
|
||||
m_details.fields.insert(m_last_node_field_name);
|
||||
m_details.operators.insert(e->op);
|
||||
m_expect_list = true;
|
||||
m_expect_evtname = e->field == "evt.type" || e->field == "evt.asynctype";
|
||||
e->value->accept(this);
|
||||
m_expect_evtname = m_last_node_field_name == "evt.type" || m_last_node_field_name == "evt.asynctype";
|
||||
e->right->accept(this);
|
||||
m_expect_evtname = false;
|
||||
m_expect_list = false;
|
||||
}
|
||||
|
||||
void filter_details_resolver::visitor::visit(ast::unary_check_expr* e)
|
||||
{
|
||||
m_expect_macro = false;
|
||||
m_details.fields.insert(get_field_name(e->field, e->arg));
|
||||
m_last_node_field_name.clear();
|
||||
e->left->accept(this);
|
||||
if (m_last_node_field_name.empty())
|
||||
{
|
||||
throw std::runtime_error("can't find field info in unary check expression");
|
||||
}
|
||||
m_details.fields.insert(m_last_node_field_name);
|
||||
m_details.operators.insert(e->op);
|
||||
}
|
||||
|
||||
void filter_details_resolver::visitor::visit(ast::identifier_expr* e)
|
||||
{
|
||||
// todo(jasondellaluce): maybe throw an error if we encounter an unknown macro?
|
||||
if(m_details.known_macros.find(e->identifier) != m_details.known_macros.end())
|
||||
{
|
||||
m_details.macros.insert(e->identifier);
|
||||
}
|
||||
}
|
||||
|
||||
void filter_details_resolver::visitor::visit(ast::value_expr* e)
|
||||
{
|
||||
if (m_expect_macro)
|
||||
{
|
||||
if(m_details.known_macros.find(e->value) != m_details.known_macros.end())
|
||||
{
|
||||
m_details.macros.insert(e->value);
|
||||
}
|
||||
// todo(jasondellaluce): should we throw an error if we
|
||||
// encounter an unknown macro?
|
||||
}
|
||||
else if (m_expect_evtname)
|
||||
if (m_expect_evtname)
|
||||
{
|
||||
m_details.evtnames.insert(e->value);
|
||||
}
|
||||
}
|
||||
|
||||
void filter_details_resolver::visitor::visit(ast::field_expr* e)
|
||||
{
|
||||
m_last_node_field_name = get_field_name(e->field, e->arg);
|
||||
}
|
||||
|
||||
void filter_details_resolver::visitor::visit(ast::field_transformer_expr* e)
|
||||
{
|
||||
e->value->accept(this);
|
||||
}
|
||||
|
@@ -60,22 +60,25 @@ private:
|
||||
explicit visitor(filter_details& details) :
|
||||
m_details(details),
|
||||
m_expect_list(false),
|
||||
m_expect_macro(false),
|
||||
m_expect_evtname(false) {}
|
||||
m_expect_evtname(false),
|
||||
m_last_node_field_name() {}
|
||||
visitor(visitor&&) = default;
|
||||
visitor(const visitor&) = delete;
|
||||
|
||||
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::identifier_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;
|
||||
void visit(libsinsp::filter::ast::field_expr* e) override;
|
||||
void visit(libsinsp::filter::ast::field_transformer_expr* e) override;
|
||||
|
||||
filter_details& m_details;
|
||||
bool m_expect_list;
|
||||
bool m_expect_macro;
|
||||
bool m_expect_evtname;
|
||||
std::string m_last_node_field_name;
|
||||
};
|
||||
};
|
||||
|
@@ -101,8 +101,6 @@ void filter_macro_resolver::visitor::visit(ast::list_expr* e)
|
||||
|
||||
void filter_macro_resolver::visitor::visit(ast::binary_check_expr* e)
|
||||
{
|
||||
// avoid exploring checks, so that we can be sure that each
|
||||
// value_expr* node visited is a macro identifier
|
||||
m_node_substitute = nullptr;
|
||||
}
|
||||
|
||||
@@ -113,10 +111,22 @@ void filter_macro_resolver::visitor::visit(ast::unary_check_expr* e)
|
||||
|
||||
void filter_macro_resolver::visitor::visit(ast::value_expr* e)
|
||||
{
|
||||
// we are supposed to get here only in case
|
||||
// of identier-only children from either a 'not',
|
||||
// an 'and' or an 'or'.
|
||||
const auto& macro = m_macros.find(e->value);
|
||||
m_node_substitute = nullptr;
|
||||
}
|
||||
|
||||
void filter_macro_resolver::visitor::visit(ast::field_expr* e)
|
||||
{
|
||||
m_node_substitute = nullptr;
|
||||
}
|
||||
|
||||
void filter_macro_resolver::visitor::visit(ast::field_transformer_expr* e)
|
||||
{
|
||||
m_node_substitute = nullptr;
|
||||
}
|
||||
|
||||
void filter_macro_resolver::visitor::visit(ast::identifier_expr* e)
|
||||
{
|
||||
const auto& macro = m_macros.find(e->identifier);
|
||||
if (macro != m_macros.end() && macro->second) // skip null-ptr macros
|
||||
{
|
||||
// note: checks for loop detection
|
||||
@@ -126,7 +136,7 @@ void filter_macro_resolver::visitor::visit(ast::value_expr* e)
|
||||
auto msg = "reference loop in macro '" + macro->first + "'";
|
||||
m_errors.push_back({msg, e->get_pos()});
|
||||
m_node_substitute = nullptr;
|
||||
m_unknown_macros.push_back({e->value, e->get_pos()});
|
||||
m_unknown_macros.push_back({e->identifier, e->get_pos()});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -140,12 +150,12 @@ void filter_macro_resolver::visitor::visit(ast::value_expr* e)
|
||||
{
|
||||
m_node_substitute = std::move(new_node);
|
||||
}
|
||||
m_resolved_macros.push_back({e->value, e->get_pos()});
|
||||
m_resolved_macros.push_back({e->identifier, e->get_pos()});
|
||||
m_macros_path.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_node_substitute = nullptr;
|
||||
m_unknown_macros.push_back({e->value, e->get_pos()});
|
||||
m_unknown_macros.push_back({e->identifier, e->get_pos()});
|
||||
}
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ class filter_macro_resolver
|
||||
according with all the definitions added through set_macro(),
|
||||
by replacing the reference with a clone of the macro AST.
|
||||
\param filter The filter AST to be processed. Note that the pointer
|
||||
is passed by reference and be modified in order to apply
|
||||
is passed by reference and be transformed in order to apply
|
||||
the substutions. In that case, the old pointer is owned by this
|
||||
class and is deleted automatically.
|
||||
\return true if at least one of the defined macros is resolved
|
||||
@@ -121,10 +121,13 @@ class filter_macro_resolver
|
||||
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::identifier_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;
|
||||
void visit(libsinsp::filter::ast::field_expr* e) override;
|
||||
void visit(libsinsp::filter::ast::field_transformer_expr* e) override;
|
||||
};
|
||||
|
||||
std::vector<value_info> m_errors;
|
||||
|
@@ -49,14 +49,22 @@ bool filter_warning_resolver::run(
|
||||
void filter_warning_resolver::visitor::visit(
|
||||
libsinsp::filter::ast::binary_check_expr* e)
|
||||
{
|
||||
if (is_unsafe_field(e->field) && is_equality_operator(e->op))
|
||||
m_last_node_is_unsafe_field = false;
|
||||
e->left->accept(this);
|
||||
if (m_last_node_is_unsafe_field && is_equality_operator(e->op))
|
||||
{
|
||||
m_is_equality_check = true;
|
||||
e->value->accept(this);
|
||||
e->right->accept(this);
|
||||
m_is_equality_check = false;
|
||||
}
|
||||
}
|
||||
|
||||
void filter_warning_resolver::visitor::visit(
|
||||
libsinsp::filter::ast::field_expr* e)
|
||||
{
|
||||
m_last_node_is_unsafe_field = is_unsafe_field(e->field);
|
||||
}
|
||||
|
||||
void filter_warning_resolver::visitor::visit(
|
||||
libsinsp::filter::ast::value_expr* e)
|
||||
{
|
||||
|
@@ -49,17 +49,22 @@ public:
|
||||
private:
|
||||
struct visitor : public libsinsp::filter::ast::base_expr_visitor
|
||||
{
|
||||
visitor(): m_is_equality_check(false), m_warnings(nullptr) {}
|
||||
visitor():
|
||||
m_is_equality_check(false),
|
||||
m_last_node_is_unsafe_field(false),
|
||||
m_warnings(nullptr) {}
|
||||
visitor(visitor&&) = default;
|
||||
visitor& operator = (visitor&&) = default;
|
||||
visitor(const visitor&) = delete;
|
||||
visitor& operator = (const visitor&) = delete;
|
||||
|
||||
bool m_is_equality_check;
|
||||
bool m_last_node_is_unsafe_field;
|
||||
std::set<falco::load_result::warning_code>* m_warnings;
|
||||
|
||||
void visit(libsinsp::filter::ast::value_expr* e) override;
|
||||
void visit(libsinsp::filter::ast::list_expr* e) override;
|
||||
void visit(libsinsp::filter::ast::binary_check_expr* e) override;
|
||||
void visit(libsinsp::filter::ast::field_expr* e) override;
|
||||
};
|
||||
};
|
||||
|
Reference in New Issue
Block a user