Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

update: improve control and UX of ignored events #2509

Merged
merged 1 commit into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions unit_tests/falco/app/actions/test_configure_interesting_sets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.

#include <falco_engine.h>

#include <falco/app/app.h>
#include <falco/app/state.h>
#include <falco/app/actions/actions.h>

Expand Down Expand Up @@ -199,14 +200,14 @@ TEST(ConfigureInterestingSets, selection_not_allevents)
ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names);

// check that all IO syscalls have been erased from the selection
auto io_set = libsinsp::events::io_sc_set();
auto erased_sc_names = libsinsp::events::sc_set_to_event_names(io_set);
auto ignored_set = falco::app::ignored_sc_set();
auto erased_sc_names = libsinsp::events::sc_set_to_event_names(ignored_set);
ASSERT_NAMES_NOCONTAIN(selected_sc_names, erased_sc_names);

// check that final selected set is exactly sinsp state + ruleset
auto rule_set = s2.engine->sc_codes_for_ruleset(s_sample_source, s_sample_ruleset);
auto state_set = libsinsp::events::sinsp_state_sc_set();
for (const auto &erased : io_set)
for (const auto &erased : ignored_set)
{
rule_set.remove(erased);
state_set.remove(erased);
Expand Down Expand Up @@ -273,7 +274,7 @@ TEST(ConfigureInterestingSets, selection_generic_evts)
"socket", "bind", "close" // from sinsp state set (network, files)
});
ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names);
auto unexpected_sc_names = libsinsp::events::sc_set_to_event_names(libsinsp::events::io_sc_set());
auto unexpected_sc_names = libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set());
ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names);
}

Expand Down Expand Up @@ -361,7 +362,7 @@ TEST(ConfigureInterestingSets, selection_custom_base_set)
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "procexit"
});
ASSERT_NAMES_EQ(selected_sc_names, expected_sc_names);
auto unexpected_sc_names = libsinsp::events::sc_set_to_event_names(libsinsp::events::io_sc_set());
auto unexpected_sc_names = libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set());
ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names);
}

Expand Down Expand Up @@ -389,7 +390,7 @@ TEST(ConfigureInterestingSets, selection_custom_base_set_repair)
"bind", "socket", "clone3", "close", "setuid"
});
ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names);
auto unexpected_sc_names = libsinsp::events::sc_set_to_event_names(libsinsp::events::io_sc_set());
auto unexpected_sc_names = libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set());
ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names);
}

Expand Down Expand Up @@ -418,3 +419,13 @@ TEST(ConfigureInterestingSets, selection_empty_custom_base_set_repair)
ASSERT_EQ(s7.selected_sc_set, s7_state_set);
ASSERT_EQ(s7.selected_sc_set.size(), s7_state_set.size());
}

TEST(ConfigureInterestingSets, ignored_set_expected_size)
{
// unit test fence to make sure we don't have unexpected regressions
// in the ignored set, to be updated in the future
ASSERT_EQ(falco::app::ignored_sc_set().size(), 14);

// we don't expect to ignore any syscall in the default base set
ASSERT_EQ(falco::app::ignored_sc_set().intersect(libsinsp::events::sinsp_state_sc_set()).size(), 0);
}
12 changes: 7 additions & 5 deletions userspace/falco/app/actions/configure_interesting_sets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ limitations under the License.
*/

#include "actions.h"
#include "helpers.h"
#include "../app.h"

using namespace falco::app;
using namespace falco::app::actions;
Expand Down Expand Up @@ -44,7 +46,7 @@ static void check_for_rules_unsupported_events(falco::app::state& s, const libsi
{
/* 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
* is expected to happen only for high volume syscalls for
* performance reasons. */
auto unsupported_sc_set = rules_sc_set.diff(s.selected_sc_set);
if (unsupported_sc_set.empty())
Expand All @@ -55,7 +57,7 @@ static void check_for_rules_unsupported_events(falco::app::state& s, const libsi
/* Get the names of the events (syscall and non syscall events) that were not activated and print them. */
auto names = libsinsp::events::sc_set_to_event_names(unsupported_sc_set);
std::cerr << "Loaded rules match syscalls that are not activated (e.g. were removed via config settings such as no -A flag or negative base_syscalls elements) 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 syscalls may have been removed via base_syscalls option or might be associated with syscalls undefined on your architecture (https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html)" << std::endl;
std::cerr << "If syscalls in rules include high volume syscalls (-> activate via `-A` flag), else syscalls may have been removed via base_syscalls option or might be associated with syscalls undefined on your architecture (https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html)" << std::endl;
}

static void select_event_set(falco::app::state& s, const libsinsp::events::set<ppm_sc_code>& rules_sc_set)
Expand Down Expand Up @@ -158,12 +160,12 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p

/* -A flag behavior:
* (1) default: all syscalls in rules included, sinsp state enforcement
without high volume I/O syscalls
without high volume syscalls
* (2) -A flag set: all syscalls in rules included, sinsp state enforcement
and allowing high volume I/O syscalls */
and allowing high volume syscalls */
if(!s.options.all_events)
{
auto ignored_sc_set = libsinsp::events::io_sc_set();
auto ignored_sc_set = falco::app::ignored_sc_set();
auto erased_sc_set = s.selected_sc_set.intersect(ignored_sc_set);
s.selected_sc_set = s.selected_sc_set.diff(ignored_sc_set);
if (!erased_sc_set.empty())
Expand Down
5 changes: 3 additions & 2 deletions userspace/falco/app/actions/print_ignored_events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.

#include "actions.h"
#include "helpers.h"
#include "../app.h"

using namespace falco::app;
using namespace falco::app::actions;
Expand All @@ -27,8 +28,8 @@ falco::app::run_result falco::app::actions::print_ignored_events(falco::app::sta
return run_result::ok();
}

std::cout << "Ignored I/O syscall(s):" << std::endl;
for(const auto& it : libsinsp::events::sc_set_to_event_names(libsinsp::events::io_sc_set()))
std::cout << "Ignored syscall(s):" << std::endl;
for(const auto& it : libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set()))
{
std::cout << "- " << it.c_str() << std::endl;
}
Expand Down
9 changes: 9 additions & 0 deletions userspace/falco/app/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ falco::atomic_signal_handler falco::app::g_reopen_outputs_signal;

using app_action = std::function<falco::app::run_result(falco::app::state&)>;

libsinsp::events::set<ppm_sc_code> falco::app::ignored_sc_set()
{
// we ignore all the I/O syscalls that can have very high throughput and
// that can badly impact performance. Of those, we avoid ignoring the
// ones that are part of the base set used by libsinsp for maintaining
// its internal state.
return libsinsp::events::io_sc_set().diff(libsinsp::events::sinsp_state_sc_set());
}

bool falco::app::run(int argc, char** argv, bool& restart, std::string& errstr)
{
falco::app::state s;
Expand Down
3 changes: 3 additions & 0 deletions userspace/falco/app/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ limitations under the License.
namespace falco {
namespace app {

libsinsp::events::set<ppm_sc_code> ignored_sc_set();

bool run(int argc, char** argv, bool& restart, std::string& errstr);

bool run(falco::app::state& s, bool& restart, std::string& errstr);

}; // namespace app
Expand Down
4 changes: 2 additions & 2 deletions userspace/falco/app/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ void options::define(cxxopts::Options& opts)
#else
("c", "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
#endif
("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"))
("A", "Monitor all events supported by Falco defined in rules and configs. Please use the -i option to list the events ignored by default without -A. 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"))
Expand All @@ -182,7 +182,7 @@ void options::define(cxxopts::Options& opts)
#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 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"))
("i", "Print all high volume syscalls that are ignored by default for performance reasons (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>])")
Expand Down