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 688fad85..469da8ed 100644 --- a/unit_tests/falco/app/actions/test_configure_interesting_sets.cpp +++ b/unit_tests/falco/app/actions/test_configure_interesting_sets.cpp @@ -15,12 +15,14 @@ limitations under the License. */ +#include "falco_utils.h" #include "evttype_index_ruleset.h" #include #include using namespace std; using namespace libsinsp::filter; +using namespace falco::utils; static std::shared_ptr create_factory() { @@ -52,7 +54,7 @@ static std::shared_ptr create_ruleset( return ret; } -static std::shared_ptr get_test_rulesets(std::unordered_set fltstrs) +static std::shared_ptr get_test_rulesets(const std::unordered_set& fltstrs) { auto f = create_factory(); auto r = create_ruleset(f); @@ -70,20 +72,9 @@ static std::shared_ptr get_test_rulesets(std::unordered_set -std::set unordered_set_to_ordered(std::unordered_set unordered_set) +void compare_evttypes_names(const std::unordered_set& actual, const std::unordered_set& expected) { - std::set s; - for(const auto& val : unordered_set) - { - s.insert(val); - } - return s; -} -template std::set unordered_set_to_ordered(std::unordered_set unordered_set); -void compare_evttypes_names(std::unordered_set &actual, 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); @@ -97,7 +88,7 @@ void compare_evttypes_names(std::unordered_set &actual, std::unorde } } -std::unordered_set extract_rules_event_names(std::unique_ptr& inspector, std::shared_ptr r) +std::unordered_set extract_rules_event_names(std::unique_ptr& inspector, std::shared_ptr& r) { std::set rule_events; r->enabled_evttypes(rule_events, 0); @@ -105,20 +96,6 @@ std::unordered_set extract_rules_event_names(std::unique_ptr return inspector->get_events_names(ppme_events_codes); } -std::unordered_set get_syscalls_ppm_codes(const std::unordered_set syscalls_names) -{ - 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_names.find(ppm_sc_name) != syscalls_names.end()) - { - ppm_sc_set.insert(ppm_sc_code); - } - } - return ppm_sc_set; -} - void compare_syscalls_subset_names(std::unordered_set &total_enforced, std::unordered_set &subset, bool inverted = false) { ASSERT_GE(total_enforced.size(), subset.size()); @@ -171,6 +148,7 @@ TEST(ConfigureInterestingSets, configure_interesting_sets) * Check sinsp enforced syscalls dependencies for: * - spawned processes * - network related syscalls + * Check that non syscalls events are enforced */ std::unordered_set fltstrs = { "(evt.type=connect or evt.type=accept)", @@ -185,6 +163,8 @@ TEST(ConfigureInterestingSets, configure_interesting_sets) expected_evttypes_names.insert(test_non_syscall); 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()); @@ -194,21 +174,36 @@ TEST(ConfigureInterestingSets, configure_interesting_sets) compare_evttypes_names(rules_evttypes_names, expected_evttypes_names); /* Same test again for syscalls events. */ - std::unordered_set rules_ppm_sc_set = get_syscalls_ppm_codes(rules_evttypes_names); + 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); /* 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); - compare_syscalls_subset_names(rules_syscalls_names_enforced, expected_syscalls_names); + intersection = unordered_set_intersection(rules_syscalls_names_enforced, expected_syscalls_names); + compare_evttypes_names(intersection, expected_syscalls_names); /* Test if sinsp state enforcement activated required syscalls for test ruleset. */ - compare_syscalls_subset_names(rules_syscalls_names_enforced, base_syscalls_sinsp_state_spawned_process); - compare_syscalls_subset_names(rules_syscalls_names_enforced, base_syscalls_sinsp_state_network); + 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); /* Test that no I/O syscalls are in the final set. */ - std::unordered_set erased_io_syscalls_names = erase_io_syscalls(ppm_sc_of_interest); + 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); - compare_syscalls_subset_names(rules_syscalls_names_enforced, erased_io_syscalls_names, true); + intersection = unordered_set_intersection(rules_syscalls_names_enforced, erased_io_syscalls_names); + 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); + } diff --git a/userspace/engine/falco_utils.cpp b/userspace/engine/falco_utils.cpp index 53e71e42..e9cf04ab 100644 --- a/userspace/engine/falco_utils.cpp +++ b/userspace/engine/falco_utils.cpp @@ -16,19 +16,201 @@ 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 93cc33b9..e01e5979 100644 --- a/userspace/engine/falco_utils.h +++ b/userspace/engine/falco_utils.h @@ -24,6 +24,10 @@ limitations under the License. #include #include #include +#include +#include +#include +#include #ifdef __GNUC__ #define likely(x) __builtin_expect(!!(x), 1) @@ -39,6 +43,39 @@ 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 3b5d4342..09261d87 100644 --- a/userspace/falco/app/actions/helpers.h +++ b/userspace/falco/app/actions/helpers.h @@ -26,7 +26,8 @@ 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); +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); diff --git a/userspace/falco/app/actions/helpers_interesting_sets.cpp b/userspace/falco/app/actions/helpers_interesting_sets.cpp index a6f32cd1..1f125767 100644 --- a/userspace/falco/app/actions/helpers_interesting_sets.cpp +++ b/userspace/falco/app/actions/helpers_interesting_sets.cpp @@ -14,94 +14,21 @@ See the License for the specific language governing permissions and limitations under the License. */ + #include "helpers.h" #include "actions.h" #include "configure_interesting_sets.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; -std::string concat_syscalls_names(std::unordered_set const syscalls_names) -{ - std::set syscalls_names_ordered = {}; - for (const auto &n : syscalls_names) - { - syscalls_names_ordered.insert(n); - } - std::stringstream ss; - std::copy(syscalls_names_ordered.begin(), syscalls_names_ordered.end(), - std::ostream_iterator(ss, ", ")); - std::string syscalls_names_str = ss.str(); - return syscalls_names_str.substr(0, syscalls_names_str.size() - 2); -} - -std::unordered_set get_syscalls_ppm_codes(const std::unordered_set syscalls_names) -{ - 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_names.find(ppm_sc_name) != syscalls_names.end()) - { - ppm_sc_set.insert(ppm_sc_code); - } - } - return ppm_sc_set; -} - -std::unordered_set get_difference_syscalls_names(std::unordered_set syscalls_names_reference, std::unordered_set syscalls_names_comparison) -{ - std::unordered_set out = syscalls_names_comparison; - for (const auto &ppm_sc_name : syscalls_names_reference) - { - if (syscalls_names_comparison.find(ppm_sc_name) != syscalls_names_comparison.end()) - { - out.erase(ppm_sc_name); - } - } - return out; -} - -void falco::app::actions::check_for_ignored_events(falco::app::state& s) -{ - /* Get the events from the rules. */ - std::set rule_events; - std::string source = falco_common::syscall_source; - s.engine->evttypes_for_ruleset(source, rule_events); - - /* Get PPME events we consider interesting from the application state as idx codes. */ - std::unique_ptr inspector(new sinsp()); - std::unordered_set ppme_events_codes(rule_events.begin(), rule_events.end()); - - auto event_names = inspector->get_events_names(ppme_events_codes); - for (const auto& n : inspector->get_events_names(s.ppm_event_info_of_interest)) - { - event_names.erase(n); - } - - /* Here the `libsinsp` state set is not enough, we need other syscalls used in the rules, - * so we use the `simple_set`, this `simple_set` contains all the syscalls of the `libsinsp` state - * plus syscalls for Falco default rules. - */ - s.ppm_sc_of_interest = inspector->enforce_simple_ppm_sc_set(); - s.ppm_event_info_of_interest = inspector->get_event_set_from_ppm_sc_set(s.ppm_sc_of_interest); - - if(event_names.empty()) - { - return; - } - - /* Get the names of the ignored events (syscall and non syscall events) and print them. */ - std::cerr << "Loaded rules match ignored event types: warning (ignored-evttype): " + concat_syscalls_names(event_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::extract_rules_event_names(falco::app::state& s, std::unique_ptr& inspector, std::unordered_set& rules_evttypes_names) { /* Get all (positive) PPME events from all rules as idx codes. @@ -119,37 +46,25 @@ void falco::app::actions::extract_rules_event_names(falco::app::state& s, std::u rules_evttypes_names = inspector->get_events_names(ppme_events_codes); } -void falco::app::actions::activate_interesting_events(falco::app::state& s, std::unique_ptr& inspector) +void falco::app::actions::check_for_unsupported_events(falco::app::state& s, std::unique_ptr& inspector, const std::unordered_set& rules_evttypes_names) { - s.ppm_event_info_of_interest = inspector->get_event_set_from_ppm_sc_set(s.ppm_sc_of_interest); - - /* Fill-up the set of event infos of interest. This is needed to ensure the critical non syscall PPME events are activated as well, e.g. container or proc exit events. */ - for (uint32_t ev = 2; ev < PPM_EVENT_MAX; ev++) + std::unordered_set intersection = unordered_set_intersection(inspector->get_events_names(s.ppm_event_info_of_interest), rules_evttypes_names); + if(intersection.empty()) { - 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) - { - s.ppm_event_info_of_interest.insert(ev); - } - } + return; } + std::unordered_set unsupported = unordered_set_difference(rules_evttypes_names, inspector->get_events_names(s.ppm_event_info_of_interest)); - /* Reading a scap file we have no concepts of ignored events we read all we need. */ - if(!s.options.all_events && !s.is_capture_mode()) - { - /* Here we have already initialized the application state with the interesting syscalls, - * so we have to check if any event types used by the loaded rules are not considered by - * Falco interesting set. - */ - falco::app::actions::check_for_ignored_events(s); - } + /* 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; + 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) +{ + 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) @@ -159,11 +74,11 @@ void falco::app::actions::activate_interesting_syscalls(falco::app::state& s, st * 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_syscalls_ppm_codes(rules_evttypes_names); + 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) { - falco_logger::log(LOG_INFO, "(" + std::to_string(rules_syscalls_names.size()) + ") syscalls activated in rules: " + concat_syscalls_names(rules_syscalls_names) + "\n"); + falco_logger::log(LOG_DEBUG, "(" + std::to_string(rules_syscalls_names.size()) + ") syscalls activated in rules: " + concat_set_in_order(rules_syscalls_names) + "\n"); } /* @@ -178,15 +93,15 @@ void falco::app::actions::activate_interesting_syscalls(falco::app::state& s, st * */ - /* Derive union of rules_ppm_sc_set (all syscalls defined in Falco rules) and enforced syscalls for libsinsp state and declare ppm_sc_of_interest. */ + // 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 = get_difference_syscalls_names(rules_syscalls_names, inspector->get_syscalls_names(s.ppm_sc_of_interest)); + 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) { - falco_logger::log(LOG_INFO, "+(" + std::to_string(non_rules_syscalls_names.size()) + ") syscalls activated (Falco's set of additional syscalls including syscalls needed for state engine): " + concat_syscalls_names(non_rules_syscalls_names) + "\n"); + 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"); } /* -A flag behavior: @@ -196,23 +111,13 @@ void falco::app::actions::activate_interesting_syscalls(falco::app::state& s, st if(!s.options.all_events) { - std::unordered_set erased_io_syscalls_names = {}; - std::unordered_set cur_ppm_sc_set = s.ppm_sc_of_interest; + 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); - const int bitmask = EC_SYSCALL - 1; - for (const auto &ppm_sc_code : cur_ppm_sc_set) - { - switch(g_infotables.m_syscall_info_table[ppm_sc_code].category & bitmask) - { - case EC_IO_READ: - case EC_IO_WRITE: - s.ppm_sc_of_interest.erase(ppm_sc_code); - erased_io_syscalls_names.insert(g_infotables.m_syscall_info_table[ppm_sc_code].name); - } - } if (erased_io_syscalls_names.size() > 0) { - falco_logger::log(LOG_INFO, "-(" + std::to_string(erased_io_syscalls_names.size()) + ") high volume I/O syscalls (`-A` flag not set): " + concat_syscalls_names(erased_io_syscalls_names) + "\n"); + 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"); } } @@ -220,7 +125,7 @@ void falco::app::actions::activate_interesting_syscalls(falco::app::state& s, st if (final_syscalls_names.size() > 0) { - falco_logger::log(LOG_INFO, "(" + std::to_string(final_syscalls_names.size()) + ") syscalls in total activated (final set): " + concat_syscalls_names(final_syscalls_names) + "\n"); + 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"); } } @@ -244,7 +149,7 @@ falco::app::run_result falco::app::actions::configure_interesting_sets(falco::ap 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); + falco::app::actions::activate_interesting_events(s, inspector, rules_evttypes_names); falco::app::actions::activate_interesting_kernel_tracepoints(s, inspector); 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 f0e8661d..83b26eed 100644 --- a/userspace/falco/app/actions/print_ignored_events.cpp +++ b/userspace/falco/app/actions/print_ignored_events.cpp @@ -33,7 +33,7 @@ falco::app::run_result falco::app::actions::print_ignored_events(falco::app::sta return run_result::ok(); } - /* Search for all the ignored syscalls after having set the syscalls and events of interest in configure_interesting_sets() app action. */ + /* Search for all the ignored syscalls. */ std::unordered_set all_events; for (uint32_t j = 0; j < PPM_EVENT_MAX; j++) { diff --git a/userspace/falco/app/options.cpp b/userspace/falco/app/options.cpp index b53b4846..cf1acf20 100644 --- a/userspace/falco/app/options.cpp +++ b/userspace/falco/app/options.cpp @@ -159,7 +159,7 @@ void options::define() #else ("c", "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "") #endif - ("A", "Monitor all events, including those not interesting to Falco. Please use the -i option to list all ignored events. This option has effect only on live captures.", cxxopts::value(all_events)->default_value("false")) + ("A", "Monitor each event defined in rules and configs + high volume I/O syscalls. Please use the -i option to list the I/O syscalls Falco supports. This option affects live captures only. Setting -A can impact performance.", cxxopts::value(all_events)->default_value("false")) ("b,print-base64", "Print data buffers in base64. This is useful for encoding binary data that needs to be used over media designed to consume this format.") ("cri", "Path to CRI socket for container metadata. Use the specified socket to fetch data from a CRI-compatible runtime. If not specified, uses the libs default. This option can be passed multiple times to specify socket to be tried until a successful one is found.", cxxopts::value(cri_socket_paths), "") ("d,daemon", "Run as a daemon.", cxxopts::value(daemon)->default_value("false")) @@ -176,7 +176,7 @@ void options::define() #ifdef HAS_MODERN_BPF ("modern-bpf", "[EXPERIMENTAL] Use BPF modern probe to capture system events.", cxxopts::value(modern_bpf)->default_value("false")) #endif - ("i", "Print all events that are ignored by default (i.e. without the -A flag) and exit.", cxxopts::value(print_ignored_events)->default_value("false")) + ("i", "Print all high volume I/O syscalls that are ignored by default (i.e. without the -A flag) and exit.", cxxopts::value(print_ignored_events)->default_value("false")) #ifndef MINIMAL_BUILD ("k,k8s-api", "Enable Kubernetes support by connecting to the API server specified as argument. E.g. \"http://admin:password@127.0.0.1:8080\". The API server can also be specified via the environment variable FALCO_K8S_API.", cxxopts::value(k8s_api), "") ("K,k8s-api-cert", "Use the provided files names to authenticate user and (optionally) verify the K8S API server identity. Each entry must specify full (absolute, or relative to the current directory) path to the respective file. Private key password is optional (needed only if key is password protected). CA certificate is optional. For all files, only PEM file format is supported. Specifying CA certificate only is obsoleted - when single entry is provided for this option, it will be interpreted as the name of a file containing bearer token. Note that the format of this command-line option prohibits use of files whose names contain ':' or '#' characters in the file name.", cxxopts::value(k8s_api_cert), "( | :[:])") diff --git a/userspace/falco/application.cpp b/userspace/falco/application.cpp index 98fe7e05..835bff48 100644 --- a/userspace/falco/application.cpp +++ b/userspace/falco/application.cpp @@ -176,6 +176,8 @@ bool application::run(std::string &errstr, bool &restart) std::bind(&application::print_help, this), std::bind(&application::print_version, this), std::bind(&application::print_page_size, this), + std::bind(&application::print_ignored_events, this), + std::bind(&application::print_syscall_events, this), std::bind(&application::print_generated_gvisor_config, this), std::bind(&application::require_config_file, this), std::bind(&application::print_plugin_info, this), @@ -195,8 +197,6 @@ bool application::run(std::string &errstr, bool &restart) std::bind(&application::init_outputs, this), std::bind(&application::init_clients, this), std::bind(&application::configure_interesting_sets, this), - std::bind(&application::print_ignored_events, this), - std::bind(&application::print_syscall_events, this), std::bind(&application::configure_syscall_buffer_size, this), #ifndef MINIMAL_BUILD std::bind(&application::start_grpc_server, this), diff --git a/userspace/falco/application.h b/userspace/falco/application.h index 38bf23f8..fbeac822 100644 --- a/userspace/falco/application.h +++ b/userspace/falco/application.h @@ -350,11 +350,11 @@ private: int create_dir(const std::string &path); bool create_handler(int sig, void (*func)(int), run_result &ret); void configure_output_format(); - void check_for_ignored_events(); + void check_for_unsupported_events(std::unique_ptr& inspector, const std::unordered_set& rules_evttypes_names); bool check_rules_plugin_requirements(std::string& err); - void extract_rules_event_names(std::unique_ptr& inspector, std::unordered_set& rules_evttypes_names); // should be called before syscalls and events activations + std::unordered_set extract_rules_event_names(std::unique_ptr& inspector); // should be called before syscalls and events activations void activate_interesting_syscalls(std::unique_ptr& inspector, const std::unordered_set& rules_evttypes_names); - void activate_interesting_events(std::unique_ptr& inspector); // should be called after calling activate_interesting_syscalls + void activate_interesting_events(std::unique_ptr& inspector, const std::unordered_set& rules_evttypes_names); // should be called after calling activate_interesting_syscalls void activate_interesting_kernel_tracepoints(std::unique_ptr& inspector); // independent of syscalls and events activations in terms of order void format_plugin_info(std::shared_ptr p, std::ostream& os) const; run_result open_offline_inspector();