diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index 37883d9d..0eed2c1d 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -25,19 +25,16 @@ FetchContent_MakeAvailable(googletest) file(GLOB_RECURSE ENGINE_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/engine/*.cpp) file(GLOB_RECURSE FALCO_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/falco/*.cpp) -file(GLOB_RECURSE FALCO_APP_ACTIONS_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/falco/app/actions/*.cpp) set(FALCO_UNIT_TESTS_SOURCES "${ENGINE_TESTS}" "${FALCO_TESTS}" - "${FALCO_APP_ACTIONS_TESTS}" ) set(FALCO_UNIT_TESTS_INCLUDES PRIVATE ${CMAKE_SOURCE_DIR}/userspace ${CMAKE_BINARY_DIR}/userspace/falco # we need it to include indirectly `config_falco.h` file - ${CMAKE_BINARY_DIR}/userspace/falco/app/actions ${CMAKE_SOURCE_DIR}/userspace/engine # we need it to include indirectly `falco_common.h` file ) diff --git a/unit_tests/falco/app/actions/test_configure_interesting_sets.cpp b/unit_tests/falco/app/actions/test_configure_interesting_sets.cpp index af2f153d..75cb4d42 100644 --- a/unit_tests/falco/app/actions/test_configure_interesting_sets.cpp +++ b/unit_tests/falco/app/actions/test_configure_interesting_sets.cpp @@ -24,6 +24,12 @@ using namespace std; using namespace libsinsp::filter; using namespace falco::utils; +// todo(jasondellaluce): these tests do not test the actual +// `configure_interesting_sets` action, but instead reproduces its logic +// and asserts the pre and post conditions. For now, this is the only thing +// we can do due to the falco_engine class lacking adequate accessor methods. +// In the future, we need to refactor this. + static std::shared_ptr create_factory() { std::shared_ptr ret(new sinsp_filter_factory(NULL)); @@ -56,133 +62,90 @@ static std::shared_ptr create_ruleset( static std::shared_ptr get_test_rulesets(const std::unordered_set& fltstrs) { - auto f = create_factory(); - auto r = create_ruleset(f); + auto f = create_factory(); + auto r = create_ruleset(f); for (const auto &fltstr : fltstrs) { - auto rule_ast = create_ast(f, fltstr); - auto rule_filter = create_filter(f, rule_ast); - falco_rule rule; - rule.name = fltstr; - rule.source = falco_common::syscall_source; - r->add(rule, rule_filter, rule_ast); + auto rule_ast = create_ast(f, fltstr); + auto rule_filter = create_filter(f, rule_ast); + falco_rule rule; + rule.name = fltstr; + rule.source = falco_common::syscall_source; + r->add(rule, rule_filter, rule_ast); r->enable(fltstr, true, 0); - } - return r; -} - -void compare_evttypes_names(const std::unordered_set& actual, const std::unordered_set& expected) -{ - - ASSERT_EQ(actual.size(), expected.size()); - std::set actual_sorted = unordered_set_to_ordered(actual); - std::set expected_sorted = unordered_set_to_ordered(expected); - - auto final = actual_sorted.begin(); - auto matching = expected_sorted.begin(); - - for(; final != actual_sorted.end(); final++, matching++) - { - ASSERT_TRUE(*matching == *final); } + return r; } -std::unordered_set extract_rules_event_names(std::unique_ptr& inspector, std::shared_ptr& r) +static libsinsp::events::set extract_rules_event_set(std::shared_ptr& r) { - std::set rule_events; - r->enabled_evttypes(rule_events, 0); - std::unordered_set ppme_events_codes(rule_events.begin(), rule_events.end()); - return inspector->get_events_names(ppme_events_codes); -} - -std::unordered_set erase_io_syscalls(std::unordered_set &ppm_sc_of_interest) -{ - std::unordered_set erased_io_syscalls_names = {}; - std::unordered_set cur_ppm_sc_set = ppm_sc_of_interest; - const int bitmask = EC_SYSCALL - 1; - for (const auto &ppm_sc_code : cur_ppm_sc_set) + std::set tmp; + libsinsp::events::set events; + auto source = falco_common::syscall_source; + r->enabled_evttypes(tmp, 0); + for (const auto &ev : tmp) { - switch(g_infotables.m_syscall_info_table[ppm_sc_code].category & bitmask) - { - case EC_IO_READ: - case EC_IO_WRITE: - ppm_sc_of_interest.erase(ppm_sc_code); - erased_io_syscalls_names.insert(g_infotables.m_syscall_info_table[ppm_sc_code].name); - } + events.insert((ppm_event_code) ev); } - return erased_io_syscalls_names; + return events; +} + +#define ASSERT_NAMES_EQ(a, b) { \ + ASSERT_EQ(std::set(a.begin(), a.end()), std::set(b.begin(), b.end())); \ } TEST(ConfigureInterestingSets, configure_interesting_sets) { - - std::unique_ptr inspector(new sinsp()); - /* Test scenario: - * * Include one I/O syscall * Include one non syscall event type * Include one exclusionary syscall definition test ruleset * Check sinsp enforced syscalls dependencies for: * - spawned processes * - network related syscalls - * Check that non syscalls events are enforced - */ + * Check that non syscalls events are enforced */ std::unordered_set fltstrs = { "(evt.type=connect or evt.type=accept)", "evt.type in (open, ptrace, mmap, execve, read, container)", "evt.type in (open, execve, mprotect) and not evt.type=mprotect"}; - std::string test_io_syscall = "read"; - std::string test_non_syscall = "container"; std::unordered_set expected_syscalls_names = { - "connect", "accept", "open", "ptrace", "mmap", "execve"}; - expected_syscalls_names.insert(test_io_syscall); - std::unordered_set expected_evttypes_names = expected_syscalls_names; - expected_evttypes_names.insert(test_non_syscall); + "connect", "accept", "open", "ptrace", "mmap", "execve", "read", "container"}; std::unordered_set base_syscalls_sinsp_state_spawned_process = {"clone", "clone3", "fork", "vfork"}; std::unordered_set base_syscalls_sinsp_state_network = {"socket", "bind", "close"}; std::unordered_set base_events = {"procexit", "container"}; - std::unordered_set intersection = {}; auto r = get_test_rulesets(fltstrs); ASSERT_EQ(r->enabled_count(0), fltstrs.size()); /* Test if event types names were extracted from each rule in test ruleset. */ - std::unordered_set rules_evttypes_names = extract_rules_event_names(inspector, r); - compare_evttypes_names(rules_evttypes_names, expected_evttypes_names); - - /* Same test again for syscalls events. */ - std::unordered_set rules_ppm_sc_set = get_ppm_sc_set_from_syscalls(rules_evttypes_names); - std::unordered_set rules_syscalls_names = inspector->get_syscalls_names(rules_ppm_sc_set); - compare_evttypes_names(rules_syscalls_names, expected_syscalls_names); + auto rules_event_set = extract_rules_event_set(r); + auto rules_names = libsinsp::events::event_set_to_names(rules_event_set); + ASSERT_NAMES_EQ(rules_names, expected_syscalls_names); /* Enforce sinsp state syscalls and test if ruleset syscalls are in final set of syscalls. */ - // TODO change to enforce_sinsp_state_ppm_sc - std::unordered_set ppm_sc_of_interest = inspector->enforce_simple_ppm_sc_set(rules_ppm_sc_set); - std::unordered_set rules_syscalls_names_enforced = inspector->get_syscalls_names(ppm_sc_of_interest); - intersection = unordered_set_intersection(rules_syscalls_names_enforced, expected_syscalls_names); - compare_evttypes_names(intersection, expected_syscalls_names); + auto base_event_set = libsinsp::events::sinsp_state_event_set(); + auto selected_event_set = base_event_set.merge(rules_event_set); + auto selected_names = libsinsp::events::event_set_to_names(selected_event_set); + auto intersection = unordered_set_intersection(selected_names, expected_syscalls_names); + ASSERT_NAMES_EQ(intersection, expected_syscalls_names); /* Test if sinsp state enforcement activated required syscalls for test ruleset. */ - intersection = unordered_set_intersection(rules_syscalls_names_enforced, base_syscalls_sinsp_state_spawned_process); - compare_evttypes_names(intersection, base_syscalls_sinsp_state_spawned_process); - intersection = unordered_set_intersection(rules_syscalls_names_enforced, base_syscalls_sinsp_state_network); - compare_evttypes_names(intersection, base_syscalls_sinsp_state_network); + intersection = unordered_set_intersection(selected_names, base_syscalls_sinsp_state_spawned_process); + ASSERT_NAMES_EQ(intersection, base_syscalls_sinsp_state_spawned_process); + intersection = unordered_set_intersection(selected_names, base_syscalls_sinsp_state_network); + ASSERT_NAMES_EQ(intersection, base_syscalls_sinsp_state_network); /* Test that no I/O syscalls are in the final set. */ - std::unordered_set io_ppm_sc_set = enforce_io_ppm_sc_set(); - std::unordered_set erased_io_syscalls_names = inspector->get_syscalls_names(unordered_set_intersection(ppm_sc_of_interest, io_ppm_sc_set)); - ppm_sc_of_interest = unordered_set_difference(ppm_sc_of_interest, io_ppm_sc_set); - rules_syscalls_names_enforced = inspector->get_syscalls_names(ppm_sc_of_interest); - intersection = unordered_set_intersection(rules_syscalls_names_enforced, erased_io_syscalls_names); + auto io_event_set = libsinsp::events::sc_set_to_event_set(libsinsp::events::io_sc_set()); + auto erased_event_set = selected_event_set.intersect(io_event_set); + selected_event_set = selected_event_set.diff(io_event_set); + selected_names = libsinsp::events::event_set_to_names(selected_event_set); + intersection = unordered_set_intersection(selected_names, libsinsp::events::event_set_to_names(erased_event_set)); ASSERT_EQ(intersection.size(), 0); /* Test that enforced non syscalls events are in final events set. */ - std::unordered_set ppm_event_info_of_interest = inspector->get_event_set_from_ppm_sc_set(ppm_sc_of_interest); - ppm_event_info_of_interest = enforce_sinsp_state_ppme(ppm_event_info_of_interest); - std::unordered_set final_events_names = inspector->get_events_names(ppm_event_info_of_interest); - intersection = unordered_set_intersection(final_events_names, base_events); - compare_evttypes_names(intersection, base_events); + intersection = unordered_set_intersection(selected_names, base_events); + ASSERT_NAMES_EQ(intersection, base_events); } diff --git a/userspace/engine/falco_utils.cpp b/userspace/engine/falco_utils.cpp index e9cf04ab..53e71e42 100644 --- a/userspace/engine/falco_utils.cpp +++ b/userspace/engine/falco_utils.cpp @@ -16,201 +16,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -#include #include #include -#include -#include -#include -#include -#include -#include #include "falco_utils.h" #include "utils.h" #include "banned.h" // This raises a compilation error when certain functions are used -extern sinsp_evttables g_infotables; - namespace falco { namespace utils { -std::unordered_set get_ppm_sc_set_from_syscalls(const std::unordered_set& syscalls) -{ - std::unordered_set ppm_sc_set = {}; - for (int ppm_sc_code = 0; ppm_sc_code < PPM_SC_MAX; ++ppm_sc_code) - { - std::string ppm_sc_name = g_infotables.m_syscall_info_table[ppm_sc_code].name; - if (syscalls.find(ppm_sc_name) != syscalls.end()) - { - ppm_sc_set.insert(ppm_sc_code); - } - } - return ppm_sc_set; -} - -std::unordered_set enforce_io_ppm_sc_set(std::unordered_set ppm_sc_set) -{ - const int bitmask = EC_SYSCALL - 1; - for(int ppm_sc_code = 0; ppm_sc_code < PPM_SC_MAX; ppm_sc_code++) - { - switch(g_infotables.m_syscall_info_table[ppm_sc_code].category & bitmask) - { - case EC_IO_READ: - case EC_IO_WRITE: - ppm_sc_set.insert(ppm_sc_code); - } - } - return ppm_sc_set; -} - -std::unordered_set enforce_sinsp_state_ppme(std::unordered_set ppm_event_info_of_interest) -{ - /* Fill-up the set of event infos of interest. This is needed to ensure critical non syscall PPME events are activated, e.g. container or proc exit events. */ - for (uint32_t ev = 2; ev < PPM_EVENT_MAX; ev++) - { - if (!sinsp::is_old_version_event(ev) - && !sinsp::is_unused_event(ev) - && !sinsp::is_unknown_event(ev)) - { - /* So far we only covered syscalls, so we add other kinds of - interesting events. In this case, we are also interested in - metaevents and in the procexit tracepoint event. */ - if (sinsp::is_metaevent(ev) || ev == PPME_PROCEXIT_1_E) - { - ppm_event_info_of_interest.insert(ev); - } - } - } - return ppm_event_info_of_interest; -} - -// unordered_set_to_ordered -template -std::set unordered_set_to_ordered(const std::unordered_set& unordered_set) -{ - std::set s; - for(const auto& val : unordered_set) - { - s.insert(val); - } - return s; -} -template std::set unordered_set_to_ordered(const std::unordered_set& unordered_set); -template std::set unordered_set_to_ordered(const std::unordered_set& unordered_set); - -// unordered_set_difference, equivalent to SQL left_anti join operation -template -std::unordered_set unordered_set_difference(const std::unordered_set& a, const std::unordered_set& b) -{ - std::unordered_set s; - for(const auto& val : a) - { - if (b.find(val) == b.end()) - { - s.insert(val); - } - } - return s; -} -template std::unordered_set unordered_set_difference(const std::unordered_set& a, const std::unordered_set& b); -template std::unordered_set unordered_set_difference(const std::unordered_set& a, const std::unordered_set& b); - -// set_difference, equivalent to SQL left_anti join operation -template -std::set set_difference(const std::set& a, const std::set& b) -{ - std::set out; - std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::inserter(out, out.begin())); - return out; -} -template std::set set_difference(const std::set& a, const std::set& b); -template std::set set_difference(const std::set& a, const std::set& b); - -// unordered_set_union -template -std::unordered_set unordered_set_union(const std::unordered_set& a, const std::unordered_set& b) -{ - std::unordered_set s = a; - for(const auto& val : b) - { - s.insert(val); - } - return s; -} -template std::unordered_set unordered_set_union(const std::unordered_set& a, const std::unordered_set& b); -template std::unordered_set unordered_set_union(const std::unordered_set& a, const std::unordered_set& b); - -// set_union -template -std::set set_union(const std::set& a, const std::set& b) -{ - std::set out; - std::set_union(a.begin(), a.end(), b.begin(), b.end(), std::inserter(out, out.begin())); - return out; -} -template std::set set_union(const std::set& a, const std::set& b); -template std::set set_union(const std::set& a, const std::set& b); - -// unordered_set_intersection -template -std::unordered_set unordered_set_intersection(const std::unordered_set& a, const std::unordered_set& b) -{ - std::unordered_set s; - for(const auto& val : a) - { - if (b.find(val) != b.end()) - { - s.insert(val); - } - } - return s; -} -template std::unordered_set unordered_set_intersection(const std::unordered_set& a, const std::unordered_set& b); -template std::unordered_set unordered_set_intersection(const std::unordered_set& a, const std::unordered_set& b); - -// set_intersection -template -std::set set_intersection(const std::set& a, const std::set& b) -{ - std::set out; - std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::inserter(out, out.begin())); - return out; -} -template std::set set_intersection(const std::set& a, const std::set& b); -template std::set set_intersection(const std::set& a, const std::set& b); - -std::string concat_set_in_order(const std::unordered_set& s, const std::string& delim) -{ - if (s.empty()) - { - return ""; - } - std::set s_ordered = unordered_set_to_ordered(s); - std::stringstream ss; - std::copy(s_ordered.begin(), s_ordered.end(), - std::ostream_iterator(ss, delim.c_str())); - std::string s_str = ss.str(); - return s_str.substr(0, s_str.size() - delim.size()); -} - -std::string concat_set_in_order(const std::set& s, const std::string& delim) -{ - if (s.empty()) - { - return ""; - } - std::stringstream ss; - std::copy(s.begin(), s.end(), - std::ostream_iterator(ss, delim.c_str())); - std::string s_str = ss.str(); - return s_str.substr(0, s_str.size() - delim.size()); -} - - std::string wrap_text(const std::string& in, uint32_t indent, uint32_t line_len) { std::istringstream is(in); diff --git a/userspace/engine/falco_utils.h b/userspace/engine/falco_utils.h index e01e5979..73a6e006 100644 --- a/userspace/engine/falco_utils.h +++ b/userspace/engine/falco_utils.h @@ -43,39 +43,6 @@ namespace falco namespace utils { -// TODO interim helper methods -> shall be integrated into sinsp APIs -std::unordered_set get_ppm_sc_set_from_syscalls(const std::unordered_set& syscalls); -std::unordered_set enforce_sinsp_state_ppme(std::unordered_set ppm_event_info_of_interest = {}); -std::unordered_set enforce_io_ppm_sc_set(std::unordered_set ppm_sc_set = {}); // needs libs bump hence duplicated in meantime -// end interim helper methods - -// TODO interim libs utils methods -template -std::set unordered_set_to_ordered(const std::unordered_set& unordered_set); - -template -std::unordered_set unordered_set_difference(const std::unordered_set& a, const std::unordered_set& b); - -template -std::set set_difference(const std::set& a, const std::set& b); - -template -std::unordered_set unordered_set_union(const std::unordered_set& a, const std::unordered_set& b); - -template -std::set set_union(const std::set& a, const std::set& b); - -template -std::unordered_set unordered_set_intersection(const std::unordered_set& a, const std::unordered_set& b); - -template -std::set set_intersection(const std::set& a, const std::set& b); - -std::string concat_set_in_order(const std::unordered_set& s, const std::string& delim = ", "); -std::string concat_set_in_order(const std::set& s, const std::string& delim = ", "); - -// end interim libs utils methods - std::string wrap_text(const std::string& in, uint32_t indent, uint32_t linelen); void readfile(const std::string& filename, std::string& data); diff --git a/userspace/falco/app/actions/helpers.h b/userspace/falco/app/actions/helpers.h index 09261d87..6c8c22a7 100644 --- a/userspace/falco/app/actions/helpers.h +++ b/userspace/falco/app/actions/helpers.h @@ -25,10 +25,6 @@ namespace actions { bool check_rules_plugin_requirements(falco::app::state& s, std::string& err); void print_enabled_event_sources(falco::app::state& s); -void extract_rules_event_names(falco::app::state& s, std::unique_ptr& inspector, std::unordered_set& rules_evttypes_names); -void activate_interesting_events(falco::app::state& s, std::unique_ptr& inspector, const std::unordered_set& rules_evttypes_names); -void check_for_unsupported_events(falco::app::state& s, std::unique_ptr& inspector, const std::unordered_set& rules_evttypes_names); -void activate_interesting_syscalls(falco::app::state& s, std::unique_ptr& inspector, const std::unordered_set& rules_evttypes_names); void activate_interesting_kernel_tracepoints(falco::app::state& s, std::unique_ptr& inspector); void check_for_ignored_events(falco::app::state& s); void format_plugin_info(std::shared_ptr p, std::ostream& os); diff --git a/userspace/falco/app/actions/helpers_interesting_sets.cpp b/userspace/falco/app/actions/helpers_interesting_sets.cpp index 63c84ae7..3637abbb 100644 --- a/userspace/falco/app/actions/helpers_interesting_sets.cpp +++ b/userspace/falco/app/actions/helpers_interesting_sets.cpp @@ -14,142 +14,137 @@ See the License for the specific language governing permissions and limitations under the License. */ - -#include "helpers.h" #include "actions.h" -#include "falco_utils.h" -#include -#include #include using namespace falco::app; using namespace falco::app::actions; -using namespace falco::utils; -extern sinsp_evttables g_infotables; - -void falco::app::actions::extract_rules_event_names(falco::app::state& s, std::unique_ptr& inspector, std::unordered_set& rules_evttypes_names) +static libsinsp::events::set extract_rules_event_set(falco::app::state& s) { /* Get all (positive) PPME events from all rules as idx codes. * Events names from negative filter expression statements are NOT included. - * PPME events in libsinsp are needed to map each event type into it's enter and exit event if applicable (e.g. for syscall events). - */ - std::set rule_events; - std::string source = falco_common::syscall_source; - s.engine->evttypes_for_ruleset(source, rule_events); - std::unordered_set ppme_events_codes(rule_events.begin(), rule_events.end()); - - /* Translate PPME event idx codes to consolidated event names. - * Those are the exact event type (evt.type) names from the rules and hence also contain non syscall names, e.g. "container". - */ - rules_evttypes_names = inspector->get_events_names(ppme_events_codes); + * PPME events in libsinsp are needed to map each event type into it's enter + * and exit event if applicable (e.g. for syscall events). */ + std::set tmp; + libsinsp::events::set events; + auto source = falco_common::syscall_source; + s.engine->evttypes_for_ruleset(source, tmp); + for (const auto &ev : tmp) + { + events.insert((ppm_event_code) ev); + } + return events; } -void falco::app::actions::check_for_unsupported_events(falco::app::state& s, std::unique_ptr& inspector, const std::unordered_set& rules_evttypes_names) +static void check_for_rules_unsupported_events(falco::app::state& s, const libsinsp::events::set& rules_event_set) { - std::unordered_set intersection = unordered_set_intersection(inspector->get_events_names(s.ppm_event_info_of_interest), rules_evttypes_names); - if(intersection.empty()) + /* Unsupported events are those events that are used in the rules + * but that are not part of the selected event set. For now, this + * is expected to happen only for high volume I/O syscalls for + * performance reasons. */ + auto unsupported_event_set = rules_event_set.diff(s.selected_event_set); + if (unsupported_event_set.empty()) { return; } - std::unordered_set unsupported = unordered_set_difference(rules_evttypes_names, inspector->get_events_names(s.ppm_event_info_of_interest)); /* Get the names of the events (syscall and non syscall events) that were not activated and print them. */ - std::cerr << "Loaded rules match event types that are not activated or unsupported with current configuration: warning (unsupported-evttype): " + concat_set_in_order(unsupported) << std::endl; + auto names = libsinsp::events::event_set_to_names(unsupported_event_set); + std::cerr << "Loaded rules match event types that are not activated or unsupported with current configuration: warning (unsupported-evttype): " + concat_set_in_order(names) << std::endl; std::cerr << "If syscalls in rules include high volume I/O syscalls (-> activate via `-A` flag), else (2) syscalls might be associated with syscalls undefined on your architecture (https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html)" << std::endl; } -void falco::app::actions::activate_interesting_events(falco::app::state& s, std::unique_ptr& inspector, const std::unordered_set& rules_evttypes_names) +static void select_event_set(falco::app::state& s, const libsinsp::events::set& rules_event_set) { - std::unordered_set ppm_event_info_of_interest = inspector->get_event_set_from_ppm_sc_set(s.ppm_sc_of_interest); - s.ppm_event_info_of_interest = enforce_sinsp_state_ppme(ppm_event_info_of_interest); - check_for_unsupported_events(s, inspector, rules_evttypes_names); -} - -void falco::app::actions::activate_interesting_syscalls(falco::app::state& s, std::unique_ptr& inspector, const std::unordered_set& rules_evttypes_names) -{ - - /* Translate PPME event names to PPM syscall idx codes. - * PPM syscall idx codes can be viewed as condensed libsinsp lookup table to map a system call name to it's actual system syscall id (as defined by the Linux kernel). - * Hence here we don't need syscall enter and exit distinction. - */ - std::unordered_set rules_ppm_sc_set = get_ppm_sc_set_from_syscalls(rules_evttypes_names); - std::unordered_set rules_syscalls_names = inspector->get_syscalls_names(rules_ppm_sc_set); - if (rules_syscalls_names.size() > 0) + /* PPM syscall codes (sc) can be viewed as condensed libsinsp lookup table + * to map a system call name to it's actual system syscall id (as defined + * by the Linux kernel). Hence here we don't need syscall enter and exit distinction. */ + auto rules_names = libsinsp::events::event_set_to_names(rules_event_set); + if (!rules_event_set.empty()) { - falco_logger::log(LOG_DEBUG, "(" + std::to_string(rules_syscalls_names.size()) + ") syscalls activated in rules: " + concat_set_in_order(rules_syscalls_names) + "\n"); + falco_logger::log(LOG_DEBUG, "(" + std::to_string(rules_names.size()) + + ") syscalls activated in rules: " + concat_set_in_order(rules_names) + "\n"); } - /* - * - * DEFAULT OPTION: - * - * Current enforce_simple_ppm_sc_set approach includes multiple steps: - * (1) Enforce all positive syscalls from each Falco rule - * (2) Enforce a static set of syscalls in addition to the syscalls defined in Falco's rules - * (3) Enforce `libsinsp` state set (non-adaptive, not conditioned by rules, but based on PPME event table flags indicating generic sinsp state modifications) - * -> Final set is union of (1), (2) and (3) - * - */ + /* DEFAULT OPTION: + * Current sinsp_state_sc_set() approach includes multiple steps: + * (1) Enforce all positive syscalls from each Falco rule + * (2) Enforce `libsinsp` state set (non-adaptive, not conditioned by rules, + but based on PPME event table flags indicating generic sinsp state modifications) + * -> Final set is union of (1) and (2) */ + auto base_event_set = libsinsp::events::sinsp_state_event_set(); + s.selected_event_set = rules_event_set.merge(base_event_set); - // TODO change to enforce_sinsp_state_ppm_sc - s.ppm_sc_of_interest = inspector->enforce_simple_ppm_sc_set(rules_ppm_sc_set); - - /* Derive the diff between the additional syscalls added via libsinsp state enforcement and the syscalls from each Falco rule. */ - std::unordered_set non_rules_syscalls_names = unordered_set_difference(inspector->get_syscalls_names(s.ppm_sc_of_interest), rules_syscalls_names); - - if (non_rules_syscalls_names.size() > 0) + /* Derive the diff between the additional syscalls added via libsinsp state + enforcement and the syscalls from each Falco rule. */ + auto non_rules_event_set = s.selected_event_set.diff(rules_event_set); + if (!non_rules_event_set.empty()) { - falco_logger::log(LOG_DEBUG, "+(" + std::to_string(non_rules_syscalls_names.size()) + ") syscalls activated (Falco's set of additional syscalls including syscalls needed for state engine): " + concat_set_in_order(non_rules_syscalls_names) + "\n"); + falco_logger::log(LOG_DEBUG, "+(" + std::to_string(non_rules_event_set.size()) + + ") syscalls activated (Falco's set of additional syscalls including syscalls needed for state engine): " + + concat_set_in_order(libsinsp::events::event_set_to_names(non_rules_event_set)) + "\n"); } /* -A flag behavior: - * default: all syscalls in rules included, sinsp state enforcement without high volume I/O syscalls - * -A flag set: all syscalls in rules included, sinsp state enforcement and allowing high volume I/O syscalls - */ - + * (1) default: all syscalls in rules included, sinsp state enforcement + without high volume I/O syscalls + * (2) -A flag set: all syscalls in rules included, sinsp state enforcement + and allowing high volume I/O syscalls */ if(!s.options.all_events) { - std::unordered_set io_ppm_sc_set = enforce_io_ppm_sc_set(); - std::unordered_set erased_io_syscalls_names = inspector->get_syscalls_names(unordered_set_intersection(s.ppm_sc_of_interest, io_ppm_sc_set)); - s.ppm_sc_of_interest = unordered_set_difference(s.ppm_sc_of_interest, io_ppm_sc_set); - - if (erased_io_syscalls_names.size() > 0) + auto ignored_event_set = libsinsp::events::sc_set_to_event_set(libsinsp::events::io_sc_set()); + auto erased_event_set = s.selected_event_set.intersect(ignored_event_set); + s.selected_event_set = s.selected_event_set.diff(ignored_event_set); + if (!erased_event_set.empty()) { - falco_logger::log(LOG_DEBUG, "-(" + std::to_string(erased_io_syscalls_names.size()) + ") high volume I/O syscalls (`-A` flag not set): " + concat_set_in_order(erased_io_syscalls_names) + "\n"); + falco_logger::log(LOG_DEBUG, "-(" + std::to_string(erased_event_set.size()) + + ") ignored high volume I/O syscalls (`-A` flag not set): " + + concat_set_in_order(libsinsp::events::event_set_to_names(erased_event_set)) + "\n"); } } - std::unordered_set final_syscalls_names = inspector->get_syscalls_names(s.ppm_sc_of_interest); - - if (final_syscalls_names.size() > 0) + if (!s.selected_event_set.empty()) { - falco_logger::log(LOG_DEBUG, "(" + std::to_string(final_syscalls_names.size()) + ") syscalls in total activated (final set): " + concat_set_in_order(final_syscalls_names) + "\n"); + falco_logger::log(LOG_DEBUG, "(" + std::to_string(s.selected_event_set.size()) + + ") syscalls in total activated (final set): " + + concat_set_in_order(libsinsp::events::event_set_to_names(s.selected_event_set)) + "\n"); } - } -void falco::app::actions::activate_interesting_kernel_tracepoints(falco::app::state& s, std::unique_ptr& inspector) +static void select_syscall_set(falco::app::state& s, const libsinsp::events::set& rules_event_set) +{ + s.selected_sc_set = libsinsp::events::event_set_to_sc_set(s.selected_event_set); +} + +static void select_kernel_tracepoint_set(falco::app::state& s) { /* Kernel tracepoints activation - * - * Activate all tracepoints except `sched_switch` tracepoint since it is highly noisy and not so useful - * for our state/events enrichment. - */ + * Activate all tracepoints except `sched_switch` tracepoint since it + * is highly noisy and not so useful + * for our state/events enrichment. */ s.selected_tp_set = libsinsp::events::sinsp_state_tp_set(); s.selected_tp_set.remove(ppm_tp_code::SCHED_SWITCH); } falco::app::run_result falco::app::actions::configure_interesting_sets(falco::app::state& s) { - - std::unique_ptr inspector(new sinsp()); - std::unordered_set rules_evttypes_names; - - falco::app::actions::extract_rules_event_names(s, inspector, rules_evttypes_names); // when reaching this code all evttypes are valid - falco::app::actions::activate_interesting_syscalls(s, inspector, rules_evttypes_names); - falco::app::actions::activate_interesting_events(s, inspector, rules_evttypes_names); - falco::app::actions::activate_interesting_kernel_tracepoints(s, inspector); - + s.selected_event_set.clear(); + s.selected_sc_set.clear(); + s.selected_tp_set.clear(); + + /* note: the set of events is the richest source of truth about + * the events generable by an inspector, because they also carry information + * about events that are old, unused, internal, and so on. As such, the + * strategy is to first craft the actual set of selected events, and + * then use it to obtain a set of enabled kernel tracepoints and a set + * of syscall codes. Those last two sets will be passed down to the + * inspector to instruct the kernel drivers on which kernel event should + * be collected at runtime. */ + auto rules_event_set = extract_rules_event_set(s); + select_event_set(s, rules_event_set); + check_for_rules_unsupported_events(s, rules_event_set); + select_syscall_set(s, rules_event_set); + select_kernel_tracepoint_set(s); return run_result::ok(); } diff --git a/userspace/falco/app/actions/print_ignored_events.cpp b/userspace/falco/app/actions/print_ignored_events.cpp index 831ddfe3..9f868a10 100644 --- a/userspace/falco/app/actions/print_ignored_events.cpp +++ b/userspace/falco/app/actions/print_ignored_events.cpp @@ -25,17 +25,13 @@ using namespace falco::utils; falco::app::run_result falco::app::actions::print_ignored_events(falco::app::state& s) { - if(!s.options.print_ignored_events) { return run_result::ok(); } - std::unique_ptr inspector(new sinsp()); - std::unordered_set io_ppm_sc_set = enforce_io_ppm_sc_set(); - std::cout << "Ignored I/O syscall(s):" << std::endl; - for(const auto& it : inspector->get_syscalls_names(io_ppm_sc_set)) + for(const auto& it : libsinsp::events::sc_set_to_names(libsinsp::events::io_sc_set())) { std::cout << "- " << it.c_str() << std::endl; } diff --git a/userspace/falco/app/actions/print_syscall_events.cpp b/userspace/falco/app/actions/print_syscall_events.cpp index b8167a47..681fa580 100644 --- a/userspace/falco/app/actions/print_syscall_events.cpp +++ b/userspace/falco/app/actions/print_syscall_events.cpp @@ -76,7 +76,7 @@ falco::app::run_result falco::app::actions::print_syscall_events(falco::app::sta { if(s.options.list_syscall_events) { - const auto events = get_event_entries(true, s.ppm_event_info_of_interest); + const auto events = get_event_entries(true, libsinsp::events::all_event_set()); if(s.options.markdown) {