mirror of
https://github.com/falcosecurity/falco.git
synced 2025-07-30 21:55:56 +00:00
cleanup(app_actions): adjust configure_interesting_sets
* address reviewers feedback * improve clarity around new -A and -i behavior * additional cleanup (e.g. use generic set operations only) * extend unit tests Note: sinsp ppm sc API is undergoing a refactor, therefore current lookups are interim and will subsequently be refactored as well. Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com> Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
This commit is contained in:
parent
f77f8667a1
commit
72439b2eed
@ -15,12 +15,14 @@ limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
#include "falco_utils.h"
|
||||
#include "evttype_index_ruleset.h"
|
||||
#include <filter/parser.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace libsinsp::filter;
|
||||
using namespace falco::utils;
|
||||
|
||||
static std::shared_ptr<gen_event_filter_factory> create_factory()
|
||||
{
|
||||
@ -52,7 +54,7 @@ static std::shared_ptr<filter_ruleset> create_ruleset(
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::shared_ptr<filter_ruleset> get_test_rulesets(std::unordered_set<std::string> fltstrs)
|
||||
static std::shared_ptr<filter_ruleset> get_test_rulesets(const std::unordered_set<std::string>& fltstrs)
|
||||
{
|
||||
auto f = create_factory();
|
||||
auto r = create_ruleset(f);
|
||||
@ -70,20 +72,9 @@ static std::shared_ptr<filter_ruleset> get_test_rulesets(std::unordered_set<std:
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::set<T> unordered_set_to_ordered(std::unordered_set<T> unordered_set)
|
||||
void compare_evttypes_names(const std::unordered_set<std::string>& actual, const std::unordered_set<std::string>& expected)
|
||||
{
|
||||
std::set<T> s;
|
||||
for(const auto& val : unordered_set)
|
||||
{
|
||||
s.insert(val);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template std::set<std::string> unordered_set_to_ordered(std::unordered_set<std::string> unordered_set);
|
||||
|
||||
void compare_evttypes_names(std::unordered_set<std::string> &actual, std::unordered_set<std::string> &expected)
|
||||
{
|
||||
ASSERT_EQ(actual.size(), expected.size());
|
||||
std::set<std::string> actual_sorted = unordered_set_to_ordered(actual);
|
||||
std::set<std::string> expected_sorted = unordered_set_to_ordered(expected);
|
||||
@ -97,7 +88,7 @@ void compare_evttypes_names(std::unordered_set<std::string> &actual, std::unorde
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> extract_rules_event_names(std::unique_ptr<sinsp>& inspector, std::shared_ptr<filter_ruleset> r)
|
||||
std::unordered_set<std::string> extract_rules_event_names(std::unique_ptr<sinsp>& inspector, std::shared_ptr<filter_ruleset>& r)
|
||||
{
|
||||
std::set<uint16_t> rule_events;
|
||||
r->enabled_evttypes(rule_events, 0);
|
||||
@ -105,20 +96,6 @@ std::unordered_set<std::string> extract_rules_event_names(std::unique_ptr<sinsp>
|
||||
return inspector->get_events_names(ppme_events_codes);
|
||||
}
|
||||
|
||||
std::unordered_set<uint32_t> get_syscalls_ppm_codes(const std::unordered_set<std::string> syscalls_names)
|
||||
{
|
||||
std::unordered_set<uint32_t> 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<std::string> &total_enforced, std::unordered_set<std::string> &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<std::string> 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<std::string> base_syscalls_sinsp_state_spawned_process = {"clone", "clone3", "fork", "vfork"};
|
||||
std::unordered_set<std::string> base_syscalls_sinsp_state_network = {"socket", "bind", "close"};
|
||||
std::unordered_set<std::string> base_events = {"procexit", "container"};
|
||||
std::unordered_set<std::string> 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<uint32_t> rules_ppm_sc_set = get_syscalls_ppm_codes(rules_evttypes_names);
|
||||
std::unordered_set<uint32_t> rules_ppm_sc_set = get_ppm_sc_set_from_syscalls(rules_evttypes_names);
|
||||
std::unordered_set<std::string> 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<uint32_t> ppm_sc_of_interest = inspector->enforce_simple_ppm_sc_set(rules_ppm_sc_set);
|
||||
std::unordered_set<std::string> 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<std::string> erased_io_syscalls_names = erase_io_syscalls(ppm_sc_of_interest);
|
||||
std::unordered_set<uint32_t> io_ppm_sc_set = enforce_io_ppm_sc_set();
|
||||
std::unordered_set<std::string> 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<uint32_t> 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<std::string> 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);
|
||||
|
||||
}
|
||||
|
@ -16,19 +16,201 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sinsp.h>
|
||||
|
||||
#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<uint32_t> get_ppm_sc_set_from_syscalls(const std::unordered_set<std::string>& syscalls)
|
||||
{
|
||||
std::unordered_set<uint32_t> 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<uint32_t> enforce_io_ppm_sc_set(std::unordered_set<uint32_t> 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<uint32_t> enforce_sinsp_state_ppme(std::unordered_set<uint32_t> 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<typename T>
|
||||
std::set<T> unordered_set_to_ordered(const std::unordered_set<T>& unordered_set)
|
||||
{
|
||||
std::set<T> s;
|
||||
for(const auto& val : unordered_set)
|
||||
{
|
||||
s.insert(val);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template std::set<uint32_t> unordered_set_to_ordered(const std::unordered_set<uint32_t>& unordered_set);
|
||||
template std::set<std::string> unordered_set_to_ordered(const std::unordered_set<std::string>& unordered_set);
|
||||
|
||||
// unordered_set_difference, equivalent to SQL left_anti join operation
|
||||
template<typename T>
|
||||
std::unordered_set<T> unordered_set_difference(const std::unordered_set<T>& a, const std::unordered_set<T>& b)
|
||||
{
|
||||
std::unordered_set<T> s;
|
||||
for(const auto& val : a)
|
||||
{
|
||||
if (b.find(val) == b.end())
|
||||
{
|
||||
s.insert(val);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template std::unordered_set<std::string> unordered_set_difference(const std::unordered_set<std::string>& a, const std::unordered_set<std::string>& b);
|
||||
template std::unordered_set<uint32_t> unordered_set_difference(const std::unordered_set<uint32_t>& a, const std::unordered_set<uint32_t>& b);
|
||||
|
||||
// set_difference, equivalent to SQL left_anti join operation
|
||||
template<typename T>
|
||||
std::set<T> set_difference(const std::set<T>& a, const std::set<T>& b)
|
||||
{
|
||||
std::set<T> out;
|
||||
std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::inserter(out, out.begin()));
|
||||
return out;
|
||||
}
|
||||
template std::set<std::string> set_difference(const std::set<std::string>& a, const std::set<std::string>& b);
|
||||
template std::set<uint32_t> set_difference(const std::set<uint32_t>& a, const std::set<uint32_t>& b);
|
||||
|
||||
// unordered_set_union
|
||||
template<typename T>
|
||||
std::unordered_set<T> unordered_set_union(const std::unordered_set<T>& a, const std::unordered_set<T>& b)
|
||||
{
|
||||
std::unordered_set<T> s = a;
|
||||
for(const auto& val : b)
|
||||
{
|
||||
s.insert(val);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template std::unordered_set<std::string> unordered_set_union(const std::unordered_set<std::string>& a, const std::unordered_set<std::string>& b);
|
||||
template std::unordered_set<uint32_t> unordered_set_union(const std::unordered_set<uint32_t>& a, const std::unordered_set<uint32_t>& b);
|
||||
|
||||
// set_union
|
||||
template<typename T>
|
||||
std::set<T> set_union(const std::set<T>& a, const std::set<T>& b)
|
||||
{
|
||||
std::set<T> out;
|
||||
std::set_union(a.begin(), a.end(), b.begin(), b.end(), std::inserter(out, out.begin()));
|
||||
return out;
|
||||
}
|
||||
template std::set<std::string> set_union(const std::set<std::string>& a, const std::set<std::string>& b);
|
||||
template std::set<uint32_t> set_union(const std::set<uint32_t>& a, const std::set<uint32_t>& b);
|
||||
|
||||
// unordered_set_intersection
|
||||
template<typename T>
|
||||
std::unordered_set<T> unordered_set_intersection(const std::unordered_set<T>& a, const std::unordered_set<T>& b)
|
||||
{
|
||||
std::unordered_set<T> s;
|
||||
for(const auto& val : a)
|
||||
{
|
||||
if (b.find(val) != b.end())
|
||||
{
|
||||
s.insert(val);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template std::unordered_set<std::string> unordered_set_intersection(const std::unordered_set<std::string>& a, const std::unordered_set<std::string>& b);
|
||||
template std::unordered_set<uint32_t> unordered_set_intersection(const std::unordered_set<uint32_t>& a, const std::unordered_set<uint32_t>& b);
|
||||
|
||||
// set_intersection
|
||||
template<typename T>
|
||||
std::set<T> set_intersection(const std::set<T>& a, const std::set<T>& b)
|
||||
{
|
||||
std::set<T> out;
|
||||
std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::inserter(out, out.begin()));
|
||||
return out;
|
||||
}
|
||||
template std::set<std::string> set_intersection(const std::set<std::string>& a, const std::set<std::string>& b);
|
||||
template std::set<uint32_t> set_intersection(const std::set<uint32_t>& a, const std::set<uint32_t>& b);
|
||||
|
||||
std::string concat_set_in_order(const std::unordered_set<std::string>& s, const std::string& delim)
|
||||
{
|
||||
if (s.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::set<std::string> s_ordered = unordered_set_to_ordered(s);
|
||||
std::stringstream ss;
|
||||
std::copy(s_ordered.begin(), s_ordered.end(),
|
||||
std::ostream_iterator<std::string>(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<std::string>& s, const std::string& delim)
|
||||
{
|
||||
if (s.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::stringstream ss;
|
||||
std::copy(s.begin(), s.end(),
|
||||
std::ostream_iterator<std::string>(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);
|
||||
|
@ -24,6 +24,10 @@ limitations under the License.
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#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<uint32_t> get_ppm_sc_set_from_syscalls(const std::unordered_set<std::string>& syscalls);
|
||||
std::unordered_set<uint32_t> enforce_sinsp_state_ppme(std::unordered_set<uint32_t> ppm_event_info_of_interest = {});
|
||||
std::unordered_set<uint32_t> enforce_io_ppm_sc_set(std::unordered_set<uint32_t> ppm_sc_set = {}); // needs libs bump hence duplicated in meantime
|
||||
// end interim helper methods
|
||||
|
||||
// TODO interim libs utils methods
|
||||
template<typename T>
|
||||
std::set<T> unordered_set_to_ordered(const std::unordered_set<T>& unordered_set);
|
||||
|
||||
template<typename T>
|
||||
std::unordered_set<T> unordered_set_difference(const std::unordered_set<T>& a, const std::unordered_set<T>& b);
|
||||
|
||||
template<typename T>
|
||||
std::set<T> set_difference(const std::set<T>& a, const std::set<T>& b);
|
||||
|
||||
template<typename T>
|
||||
std::unordered_set<T> unordered_set_union(const std::unordered_set<T>& a, const std::unordered_set<T>& b);
|
||||
|
||||
template<typename T>
|
||||
std::set<T> set_union(const std::set<T>& a, const std::set<T>& b);
|
||||
|
||||
template<typename T>
|
||||
std::unordered_set<T> unordered_set_intersection(const std::unordered_set<T>& a, const std::unordered_set<T>& b);
|
||||
|
||||
template<typename T>
|
||||
std::set<T> set_intersection(const std::set<T>& a, const std::set<T>& b);
|
||||
|
||||
std::string concat_set_in_order(const std::unordered_set<std::string>& s, const std::string& delim = ", ");
|
||||
std::string concat_set_in_order(const std::set<std::string>& 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);
|
||||
|
@ -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<sinsp>& inspector, std::unordered_set<std::string>& rules_evttypes_names);
|
||||
void activate_interesting_events(falco::app::state& s, std::unique_ptr<sinsp>& inspector);
|
||||
void activate_interesting_events(falco::app::state& s, std::unique_ptr<sinsp>& inspector, const std::unordered_set<std::string>& rules_evttypes_names);
|
||||
void check_for_unsupported_events(falco::app::state& s, std::unique_ptr<sinsp>& inspector, const std::unordered_set<std::string>& rules_evttypes_names);
|
||||
void activate_interesting_syscalls(falco::app::state& s, std::unique_ptr<sinsp>& inspector, const std::unordered_set<std::string>& rules_evttypes_names);
|
||||
void activate_interesting_kernel_tracepoints(falco::app::state& s, std::unique_ptr<sinsp>& inspector);
|
||||
void check_for_ignored_events(falco::app::state& s);
|
||||
|
@ -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 <unordered_set>
|
||||
#include <sinsp.h>
|
||||
#include <sstream>
|
||||
|
||||
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<std::string> const syscalls_names)
|
||||
{
|
||||
std::set<std::string> 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<std::string>(ss, ", "));
|
||||
std::string syscalls_names_str = ss.str();
|
||||
return syscalls_names_str.substr(0, syscalls_names_str.size() - 2);
|
||||
}
|
||||
|
||||
std::unordered_set<uint32_t> get_syscalls_ppm_codes(const std::unordered_set<std::string> syscalls_names)
|
||||
{
|
||||
std::unordered_set<uint32_t> 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<std::string> get_difference_syscalls_names(std::unordered_set<std::string> syscalls_names_reference, std::unordered_set<std::string> syscalls_names_comparison)
|
||||
{
|
||||
std::unordered_set<std::string> 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<uint16_t> 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<sinsp> inspector(new sinsp());
|
||||
std::unordered_set<uint32_t> 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<sinsp>& inspector, std::unordered_set<std::string>& 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<sinsp>& inspector)
|
||||
void falco::app::actions::check_for_unsupported_events(falco::app::state& s, std::unique_ptr<sinsp>& inspector, const std::unordered_set<std::string>& 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<std::string> 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<std::string> 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<sinsp>& inspector, const std::unordered_set<std::string>& rules_evttypes_names)
|
||||
{
|
||||
std::unordered_set<uint32_t> 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<sinsp>& inspector, const std::unordered_set<std::string>& 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<uint32_t> rules_ppm_sc_set = get_syscalls_ppm_codes(rules_evttypes_names);
|
||||
std::unordered_set<uint32_t> rules_ppm_sc_set = get_ppm_sc_set_from_syscalls(rules_evttypes_names);
|
||||
std::unordered_set<std::string> 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<std::string> non_rules_syscalls_names = get_difference_syscalls_names(rules_syscalls_names, inspector->get_syscalls_names(s.ppm_sc_of_interest));
|
||||
std::unordered_set<std::string> 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<std::string> erased_io_syscalls_names = {};
|
||||
std::unordered_set<uint32_t> cur_ppm_sc_set = s.ppm_sc_of_interest;
|
||||
std::unordered_set<uint32_t> io_ppm_sc_set = enforce_io_ppm_sc_set();
|
||||
std::unordered_set<std::string> 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();
|
||||
|
@ -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<uint32_t> all_events;
|
||||
for (uint32_t j = 0; j < PPM_EVENT_MAX; j++)
|
||||
{
|
||||
|
@ -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), "<path>")
|
||||
#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), "<path>")
|
||||
("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), "<url>")
|
||||
("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), "(<bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>])")
|
||||
|
@ -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),
|
||||
|
@ -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<sinsp>& inspector, const std::unordered_set<std::string>& rules_evttypes_names);
|
||||
bool check_rules_plugin_requirements(std::string& err);
|
||||
void extract_rules_event_names(std::unique_ptr<sinsp>& inspector, std::unordered_set<std::string>& rules_evttypes_names); // should be called before syscalls and events activations
|
||||
std::unordered_set<std::string> extract_rules_event_names(std::unique_ptr<sinsp>& inspector); // should be called before syscalls and events activations
|
||||
void activate_interesting_syscalls(std::unique_ptr<sinsp>& inspector, const std::unordered_set<std::string>& rules_evttypes_names);
|
||||
void activate_interesting_events(std::unique_ptr<sinsp>& inspector); // should be called after calling activate_interesting_syscalls
|
||||
void activate_interesting_events(std::unique_ptr<sinsp>& inspector, const std::unordered_set<std::string>& rules_evttypes_names); // should be called after calling activate_interesting_syscalls
|
||||
void activate_interesting_kernel_tracepoints(std::unique_ptr<sinsp>& inspector); // independent of syscalls and events activations in terms of order
|
||||
void format_plugin_info(std::shared_ptr<sinsp_plugin> p, std::ostream& os) const;
|
||||
run_result open_offline_inspector();
|
||||
|
Loading…
Reference in New Issue
Block a user