diff --git a/userspace/engine/CMakeLists.txt b/userspace/engine/CMakeLists.txt index 8218a4d6..30c2fef4 100644 --- a/userspace/engine/CMakeLists.txt +++ b/userspace/engine/CMakeLists.txt @@ -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) diff --git a/userspace/engine/filter_evttype_resolver.cpp b/userspace/engine/filter_evttype_resolver.cpp new file mode 100644 index 00000000..cc8befd7 --- /dev/null +++ b/userspace/engine/filter_evttype_resolver.cpp @@ -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 + +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& 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& 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 filter, set& 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 nodetypes; + evttypes("", nodetypes); + m_last_node_evttypes.clear(); + for (auto &c : e->children) + { + set 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 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 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 all_types; + set 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); +} diff --git a/userspace/engine/filter_evttype_resolver.h b/userspace/engine/filter_evttype_resolver.h new file mode 100644 index 00000000..c55dbe07 --- /dev/null +++ b/userspace/engine/filter_evttype_resolver.h @@ -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 +#include +#include +#include + +/*! + \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& 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& out); + + /*! + \brief Overloaded version of evttypes() that supports filters wrapped + in shared pointers + */ + void evttypes(std::shared_ptr filter, + std::set& 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 m_last_node_evttypes; +};