Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to return event types used by a filter #74

Merged
merged 1 commit into from
Oct 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions userspace/libsinsp/filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,18 @@ sinsp_filter_check::sinsp_filter_check()
m_val_storages = vector<vector<uint8_t>> (1, vector<uint8_t>(256));
m_val_storages_min_size = (numeric_limits<uint32_t>::max)();
m_val_storages_max_size = (numeric_limits<uint32_t>::min)();

// Do this once
if(s_all_event_types.size() == 0)
{
//
// Fill in from 2 to PPM_EVENT_MAX-1. 0 and 1 are excluded as
// those are PPM_GENERIC_E/PPME_GENERIC_X.
for(uint16_t i = 2; i < PPM_EVENT_MAX; i++)
{
s_all_event_types.insert(i);
}
}
}

void sinsp_filter_check::set_inspector(sinsp* inspector)
Expand Down Expand Up @@ -1365,6 +1377,18 @@ uint8_t* sinsp_filter_check::extract_cached(sinsp_evt *evt, OUT uint32_t* len, b
}
}

const std::set<uint16_t> &sinsp_filter_check::evttypes()
{
// By default a check should be considered for all event types
// so use the default.
return s_all_event_types;
}

const std::set<uint16_t> &sinsp_filter_check::possible_evttypes()
{
return s_all_event_types;
}

bool sinsp_filter_check::compare(gen_event *evt)
{
if(m_eval_cache_entry != NULL)
Expand Down
67 changes: 67 additions & 0 deletions userspace/libsinsp/filterchecks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4524,6 +4524,73 @@ uint8_t* sinsp_filter_check_event::extract(sinsp_evt *evt, OUT uint32_t* len, bo
return NULL;
}

const std::set<uint16_t> &sinsp_filter_check_event::evttypes()
{
bool should_match = true;

if(m_field_id == TYPE_TYPE)
{
// The only meaningful comparison operators for this
// filter check should be direct comparisons and not
// LT/GE/CONTAINS/etc.
if(!(m_cmpop == CO_EQ || m_cmpop == CO_NE || m_cmpop == CO_IN))
{
m_event_types = possible_evttypes();
return m_event_types;
}

// If the comparison operator is !=, we need to invert
// the set. "not" is handled in
// gen_event_filter_expression::evttypes().
if(m_cmpop == CO_NE)
{
should_match = false;
}
}
else
{
// Should run for all event types
m_event_types = possible_evttypes();
return m_event_types;
}

// If here, we know we can find a more specific set of event types.
m_event_types.clear();

sinsp_evttables* einfo = m_inspector->get_event_info_tables();
const struct ppm_event_info* etable = einfo->m_event_info;

// This skips PPME_EVENT_GENERIC_{E,X} as the logical
// operators/inverse don't work for these values.
for(uint32_t i = 2; i < PPM_EVENT_MAX; i++)
{
// The values are held as strings, so we need to
// convert them back to numbers.
bool found = false;
for (uint16_t j=0; j < m_val_storages.size(); j++)
{
std::string evttype_str((char *) filter_value_p(j));

if(etable[i].name == evttype_str)
{
found = true;
break;
}
}

// We add to m_event_types if:
// - was found and should_match == true, or
// - was not found and should_match == false
// so found == should_match
if(found == should_match)
{
m_event_types.insert(i);
}
}

return m_event_types;
}

bool sinsp_filter_check_event::compare(sinsp_evt *evt)
{
bool res;
Expand Down
9 changes: 9 additions & 0 deletions userspace/libsinsp/filterchecks.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ class sinsp_filter_check : public gen_event_filter_check
return Json::nullValue;
}

virtual const std::set<uint16_t> &evttypes() override;
const std::set<uint16_t> &possible_evttypes() override;

//
// Compare the field with the constant value obtained from parse_filter_value()
//
Expand Down Expand Up @@ -193,6 +196,8 @@ class sinsp_filter_check : public gen_event_filter_check
private:
void set_inspector(sinsp* inspector);

std::set<uint16_t> s_all_event_types;

friend class sinsp_filter_check_list;
friend class sinsp_filter_optimizer;
friend class chk_compare_helper;
Expand Down Expand Up @@ -482,6 +487,8 @@ class sinsp_filter_check_event : public sinsp_filter_check
Json::Value extract_as_js(sinsp_evt *evt, OUT uint32_t* len);
bool compare(sinsp_evt *evt);

const std::set<uint16_t> &evttypes() override;

uint64_t m_u64val;
uint64_t m_tsdelta;
uint32_t m_u32val;
Expand Down Expand Up @@ -510,6 +517,8 @@ class sinsp_filter_check_event : public sinsp_filter_check
uint32_t m_storage_size;
const char* m_cargname;
sinsp_filter_check_reference* m_converter;

std::set<uint16_t> m_event_types;
};

//
Expand Down
113 changes: 113 additions & 0 deletions userspace/libsinsp/gen_filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ along with Falco. If not, see <http://www.gnu.org/licenses/>.
*/

#include <cstddef>
#include <algorithm>
#include "stdint.h"
#include "gen_filter.h"
#include "sinsp.h"
#include "sinsp_int.h"

std::set<uint16_t> gen_event_filter_check::s_default_evttypes{1};

gen_event::gen_event()
{
}
Expand Down Expand Up @@ -58,6 +61,16 @@ int32_t gen_event_filter_check::get_check_id()
return m_check_id;
}

const std::set<uint16_t> &gen_event_filter_check::evttypes()
{
return s_default_evttypes;
}

const std::set<uint16_t> &gen_event_filter_check::possible_evttypes()
{
return s_default_evttypes;
}

///////////////////////////////////////////////////////////////////////////////
// gen_event_filter_expression implementation
///////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -199,6 +212,101 @@ int32_t gen_event_filter_expression::get_expr_boolop()
return b0;
}

std::set<uint16_t> gen_event_filter_expression::inverse(const std::set<uint16_t> &evttypes)
{
std::set<uint16_t> ret;

// The inverse of "all events" is still "all events". This
// ensures that when no specific set of event types are named
// in the filter that the filter still runs for all event
// types.
if(evttypes == m_expr_possible_evttypes)
{
ret = evttypes;
return ret;
}

std::set_difference(m_expr_possible_evttypes.begin(), m_expr_possible_evttypes.end(),
evttypes.begin(), evttypes.end(),
std::inserter(ret, ret.begin()));

return ret;
}

void gen_event_filter_expression::combine_evttypes(boolop op,
const std::set<uint16_t> &chk_evttypes)
{
switch(op)
{
case BO_NONE:
// Overwrite with contents of set
// Should only occur for the first check in a list
m_expr_event_types = chk_evttypes;
break;
case BO_NOT:
m_expr_event_types = inverse(chk_evttypes);
break;
case BO_ORNOT:
combine_evttypes(BO_OR, inverse(chk_evttypes));
break;
case BO_ANDNOT:
combine_evttypes(BO_AND, inverse(chk_evttypes));
break;
case BO_OR:
// Merge the event types from the
// other set into this one.
m_expr_event_types.insert(chk_evttypes.begin(), chk_evttypes.end());
break;
case BO_AND:
// Set to the intersection of event types between this
// set and the provided set.

std::set<uint16_t> intersect;
std::set_intersection(m_expr_event_types.begin(), m_expr_event_types.end(),
chk_evttypes.begin(), chk_evttypes.end(),
std::inserter(intersect, intersect.begin()));
m_expr_event_types = intersect;
break;
}
}

const std::set<uint16_t> &gen_event_filter_expression::evttypes()
{
m_expr_event_types.clear();

m_expr_possible_evttypes = possible_evttypes();

for(uint32_t i = 0; i < m_checks.size(); i++)
{
gen_event_filter_check *chk = m_checks[i];
ASSERT(chk != NULL);

const std::set<uint16_t> &chk_evttypes = m_checks[i]->evttypes();

combine_evttypes(chk->m_boolop, chk_evttypes);
}

return m_expr_event_types;
}

const std::set<uint16_t> &gen_event_filter_expression::possible_evttypes()
{
// Return the set of possible event types from the first filtercheck.
if(m_checks.size() == 0)
{
// Shouldn't happen--every filter expression should have a
// real filtercheck somewhere below it.
ASSERT(false);
m_expr_possible_evttypes = s_default_evttypes;
}
else
{
m_expr_possible_evttypes = m_checks[0]->possible_evttypes();
}

return m_expr_possible_evttypes;
}

///////////////////////////////////////////////////////////////////////////////
// sinsp_filter implementation
///////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -248,3 +356,8 @@ void gen_event_filter::add_check(gen_event_filter_check* chk)
{
m_curexpr->add_check((gen_event_filter_check *) chk);
}

std::set<uint16_t> gen_event_filter::evttypes()
{
return m_filter->evttypes();
}
37 changes: 37 additions & 0 deletions userspace/libsinsp/gen_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ along with Falco. If not, see <http://www.gnu.org/licenses/>.

#pragma once

#include <set>
#include <vector>

/*
Expand Down Expand Up @@ -115,6 +116,16 @@ class gen_event_filter_check
void set_check_id(int32_t id);
virtual int32_t get_check_id();

// Return all event types used by this filtercheck. It's used in
// programs like falco to speed up rule evaluation.
virtual const std::set<uint16_t> &evttypes();

// Return all possible event types. Used for "not" operators
// where a set of events must be inverted.
virtual const std::set<uint16_t> &possible_evttypes();

static std::set<uint16_t> s_default_evttypes;

private:
int32_t m_check_id = 0;

Expand Down Expand Up @@ -160,8 +171,30 @@ class gen_event_filter_expression : public gen_event_filter_check
//
int32_t get_expr_boolop();

// Return all event types used by this expression. It's used in
// programs like falco to speed up rule evaluation.
const std::set<uint16_t> &evttypes() override;

// An expression does not directly have a set of possible
// event types, but it can determine them from the m_checks
// vector.
const std::set<uint16_t> &possible_evttypes() override;

gen_event_filter_expression* m_parent;
std::vector<gen_event_filter_check*> m_checks;

private:

std::set<uint16_t> m_expr_event_types;
std::set<uint16_t> m_expr_possible_evttypes;

// Return the "inverse" of the provided set of event types, using the
// provided full possible set of event types as a hint.
std::set<uint16_t> inverse(const std::set<uint16_t> &evttypes);

// Given a boolean op and a set of event types from a
// filtercheck in the expression, update m_expr_event_types appropriately.
void combine_evttypes(boolop op, const std::set<uint16_t> &evttypes);
};


Expand All @@ -184,6 +217,10 @@ class gen_event_filter
void pop_expression();
void add_check(gen_event_filter_check* chk);

// Return all event types used by this filter. It's used in
// programs like falco to speed up rule evaluation.
std::set<uint16_t> evttypes();

gen_event_filter_expression* m_filter;

protected:
Expand Down
1 change: 1 addition & 0 deletions userspace/libsinsp/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ include_directories(${LIBSCAP_INCLUDE_DIR})
add_executable(unit-test-libsinsp
cgroup_list_counter.ut.cpp
sinsp.ut.cpp
evttype_filter.ut.cpp
)

target_link_libraries(unit-test-libsinsp
Expand Down
Loading