mirror of
https://github.com/falcosecurity/falco.git
synced 2025-09-15 06:19:12 +00:00
new(engine): add rule filter macro-resolver
This is a first step towards porting the rule filter building logic that is currently implemented in Lua. filter_macro_resolver uses the newly introduced AST constructs from libsinsp, and allow manipulating filter ASTs to resolve/replace macro references. This is meant to be used at boot time by the rule loader (which we still want to maintain implemented in Lua for now). Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
136
userspace/engine/filter_macro_resolver.cpp
Normal file
136
userspace/engine/filter_macro_resolver.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
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_macro_resolver.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace libsinsp::filter;
|
||||
|
||||
bool filter_macro_resolver::run(libsinsp::filter::ast::expr*& filter)
|
||||
{
|
||||
m_unknown_macros.clear();
|
||||
m_resolved_macros.clear();
|
||||
m_last_node_changed = false;
|
||||
m_last_node = filter;
|
||||
filter->accept(this);
|
||||
if (m_last_node_changed)
|
||||
{
|
||||
delete filter;
|
||||
filter = m_last_node;
|
||||
}
|
||||
return !m_resolved_macros.empty();
|
||||
}
|
||||
|
||||
void filter_macro_resolver::define_macro(
|
||||
string name,
|
||||
shared_ptr<libsinsp::filter::ast::expr> macro)
|
||||
{
|
||||
auto it = m_macros.find(name);
|
||||
m_macros[name] = macro;
|
||||
}
|
||||
|
||||
set<string>& filter_macro_resolver::get_unknown_macros()
|
||||
{
|
||||
return m_unknown_macros;
|
||||
}
|
||||
|
||||
set<string>& filter_macro_resolver::get_resolved_macros()
|
||||
{
|
||||
return m_resolved_macros;
|
||||
}
|
||||
|
||||
void filter_macro_resolver::visit(ast::and_expr* e)
|
||||
{
|
||||
for (size_t i = 0; i < e->children.size(); i++)
|
||||
{
|
||||
e->children[i]->accept(this);
|
||||
if (m_last_node_changed)
|
||||
{
|
||||
delete e->children[i];
|
||||
e->children[i] = m_last_node;
|
||||
}
|
||||
}
|
||||
m_last_node = e;
|
||||
m_last_node_changed = false;
|
||||
}
|
||||
|
||||
void filter_macro_resolver::visit(ast::or_expr* e)
|
||||
{
|
||||
for (size_t i = 0; i < e->children.size(); i++)
|
||||
{
|
||||
e->children[i]->accept(this);
|
||||
if (m_last_node_changed)
|
||||
{
|
||||
delete e->children[i];
|
||||
e->children[i] = m_last_node;
|
||||
}
|
||||
}
|
||||
m_last_node = e;
|
||||
m_last_node_changed = false;
|
||||
}
|
||||
|
||||
void filter_macro_resolver::visit(ast::not_expr* e)
|
||||
{
|
||||
e->child->accept(this);
|
||||
if (m_last_node_changed)
|
||||
{
|
||||
delete e->child;
|
||||
e->child = m_last_node;
|
||||
}
|
||||
m_last_node = e;
|
||||
m_last_node_changed = false;
|
||||
}
|
||||
|
||||
void filter_macro_resolver::visit(ast::list_expr* e)
|
||||
{
|
||||
m_last_node = e;
|
||||
m_last_node_changed = false;
|
||||
}
|
||||
|
||||
void filter_macro_resolver::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_last_node = e;
|
||||
m_last_node_changed = false;
|
||||
}
|
||||
|
||||
void filter_macro_resolver::visit(ast::unary_check_expr* e)
|
||||
{
|
||||
m_last_node = e;
|
||||
m_last_node_changed = false;
|
||||
}
|
||||
|
||||
void filter_macro_resolver::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'.
|
||||
auto macro = m_macros.find(e->value);
|
||||
if (macro != m_macros.end())
|
||||
{
|
||||
// todo(jasondellaluce): should we visit down the new resolved AST too?
|
||||
m_last_node = ast::clone((*macro).second.get());
|
||||
m_last_node_changed = true;
|
||||
m_resolved_macros.insert(e->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_last_node = e;
|
||||
m_last_node_changed = false;
|
||||
m_unknown_macros.insert(e->value);
|
||||
}
|
||||
}
|
87
userspace/engine/filter_macro_resolver.h
Normal file
87
userspace/engine/filter_macro_resolver.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
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 <map>
|
||||
#include <memory>
|
||||
|
||||
/*!
|
||||
\brief Helper class for substituting and resolving macro
|
||||
refereces in parsed filters.
|
||||
*/
|
||||
class filter_macro_resolver: private libsinsp::filter::ast::expr_visitor
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
\brief Visits a filter AST and substitutes macro references
|
||||
according with all the definitions added through define_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
|
||||
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
|
||||
*/
|
||||
bool run(libsinsp::filter::ast::expr*& filter);
|
||||
|
||||
/*!
|
||||
\brief Defines a new macro to be substituted in filters. If called
|
||||
multiple times for the same macro name, the previous definition
|
||||
gets overridden.
|
||||
\param name The name of the macro.
|
||||
\param macro The AST of the macro.
|
||||
*/
|
||||
void define_macro(
|
||||
std::string name,
|
||||
std::shared_ptr<libsinsp::filter::ast::expr> macro);
|
||||
|
||||
/*!
|
||||
\brief Returns a set containing the names of all the macros
|
||||
substituted during the last invocation of run(). Should be
|
||||
non-empty if the last invocation of run() returned true.
|
||||
*/
|
||||
std::set<std::string>& get_resolved_macros();
|
||||
|
||||
/*!
|
||||
\brief Returns a set containing the names of all the macros
|
||||
that remained unresolved during the last invocation of run().
|
||||
A macro remains unresolved if it is found inside the processed
|
||||
filter but it was not defined with define_macro();
|
||||
*/
|
||||
std::set<std::string>& get_unknown_macros();
|
||||
|
||||
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_last_node_changed;
|
||||
libsinsp::filter::ast::expr* m_last_node;
|
||||
std::set<std::string> m_unknown_macros;
|
||||
std::set<std::string> m_resolved_macros;
|
||||
std::map<
|
||||
std::string,
|
||||
std::shared_ptr<libsinsp::filter::ast::expr>
|
||||
> m_macros;
|
||||
};
|
Reference in New Issue
Block a user