mirror of
https://github.com/falcosecurity/falco.git
synced 2025-09-18 07:51:12 +00:00
cleanup(userspace/engine): drop filtr_evttype_resolver
Its logic was ported into libsinsp in:
3d8550e70e
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2023 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 <gtest/gtest.h>
|
||||
#include <engine/filter_evttype_resolver.h>
|
||||
#include <sinsp.h>
|
||||
#include <filter/parser.h>
|
||||
|
||||
#define ASSERT_FILTER_EQ(a, b) { ASSERT_EQ(get_filter_set(a), get_filter_set(b)); }
|
||||
|
||||
std::set<uint16_t> get_filter_set(const string &fltstr)
|
||||
{
|
||||
set<uint16_t> actual;
|
||||
auto f = libsinsp::filter::parser(fltstr).parse();
|
||||
filter_evttype_resolver().evttypes(f.get(), actual);
|
||||
return actual;
|
||||
}
|
||||
|
||||
std::set<uint16_t> get_set_difference(std::set<uint16_t> exclude_set = {})
|
||||
{
|
||||
std::set<uint16_t> set_difference = {};
|
||||
|
||||
for(uint32_t i = PPME_GENERIC_E; i < PPM_EVENT_MAX; i++)
|
||||
{
|
||||
/* Skip events that are unused. */
|
||||
if(sinsp::is_unused_event(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(exclude_set.find(i) == exclude_set.end())
|
||||
{
|
||||
set_difference.insert(i);
|
||||
}
|
||||
}
|
||||
return set_difference;
|
||||
}
|
||||
|
||||
TEST(EvtTypeResolver, check_openat)
|
||||
{
|
||||
std::set<uint16_t> openat_only{
|
||||
PPME_SYSCALL_OPENAT_E, PPME_SYSCALL_OPENAT_X,
|
||||
PPME_SYSCALL_OPENAT_2_E, PPME_SYSCALL_OPENAT_2_X};
|
||||
|
||||
std::set<uint16_t> not_openat = get_set_difference(openat_only);
|
||||
|
||||
/* `openat_only` */
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat"), openat_only);
|
||||
ASSERT_EQ(get_filter_set("evt.type = openat"), openat_only);
|
||||
ASSERT_EQ(get_filter_set("not evt.type != openat"), openat_only);
|
||||
ASSERT_EQ(get_filter_set("not not evt.type = openat"), openat_only);
|
||||
ASSERT_EQ(get_filter_set("not not not not evt.type = openat"), openat_only);
|
||||
ASSERT_EQ(get_filter_set("evt.type in (openat)"), openat_only);
|
||||
ASSERT_EQ(get_filter_set("not (not evt.type=openat)"), openat_only);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat and proc.name=nginx"), openat_only);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat and not proc.name=nginx"), openat_only);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat and (proc.name=nginx)"), openat_only);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat and not (evt.type=close and proc.name=nginx)"), openat_only);
|
||||
|
||||
/* `not_openat` */
|
||||
ASSERT_EQ(get_filter_set("evt.type!=openat"), not_openat);
|
||||
ASSERT_EQ(get_filter_set("not not not evt.type = openat"), not_openat);
|
||||
ASSERT_EQ(get_filter_set("not evt.type=openat"), not_openat);
|
||||
ASSERT_EQ(get_filter_set("evt.type=close or evt.type!=openat"), not_openat);
|
||||
}
|
||||
|
||||
TEST(EvtTypeResolver, check_openat_or_close)
|
||||
{
|
||||
std::set<uint16_t> openat_close_only{
|
||||
PPME_SYSCALL_OPENAT_E, PPME_SYSCALL_OPENAT_X,
|
||||
PPME_SYSCALL_OPENAT_2_E, PPME_SYSCALL_OPENAT_2_X,
|
||||
PPME_SYSCALL_CLOSE_E, PPME_SYSCALL_CLOSE_X};
|
||||
|
||||
std::set<uint16_t> not_openat_close = get_set_difference(openat_close_only);
|
||||
|
||||
/* `openat_close_only` */
|
||||
ASSERT_EQ(get_filter_set("evt.type in (openat, close)"), openat_close_only);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat or evt.type=close"), openat_close_only);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat or (evt.type=close and proc.name=nginx)"), openat_close_only);
|
||||
ASSERT_EQ(get_filter_set("evt.type=close or (evt.type=openat and proc.name=nginx)"), openat_close_only);
|
||||
|
||||
/* not `not_openat_close` */
|
||||
ASSERT_EQ(get_filter_set("not evt.type in (openat, close)"), not_openat_close);
|
||||
ASSERT_EQ(get_filter_set("not not not evt.type in (openat, close)"), not_openat_close);
|
||||
ASSERT_EQ(get_filter_set("evt.type!=openat and evt.type!=close"), not_openat_close);
|
||||
}
|
||||
|
||||
TEST(EvtTypeResolver, check_all_events)
|
||||
{
|
||||
/* Computed as a difference of the empty set */
|
||||
std::set<uint16_t> all_events = get_set_difference();
|
||||
|
||||
ASSERT_EQ(get_filter_set("evt.type!=openat or evt.type!=close"), all_events);
|
||||
ASSERT_EQ(get_filter_set("proc.name=nginx"), all_events);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat or proc.name=nginx"), all_events);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat or (proc.name=nginx)"), all_events);
|
||||
ASSERT_EQ(get_filter_set("(evt.type=openat) or proc.name=nginx"), all_events);
|
||||
ASSERT_EQ(get_filter_set("evt.type=close or not (evt.type=openat and proc.name=nginx)"), all_events);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat or not (evt.type=close and proc.name=nginx)"), all_events);
|
||||
}
|
||||
|
||||
TEST(EvtTypeResolver, check_no_events)
|
||||
{
|
||||
std::set<uint16_t> no_events = {};
|
||||
|
||||
ASSERT_EQ(get_filter_set("evt.type=close and evt.type=openat"), no_events);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat and (evt.type=close and proc.name=nginx)"), no_events);
|
||||
ASSERT_EQ(get_filter_set("evt.type=openat and (evt.type=close)"), no_events);
|
||||
}
|
||||
|
||||
TEST(EvtTypeResolver, check_properties)
|
||||
{
|
||||
std::set<uint16_t> no_events = {};
|
||||
|
||||
// see: https://github.com/falcosecurity/libs/pull/854#issuecomment-1411151732
|
||||
ASSERT_FILTER_EQ(
|
||||
"evt.type in (connect, execve, accept, mmap, container) and not (proc.name=cat and evt.type=mmap)",
|
||||
"evt.type in (accept, connect, container, execve, mmap)");
|
||||
ASSERT_EQ(get_filter_set("(evt.type=mmap and not evt.type=mmap)"), no_events);
|
||||
|
||||
// defining algebraic base sets
|
||||
std::string zerof = "(evt.type in ())"; ///< "zero"-set: no evt type should matches the filter
|
||||
std::string onef = "(evt.type exists)"; ///< "one"-set: all evt types should match the filter
|
||||
std::string neutral1 = "(proc.name=cat)"; ///< "neutral"-sets: evt types are not checked in the filter
|
||||
std::string neutral2 = "(not proc.name=cat)";
|
||||
ASSERT_FILTER_EQ(onef, neutral1);
|
||||
ASSERT_FILTER_EQ(onef, neutral2);
|
||||
|
||||
// algebraic set properties
|
||||
// 1' = 0
|
||||
ASSERT_FILTER_EQ("not " + onef, zerof);
|
||||
// 0' = 1
|
||||
ASSERT_FILTER_EQ("not " + zerof, onef);
|
||||
// (A')' = A
|
||||
ASSERT_FILTER_EQ("evt.type=mmap", "not (not evt.type=mmap)");
|
||||
// A * A' = 0
|
||||
ASSERT_EQ(get_filter_set(zerof), no_events);
|
||||
// A + A' = 1
|
||||
ASSERT_FILTER_EQ("evt.type=mmap or not evt.type=mmap", onef);
|
||||
ASSERT_FILTER_EQ("evt.type=mmap or not evt.type=mmap", neutral1);
|
||||
ASSERT_FILTER_EQ("evt.type=mmap or not evt.type=mmap", neutral2);
|
||||
// 0 * 1 = 0
|
||||
ASSERT_FILTER_EQ(zerof + " and " + onef, zerof);
|
||||
ASSERT_FILTER_EQ(zerof + " and " + neutral1, zerof);
|
||||
ASSERT_FILTER_EQ(zerof + " and " + neutral2, zerof);
|
||||
// 0 + 1 = 1
|
||||
ASSERT_FILTER_EQ(zerof + " or " + onef, onef);
|
||||
ASSERT_FILTER_EQ(zerof + " or " + neutral1, onef);
|
||||
ASSERT_FILTER_EQ(zerof + " or " + neutral2, onef);
|
||||
// A * 0 = 0
|
||||
ASSERT_FILTER_EQ("evt.type=mmap and " + zerof, zerof);
|
||||
// A * 1 = A
|
||||
ASSERT_FILTER_EQ("evt.type=mmap and " + onef, "evt.type=mmap");
|
||||
ASSERT_FILTER_EQ("evt.type=mmap and " + neutral1, "evt.type=mmap");
|
||||
ASSERT_FILTER_EQ("evt.type=mmap and " + neutral2, "evt.type=mmap");
|
||||
// A + 0 = A
|
||||
ASSERT_FILTER_EQ("evt.type=mmap or " + zerof, "evt.type=mmap");
|
||||
// A + 1 = 1
|
||||
ASSERT_FILTER_EQ("evt.type=mmap or " + onef, onef);
|
||||
ASSERT_FILTER_EQ("evt.type=mmap or " + neutral1, onef);
|
||||
ASSERT_FILTER_EQ("evt.type=mmap or " + neutral2, onef);
|
||||
// A + A = A
|
||||
ASSERT_FILTER_EQ("evt.type=mmap or evt.type=mmap", "evt.type=mmap");
|
||||
// A * A = A
|
||||
ASSERT_FILTER_EQ("evt.type=mmap and evt.type=mmap", "evt.type=mmap");
|
||||
|
||||
// de morgan's laws
|
||||
ASSERT_FILTER_EQ(
|
||||
"not (proc.name=cat or evt.type=mmap)",
|
||||
"not proc.name=cat and not evt.type=mmap");
|
||||
ASSERT_FILTER_EQ(
|
||||
"not (proc.name=cat or fd.type=file)",
|
||||
"not proc.name=cat and not fd.type=file");
|
||||
ASSERT_FILTER_EQ(
|
||||
"not (evt.type=execve or evt.type=mmap)",
|
||||
"not evt.type=execve and not evt.type=mmap");
|
||||
ASSERT_FILTER_EQ(
|
||||
"not (evt.type=mmap or evt.type=mmap)",
|
||||
"not evt.type=mmap and not evt.type=mmap");
|
||||
ASSERT_FILTER_EQ(
|
||||
"not (proc.name=cat and evt.type=mmap)",
|
||||
"not proc.name=cat or not evt.type=mmap");
|
||||
ASSERT_FILTER_EQ(
|
||||
"not (proc.name=cat and fd.type=file)",
|
||||
"not proc.name=cat or not fd.type=file");
|
||||
ASSERT_FILTER_EQ(
|
||||
"not (evt.type=execve and evt.type=mmap)",
|
||||
"not evt.type=execve or not evt.type=mmap");
|
||||
ASSERT_FILTER_EQ(
|
||||
"not (evt.type=mmap and evt.type=mmap)",
|
||||
"not evt.type=mmap or not evt.type=mmap");
|
||||
|
||||
// negation isomorphism
|
||||
ASSERT_FILTER_EQ("not evt.type=mmap", "evt.type!=mmap");
|
||||
ASSERT_FILTER_EQ("not proc.name=cat", "proc.name!=cat");
|
||||
|
||||
// commutative property (and)
|
||||
ASSERT_FILTER_EQ("evt.type=execve and evt.type=mmap", "evt.type=mmap and evt.type=execve");
|
||||
ASSERT_FILTER_EQ("not (evt.type=execve and evt.type=mmap)", "not (evt.type=mmap and evt.type=execve)");
|
||||
ASSERT_FILTER_EQ("not evt.type=execve and not evt.type=mmap", "not evt.type=mmap and not evt.type=execve");
|
||||
ASSERT_FILTER_EQ("proc.name=cat and evt.type=mmap", "evt.type=mmap and proc.name=cat");
|
||||
ASSERT_FILTER_EQ("not (proc.name=cat and evt.type=mmap)", "not (evt.type=mmap and proc.name=cat)");
|
||||
ASSERT_FILTER_EQ("not proc.name=cat and not evt.type=mmap", "not evt.type=mmap and not proc.name=cat");
|
||||
ASSERT_FILTER_EQ("proc.name=cat and fd.type=file", "fd.type=file and proc.name=cat");
|
||||
ASSERT_FILTER_EQ("not (proc.name=cat and fd.type=file)", "not (fd.type=file and proc.name=cat)");
|
||||
ASSERT_FILTER_EQ("not proc.name=cat and not fd.type=file", "not fd.type=file and not proc.name=cat");
|
||||
|
||||
// commutative property (or)
|
||||
ASSERT_FILTER_EQ("evt.type=execve or evt.type=mmap", "evt.type=mmap or evt.type=execve");
|
||||
ASSERT_FILTER_EQ("not (evt.type=execve or evt.type=mmap)", "not (evt.type=mmap or evt.type=execve)");
|
||||
ASSERT_FILTER_EQ("not evt.type=execve or not evt.type=mmap", "not evt.type=mmap or not evt.type=execve");
|
||||
ASSERT_FILTER_EQ("proc.name=cat or evt.type=mmap", "evt.type=mmap or proc.name=cat");
|
||||
ASSERT_FILTER_EQ("not (proc.name=cat or evt.type=mmap)", "not (evt.type=mmap or proc.name=cat)");
|
||||
ASSERT_FILTER_EQ("not proc.name=cat or not evt.type=mmap", "not evt.type=mmap or not proc.name=cat");
|
||||
ASSERT_FILTER_EQ("proc.name=cat or fd.type=file", "fd.type=file or proc.name=cat");
|
||||
ASSERT_FILTER_EQ("not (proc.name=cat or fd.type=file)", "not (fd.type=file or proc.name=cat)");
|
||||
ASSERT_FILTER_EQ("not proc.name=cat or not fd.type=file", "not fd.type=file or not proc.name=cat");
|
||||
}
|
@@ -19,7 +19,6 @@ set(FALCO_ENGINE_SOURCE_FILES
|
||||
evttype_index_ruleset.cpp
|
||||
formats.cpp
|
||||
filter_macro_resolver.cpp
|
||||
filter_evttype_resolver.cpp
|
||||
filter_warning_resolver.cpp
|
||||
stats_manager.cpp
|
||||
rule_loader.cpp
|
||||
|
@@ -1,253 +0,0 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
/**
|
||||
* Given a rule filtering condition (in AST form), the following logic is
|
||||
* responsible of returning the set of event types for which the
|
||||
* filtering condition can be evaluated to true.
|
||||
*
|
||||
* This implementation is based on the boolean algebraic properties of sets
|
||||
* and works as follows depending on the type of nodes:
|
||||
* - the evt types of "and" nodes are the intersection set of the evt types of
|
||||
* their children nodes.
|
||||
* - the evt types of "or" nodes are the union set of the evt types of
|
||||
* their children nodes.
|
||||
* - the evt types of leaf nodes (e.g. "evt.type=open" or "proc.name=cat")
|
||||
* depend on the type of check:
|
||||
* * checks based on evt types (e.g. =xxx, != xxx, in (xxx)) give a clear
|
||||
* definition of the matched event types. The "evt.type exists" check
|
||||
* matches every evt type.
|
||||
* * checks non-related to evt types are neutral and match all evt types
|
||||
* (e.g. proc.name=cat).
|
||||
*
|
||||
* The tricky part is handling negation (e.g. "not evt.type=open").
|
||||
* Given a set of event types, its negation is the difference between the
|
||||
* "set of all events" and the set (e.g. all types but not the ones in the set).
|
||||
* Reasonably, negation should not affect checks unrelated to evt types (e.g.
|
||||
* "proc.name=cat" is equivalent to "not proc.name=cat" for evt type matching).
|
||||
* The knowledge of whether a set of event types should be negated or not
|
||||
* can't be handled nor propagated in "and" and "or" nodes. Since rules'
|
||||
* conditions are boolean expression, the solution is to use De Morgan's Laws
|
||||
* to push the negation evaluations down to the leaf nodes as follows:
|
||||
* - "not (A and B)" is evaluated as "not A or not B"
|
||||
* - "not (A or B)" is evaluated as "not A and not B"
|
||||
* By happening only on leaf nodes, the set of matching event types can safely
|
||||
* be constructed and negated depending on the different cases.
|
||||
*/
|
||||
|
||||
|
||||
using namespace libsinsp::filter;
|
||||
|
||||
extern sinsp_evttables g_infotables;
|
||||
|
||||
static bool is_evttype_operator(const std::string& op)
|
||||
{
|
||||
return op == "==" || op == "=" || op == "!=" || op == "in";
|
||||
}
|
||||
|
||||
size_t falco_event_types::get_ppm_event_max()
|
||||
{
|
||||
return PPM_EVENT_MAX;
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::inversion(falco_event_types& types)
|
||||
{
|
||||
// we don't invert "neutral" checks
|
||||
if (m_last_node_has_evttypes)
|
||||
{
|
||||
types = m_all_events.diff(types);
|
||||
}
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::try_inversion(falco_event_types& types)
|
||||
{
|
||||
if (m_inside_negation)
|
||||
{
|
||||
inversion(types);
|
||||
}
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::evttypes(const std::string& evtname, falco_event_types& out)
|
||||
{
|
||||
for(uint16_t i = PPME_GENERIC_E; i < PPM_EVENT_MAX; i++)
|
||||
{
|
||||
// Skip unused events
|
||||
if(sinsp::is_unused_event(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fetch event names associated with event id
|
||||
const auto evtnames = m_inspector.get_events_names({i});
|
||||
for (const auto& name : evtnames)
|
||||
{
|
||||
// Skip events not matching the requested evtname
|
||||
if(evtname.empty() || name == evtname)
|
||||
{
|
||||
out.insert(i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::evttypes(
|
||||
ast::expr* filter,
|
||||
std::set<uint16_t>& out) const
|
||||
{
|
||||
visitor v;
|
||||
filter->accept(&v);
|
||||
v.m_last_node_evttypes.for_each([&out](uint16_t val){out.insert(val); return true;});
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::evttypes(
|
||||
std::shared_ptr<ast::expr> filter,
|
||||
std::set<uint16_t>& out) const
|
||||
{
|
||||
evttypes(filter.get(), out);
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::conjunction(
|
||||
const std::vector<std::unique_ptr<ast::expr>>& children)
|
||||
{
|
||||
falco_event_types types = m_all_events;
|
||||
m_last_node_evttypes.clear();
|
||||
for (auto &c : children)
|
||||
{
|
||||
c->accept(this);
|
||||
types = types.intersect(m_last_node_evttypes);
|
||||
}
|
||||
m_last_node_evttypes = types;
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::disjunction(
|
||||
const std::vector<std::unique_ptr<ast::expr>>& children)
|
||||
{
|
||||
falco_event_types types;
|
||||
m_last_node_evttypes.clear();
|
||||
for (auto &c : children)
|
||||
{
|
||||
c->accept(this);
|
||||
types.merge(m_last_node_evttypes);
|
||||
}
|
||||
m_last_node_evttypes = types;
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::visit(ast::and_expr* e)
|
||||
{
|
||||
if (m_inside_negation)
|
||||
{
|
||||
disjunction(e->children);
|
||||
}
|
||||
else
|
||||
{
|
||||
conjunction(e->children);
|
||||
}
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::visit(ast::or_expr* e)
|
||||
{
|
||||
if (m_inside_negation)
|
||||
{
|
||||
conjunction(e->children);
|
||||
}
|
||||
else
|
||||
{
|
||||
disjunction(e->children);
|
||||
}
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::visit(ast::not_expr* e)
|
||||
{
|
||||
m_last_node_evttypes.clear();
|
||||
auto inside_negation = m_inside_negation;
|
||||
m_inside_negation = !m_inside_negation;
|
||||
e->child->accept(this);
|
||||
m_inside_negation = inside_negation;
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::visit(ast::binary_check_expr* e)
|
||||
{
|
||||
m_last_node_evttypes.clear();
|
||||
m_last_node_has_evttypes = false;
|
||||
if (e->field == "evt.type" && is_evttype_operator(e->op))
|
||||
{
|
||||
// note: we expect m_inside_negation and m_last_node_has_evttypes
|
||||
// to be handled and altered by the child node
|
||||
m_expect_value = true;
|
||||
e->value->accept(this);
|
||||
m_expect_value = false;
|
||||
if (e->op == "!=")
|
||||
{
|
||||
// note: since we push the "negation" down to the tree leaves
|
||||
// (following de morgan's laws logic), the child node may have
|
||||
// already inverted the set of matched event type. As such,
|
||||
// inverting here again is safe for supporting both the
|
||||
// single-negation and double-negation cases.
|
||||
inversion(m_last_node_evttypes);
|
||||
}
|
||||
return;
|
||||
}
|
||||
m_last_node_evttypes = m_all_events;
|
||||
try_inversion(m_last_node_evttypes);
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::visit(ast::unary_check_expr* e)
|
||||
{
|
||||
m_last_node_evttypes.clear();
|
||||
m_last_node_has_evttypes = e->field == "evt.type" && e->op == "exists";
|
||||
m_last_node_evttypes = m_all_events;
|
||||
try_inversion(m_last_node_evttypes);
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::visit(ast::value_expr* e)
|
||||
{
|
||||
m_last_node_evttypes.clear();
|
||||
m_last_node_has_evttypes = m_expect_value;
|
||||
if (m_expect_value)
|
||||
{
|
||||
evttypes(e->value, m_last_node_evttypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this case only happens if a macro has not yet been substituted
|
||||
// with an actual condition. Should not happen, but we handle it
|
||||
// for consistency.
|
||||
m_last_node_evttypes = m_all_events;
|
||||
}
|
||||
try_inversion(m_last_node_evttypes);
|
||||
}
|
||||
|
||||
void filter_evttype_resolver::visitor::visit(ast::list_expr* e)
|
||||
{
|
||||
m_last_node_evttypes.clear();
|
||||
m_last_node_has_evttypes = false;
|
||||
if (m_expect_value)
|
||||
{
|
||||
m_last_node_has_evttypes = true;
|
||||
for (auto &v : e->values)
|
||||
{
|
||||
evttypes(v, m_last_node_evttypes);
|
||||
}
|
||||
try_inversion(m_last_node_evttypes);
|
||||
return;
|
||||
}
|
||||
m_last_node_evttypes = m_all_events;
|
||||
try_inversion(m_last_node_evttypes);
|
||||
}
|
@@ -1,227 +0,0 @@
|
||||
/*
|
||||
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>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <sinsp.h>
|
||||
|
||||
class falco_event_types
|
||||
{
|
||||
private:
|
||||
using vec_t = std::vector<uint8_t>;
|
||||
vec_t m_types{};
|
||||
|
||||
static inline void check_range(uint16_t e)
|
||||
{
|
||||
static const auto enum_max = get_ppm_event_max();
|
||||
if(e > enum_max)
|
||||
{
|
||||
throw std::range_error("invalid event type");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
falco_event_types(falco_event_types&&) = default;
|
||||
falco_event_types(const falco_event_types&) = default;
|
||||
falco_event_types& operator=(falco_event_types&&) = default;
|
||||
falco_event_types& operator=(const falco_event_types&) = default;
|
||||
|
||||
static size_t get_ppm_event_max();
|
||||
|
||||
inline falco_event_types():
|
||||
m_types(get_ppm_event_max() + 1, 0)
|
||||
{
|
||||
}
|
||||
|
||||
inline void insert(uint16_t e)
|
||||
{
|
||||
check_range(e);
|
||||
m_types[e] = 1;
|
||||
}
|
||||
|
||||
void merge(const falco_event_types& other)
|
||||
{
|
||||
for(size_t i = 0; i <= get_ppm_event_max(); ++i)
|
||||
{
|
||||
m_types[i] |= other.m_types[i];
|
||||
}
|
||||
}
|
||||
|
||||
void merge(const std::set<uint16_t>& other)
|
||||
{
|
||||
for(const auto& e : other)
|
||||
{
|
||||
insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool contains(uint16_t e) const
|
||||
{
|
||||
check_range(e);
|
||||
return m_types[e] != 0;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for(auto& v : m_types)
|
||||
{
|
||||
v = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool equals(const falco_event_types& other) const
|
||||
{
|
||||
return m_types == other.m_types;
|
||||
}
|
||||
|
||||
falco_event_types diff(const falco_event_types& other) const
|
||||
{
|
||||
falco_event_types ret;
|
||||
for(size_t i = 0; i <= get_ppm_event_max(); ++i)
|
||||
{
|
||||
if(m_types[i] == 1 && other.m_types[i] == 0)
|
||||
{
|
||||
ret.m_types[i] = 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
falco_event_types intersect(const falco_event_types& other) const
|
||||
{
|
||||
falco_event_types ret;
|
||||
for(size_t i = 0; i <= get_ppm_event_max(); ++i)
|
||||
{
|
||||
if(m_types[i] == 1 && other.m_types[i] == 1)
|
||||
{
|
||||
ret.m_types[i] = 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void for_each(std::function<bool(uint16_t)> consumer) const
|
||||
{
|
||||
for(uint16_t i = 0; i < m_types.size(); ++i)
|
||||
{
|
||||
if(m_types[i] != 0)
|
||||
{
|
||||
if(!consumer(i))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const falco_event_types& lhs, const falco_event_types& rhs)
|
||||
{
|
||||
return lhs.equals(rhs);
|
||||
}
|
||||
|
||||
inline bool operator!=(const falco_event_types& lhs, const falco_event_types& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Helper class for finding event types
|
||||
*/
|
||||
class filter_evttype_resolver
|
||||
{
|
||||
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
|
||||
*/
|
||||
inline void evttypes(const std::string& evtname, falco_event_types& out) const
|
||||
{
|
||||
falco_event_types evt_types;
|
||||
visitor().evttypes(evtname, evt_types);
|
||||
evt_types.for_each([&out](uint16_t val)
|
||||
{out.insert(val); return true; });
|
||||
}
|
||||
|
||||
/*!
|
||||
\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) const;
|
||||
|
||||
/*!
|
||||
\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) const;
|
||||
|
||||
private:
|
||||
struct visitor : public libsinsp::filter::ast::expr_visitor
|
||||
{
|
||||
visitor():
|
||||
m_expect_value(false),
|
||||
m_inside_negation(false),
|
||||
m_last_node_has_evttypes(false),
|
||||
m_last_node_evttypes({}),
|
||||
m_all_events({}),
|
||||
m_inspector()
|
||||
{
|
||||
evttypes("", m_all_events);
|
||||
}
|
||||
visitor(visitor&&) = default;
|
||||
visitor& operator = (visitor&&) = default;
|
||||
visitor(const visitor&) = default;
|
||||
visitor& operator = (const visitor&) = default;
|
||||
|
||||
bool m_expect_value;
|
||||
bool m_inside_negation;
|
||||
bool m_last_node_has_evttypes;
|
||||
falco_event_types m_last_node_evttypes;
|
||||
falco_event_types m_all_events;
|
||||
sinsp m_inspector;
|
||||
|
||||
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;
|
||||
void try_inversion(falco_event_types& types);
|
||||
void inversion(falco_event_types& types);
|
||||
void evttypes(const std::string& evtname, falco_event_types& out);
|
||||
void conjunction(const std::vector<std::unique_ptr<libsinsp::filter::ast::expr>>&);
|
||||
void disjunction(const std::vector<std::unique_ptr<libsinsp::filter::ast::expr>>&);
|
||||
};
|
||||
};
|
Reference in New Issue
Block a user