mirror of
https://github.com/falcosecurity/falco.git
synced 2025-09-16 14:58:31 +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