From b3ebbe12d05f2f528219678e40b0eb1a2077b892 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Wed, 8 Jun 2016 18:19:15 -0700 Subject: [PATCH] Add optional support for multiple filters. Add support for an additional set of individual filters that can run alongside the main filter set in sinsp::set_filter(). Each additional filter comes with a list of event types for which the filter should run. sinsp::add_evttype_filter adds an event type filter to the inspector. It provides a list of event types and a sinsp_filter pointer. The list of event types can be empty, implying the filter is a catchall filter and should run for all event types. This does not replace the main function set_filter()--the idea is that you can specify a global filter as well as per-event type filters. Both will run for all events. An array m_filter_by_evttype maps from event type to a list of sinsp_filter pointers. Each list at index i holds the filters that should run for events with type i. A filter can run for multiple event types, so the sinsp_filter pointers can appear in multiple lists. There's a separate list m_catchall_evttype_filters that contains filters that should run for all event types. The individual filter pointers are also held in a list m_evttype_filters so they can be cleaned up on close(). A new method run_filters_on_evt() handles the details of running the main filter, catchall filters, and the individual filters. It finds the filters related to the event's type, and runs those filters. Falco uses the lua callbacks in lua_parser{_api} to populate filters as the lua code parses the rule's condition, so also modify lua_parser to add a optional flag to get_parser that steals the m_filter object and creates a new one. Falco calls get_parser for each rule's condition, which allows it to create a sinsp_filter object for each rule. --- userspace/libsinsp/lua_parser.cpp | 27 ++++++++--- userspace/libsinsp/lua_parser.h | 4 +- userspace/libsinsp/parsers.cpp | 13 ++--- userspace/libsinsp/sinsp.cpp | 80 +++++++++++++++++++++++++++++++ userspace/libsinsp/sinsp.h | 19 ++++++++ 5 files changed, 127 insertions(+), 16 deletions(-) diff --git a/userspace/libsinsp/lua_parser.cpp b/userspace/libsinsp/lua_parser.cpp index d83389a07d..25bdebdab0 100644 --- a/userspace/libsinsp/lua_parser.cpp +++ b/userspace/libsinsp/lua_parser.cpp @@ -27,11 +27,7 @@ lua_parser::lua_parser(sinsp* inspector, lua_State *ls) m_inspector = inspector; m_ls = ls; - m_have_rel_expr = false; - m_last_boolop = BO_NONE; - m_nest_level = 0; - - m_filter = new sinsp_filter(m_inspector); + reset(); // Register our c++ defined functions luaL_openlib(m_ls, "filter", ll_filter, 0); @@ -41,13 +37,30 @@ lua_parser::lua_parser(sinsp* inspector, lua_State *ls) } -sinsp_filter* lua_parser::get_filter() +void lua_parser::reset() +{ + m_have_rel_expr = false; + m_last_boolop = BO_NONE; + m_nest_level = 0; + + m_filter = new sinsp_filter(m_inspector); +} + +sinsp_filter* lua_parser::get_filter(bool reset_filter) { if (m_nest_level != 0) { throw sinsp_exception("Error in configured filter: unbalanced nesting"); } - return m_filter; + + sinsp_filter *ret = m_filter; + + if (reset_filter) + { + reset(); + } + + return ret; } lua_parser::~lua_parser() { diff --git a/userspace/libsinsp/lua_parser.h b/userspace/libsinsp/lua_parser.h index 330e9c0e66..5a9e3e514f 100644 --- a/userspace/libsinsp/lua_parser.h +++ b/userspace/libsinsp/lua_parser.h @@ -12,9 +12,11 @@ class lua_parser public: lua_parser(sinsp* inspector, lua_State *ls); ~lua_parser(); - sinsp_filter* get_filter(); + sinsp_filter* get_filter(bool reset_filter = false); private: + + void reset(); sinsp* m_inspector; sinsp_filter* m_filter; diff --git a/userspace/libsinsp/parsers.cpp b/userspace/libsinsp/parsers.cpp index bddc1b1a5d..b40f702782 100644 --- a/userspace/libsinsp/parsers.cpp +++ b/userspace/libsinsp/parsers.cpp @@ -190,7 +190,7 @@ void sinsp_parser::process_event(sinsp_evt *evt) #if defined(HAS_FILTERING) && defined(HAS_CAPTURE_FILTERING) bool do_filter_later = false; - if(m_inspector->m_filter) + if(m_inspector->m_filter || m_inspector->m_evttype_filters.size() > 0) { ppm_event_flags eflags = evt->get_info_flags(); @@ -230,7 +230,7 @@ void sinsp_parser::process_event(sinsp_evt *evt) } else { - if(m_inspector->m_filter->run(evt) == false) + if(m_inspector->run_filters_on_evt(evt) == false) { if(evt->m_tinfo != NULL) { @@ -468,13 +468,10 @@ void sinsp_parser::process_event(sinsp_evt *evt) #if defined(HAS_FILTERING) && defined(HAS_CAPTURE_FILTERING) if(do_filter_later) { - if(m_inspector->m_filter) + if(m_inspector->run_filters_on_evt(evt) == false) { - if(m_inspector->m_filter->run(evt) == false) - { - evt->m_filtered_out = true; - return; - } + evt->m_filtered_out = true; + return; } evt->m_filtered_out = false; } diff --git a/userspace/libsinsp/sinsp.cpp b/userspace/libsinsp/sinsp.cpp index efc45bc7ad..dbbaa49138 100644 --- a/userspace/libsinsp/sinsp.cpp +++ b/userspace/libsinsp/sinsp.cpp @@ -549,6 +549,23 @@ void sinsp::close() delete m_filter; m_filter = NULL; } + + for(int i = 0; i < PPM_EVENT_MAX; i++) + { + if(m_filter_by_evttype[i]) + { + delete m_filter_by_evttype[i]; + m_filter_by_evttype[i] = NULL; + } + } + + m_catchall_evttype_filters.clear(); + + for(auto filter : m_evttype_filters) + { + delete filter; + } + m_evttype_filters.clear(); #endif } @@ -1351,6 +1368,69 @@ const string sinsp::get_filter() return m_filterstring; } +void sinsp::add_evttype_filter(list &evttypes, + sinsp_filter *filter) +{ + m_evttype_filters.push_back(filter); + + if(evttypes.size() == 0) + { + m_catchall_evttype_filters.push_back(filter); + } + else + { + + for(auto evttype: evttypes) + { + list *filters = m_filter_by_evttype[evttype]; + if(filters == NULL) + { + filters = new list(); + m_filter_by_evttype[evttype] = filters; + } + + filters->push_back(filter); + } + } +} + +bool sinsp::run_filters_on_evt(sinsp_evt *evt) +{ + // + // First run the global filter, if there is one. + // + if(m_filter && m_filter->run(evt) == true) + { + return true; + } + + // + // Then run any catchall event type filters (ones that did not + // explicitly specify any event type. + // + for(sinsp_filter *filt : m_catchall_evttype_filters) + { + if(filt->run(evt) == true) + { + return true; + } + } + + list *filters = m_filter_by_evttype[evt->m_pevt->type]; + + if(filters) + { + for(sinsp_filter *filt : *filters) + { + if(filt->run(evt) == true) + { + return true; + } + } + } + + return false; +} #endif const scap_machine_info* sinsp::get_machine_info() diff --git a/userspace/libsinsp/sinsp.h b/userspace/libsinsp/sinsp.h index c0dfa3054c..d4358519a8 100644 --- a/userspace/libsinsp/sinsp.h +++ b/userspace/libsinsp/sinsp.h @@ -349,6 +349,11 @@ class SINSP_PUBLIC sinsp string if no filter has been set yet. */ const string get_filter(); + + void add_evttype_filter(list &evttypes, + sinsp_filter* filter); + + bool run_filters_on_evt(sinsp_evt *evt); #endif /*! @@ -849,6 +854,20 @@ VISIBILITY_PRIVATE uint64_t m_firstevent_ts; sinsp_filter* m_filter; string m_filterstring; + + // Maps from event type to filter. There can be multiple + // filters per event type. + list *m_filter_by_evttype[PPM_EVENT_MAX]; + + // It's possible to add an event type filter with an empty + // list of event types, meaning it should run for all event + // types. + list m_catchall_evttype_filters; + + // This holds all the filters in + // m_filter_by_evttype/m_catchall_evttype_filters, so they can + // be cleaned up. + list m_evttype_filters; #endif //