chore(userspace,falco.yaml): rename new config key to driver.kind.

Moreover, renamed driver kinds to use better naming, and move driver's related
config keys under `driver.$kind`.

Added DEPRECTATION notices on CLI options, and in falco.yaml.

DEPRECATED options (both CLI and config ones) will have priority over the new ones,
to retain compatibility with existing configs.

DEPRECATED options will be dropped in Falco 0.38.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
This commit is contained in:
Federico Di Pierro 2023-11-14 11:59:03 +01:00 committed by poiana
parent 626e609e4b
commit 4f1b950e0d
12 changed files with 277 additions and 120 deletions

View File

@ -62,8 +62,8 @@
# syscall_event_timeouts # syscall_event_timeouts
# syscall_event_drops # syscall_event_drops
# metrics # metrics
# Falco driver selection # Falco driver
# driver_mode # driver
# Falco performance tuning (advanced) # Falco performance tuning (advanced)
# syscall_buf_size_preset # syscall_buf_size_preset
# syscall_drop_failed_exit # syscall_drop_failed_exit
@ -96,7 +96,7 @@
# - "HOST_ROOT": Specifies the prefix to the underlying host `/proc` filesystem # - "HOST_ROOT": Specifies the prefix to the underlying host `/proc` filesystem
# when deploying Falco over a container with read-only host mounts instead of # when deploying Falco over a container with read-only host mounts instead of
# directly on the host. Defaults to "/host". # directly on the host. Defaults to "/host".
# - "FALCO_BPF_PROBE": Specify a custom path to the BPF object code file (`bpf` # - "FALCO_BPF_PROBE": DEPRECATED. Specify a custom path to the BPF object code file (`bpf`
# driver). This is not needed for the modern_bpf driver. # driver). This is not needed for the modern_bpf driver.
# - "FALCO_HOSTNAME": Customize the hostname output field logged by Falco by # - "FALCO_HOSTNAME": Customize the hostname output field logged by Falco by
# setting the "FALCO_HOSTNAME" environment variable. # setting the "FALCO_HOSTNAME" environment variable.
@ -771,11 +771,11 @@ metrics:
convert_memory_to_mb: true convert_memory_to_mb: true
include_empty_values: false include_empty_values: false
############################################### ################
# Falco driver selection # # Falco driver #
############################################### ################
# [Stable] `driver_mode` # [Stable] `driver`
# #
# --- [Description] # --- [Description]
# #
@ -784,32 +784,45 @@ metrics:
# Falco with your system. Choose the appropriate driver mode based on your # Falco with your system. Choose the appropriate driver mode based on your
# system's configuration and requirements. # system's configuration and requirements.
# #
# Available driver modes: # Available driver kinds:
# - `kmod`: Kernel Module (Kernel Module) # - `kmod`: Kernel Module (Kernel Module)
# - `bpf`: eBPF (Extended Berkeley Packet Filter) # - `ebpf`: eBPF (Extended Berkeley Packet Filter)
# - `modern_bpf`: Modern eBPF (Modern Extended Berkeley Packet Filter) # - `modern-ebpf`: Modern eBPF (Modern Extended Berkeley Packet Filter), available only for recent kernels
# - `nodriver`: No Driver (No driver, just for testing) # - `none`: No Driver (No driver loaded, useful to run `syscall` source plugin or just plugins without loading any driver)
# - `gvisor`: gVisor (gVisor sandbox) # - `gvisor`: gVisor (gVisor sandbox)
# - `custom`: Custom Driver (Specify a custom driver module) # - `replay`: Replay a scap file
# Example usage:
# driver_mode: kmod
# Select the appropriate driver mode by uncommenting the corresponding line. # Select the appropriate driver mode by uncommenting the corresponding line.
# Make sure to specify only one driver mode at a time. # Make sure to specify only one driver mode at a time.
# Moreover, for each driver multiple options might be available and are grouped
# under the `driver.$kind` configuration key.
driver_mode: kmod driver:
# driver_mode: bpf kind: kmod
# driver_mode: modern_bpf kmod:
# driver_mode: nodriver buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset
# driver_mode: gvisor drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit
# driver_mode: custom ebpf:
probe: /path/to/probe.o
buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset
drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit
modern-ebpf:
cpus_for_each_syscall_buffer: 2 # Overridden by deprecated cpus_for_each_syscall_buffer
buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset
drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit
replay:
scap_file: /path/to/file.scap
gvisor:
config: /path/to/gvisor.yaml
root: /gvisor/root
####################################### #######################################
# Falco performance tuning (advanced) # # Falco performance tuning (advanced) #
####################################### #######################################
# [Stable] `syscall_buf_size_preset` # [DEPRECATED] `syscall_buf_size_preset`
#
# Deprecated in favor of driver.{kmod,ebpf,modern-ebpf}.buf_size_preset
# #
# --- [Description] # --- [Description]
# #
@ -861,10 +874,11 @@ driver_mode: kmod
# if the default size is not suitable for your use case. # if the default size is not suitable for your use case.
syscall_buf_size_preset: 4 syscall_buf_size_preset: 4
# [Experimental] `syscall_drop_failed_exit` # [DEPRECATED] `syscall_drop_failed_exit`
# Deprecated in favor of driver.{kmod,ebpf,modern-ebpf}.drop_failed_exit
# #
# Enabling this option in Falco allows it to drop failed system call exit events # Enabling this option in Falco allows it to drop failed system call exit events
# in the kernel driver before pushing them onto the ring buffer. This # in the kernel drivers before pushing them onto the ring buffer. This
# optimization can result in lower CPU usage and more efficient utilization of # optimization can result in lower CPU usage and more efficient utilization of
# the ring buffer, potentially reducing the number of event losses. However, it # the ring buffer, potentially reducing the number of event losses. However, it
# is important to note that enabling this option also means sacrificing some # is important to note that enabling this option also means sacrificing some
@ -986,7 +1000,9 @@ base_syscalls:
custom_set: [] custom_set: []
repair: false repair: false
# [Stable] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only # [DEPRECATED] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only
#
# Deprecated in favor of driver.modern-ebpf.cpus_for_each_syscall_buffer
# #
# --- [Description] # --- [Description]
# #

View File

@ -39,9 +39,9 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs)
{ {
falco::app::state s; falco::app::state s;
s.options.modern_bpf = true; s.options.modern_bpf = true;
s.config->m_cpus_for_each_syscall_buffer = online_cpus + 1; s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer = online_cpus + 1;
EXPECT_ACTION_OK(action(s)); EXPECT_ACTION_OK(action(s));
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, online_cpus); EXPECT_EQ(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer, online_cpus);
} }
// modern bpf engine, with an valid number of CPUs // modern bpf engine, with an valid number of CPUs
@ -49,8 +49,8 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs)
{ {
falco::app::state s; falco::app::state s;
s.options.modern_bpf = true; s.options.modern_bpf = true;
s.config->m_cpus_for_each_syscall_buffer = online_cpus - 1; s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer = online_cpus - 1;
EXPECT_ACTION_OK(action(s)); EXPECT_ACTION_OK(action(s));
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, online_cpus - 1); EXPECT_EQ(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer, online_cpus - 1);
} }
} }

View File

@ -30,7 +30,7 @@ TEST(ActionSelectEventSources, pre_post_conditions)
// ignore source selection in capture mode // ignore source selection in capture mode
{ {
falco::app::state s; falco::app::state s;
s.options.trace_filename = "some_capture_file.scap"; s.config->m_driver_mode = driver_mode_type::REPLAY;
EXPECT_TRUE(s.is_capture_mode()); EXPECT_TRUE(s.is_capture_mode());
EXPECT_ACTION_OK(action(s)); EXPECT_ACTION_OK(action(s));
} }

View File

@ -34,10 +34,10 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco::
return run_result::fatal("cannot get the number of online CPUs from the system\n"); return run_result::fatal("cannot get the number of online CPUs from the system\n");
} }
if(s.config->m_cpus_for_each_syscall_buffer > online_cpus) if(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer > online_cpus)
{ {
falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_cpus_for_each_syscall_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n"); falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n");
s.config->m_cpus_for_each_syscall_buffer = online_cpus; s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer = online_cpus;
} }
#endif #endif
return run_result::ok(); return run_result::ok();

View File

@ -28,18 +28,12 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco::app::state& s) falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco::app::state& s)
{ {
#ifdef __linux__ #ifdef __linux__
/* We don't need to compute the syscall buffer dimension if we are in capture mode or if the auto index = s.driver_buf_size_preset();
* the syscall source is not enabled. if (index == -1)
*/
if(s.is_capture_mode()
|| !s.is_source_enabled(falco_common::syscall_source)
|| s.is_gvisor_enabled()
|| s.options.nodriver)
{ {
// Chosen driver kind does not support this option.
return run_result::ok(); return run_result::ok();
} }
uint16_t index = s.config->m_syscall_buf_size_preset;
if(index < MIN_INDEX || index > MAX_INDEX) if(index < MIN_INDEX || index > MAX_INDEX)
{ {
return run_result::fatal("The 'syscall_buf_size_preset' value must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n"); return run_result::fatal("The 'syscall_buf_size_preset' value must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n");

View File

@ -28,9 +28,6 @@ limitations under the License.
#define PATH_MAX 260 #define PATH_MAX 260
#endif #endif
/* DEPRECATED: we will remove it in Falco 0.34. */
#define FALCO_BPF_ENV_VARIABLE "FALCO_BPF_PROBE"
using namespace falco::app; using namespace falco::app;
using namespace falco::app::actions; using namespace falco::app::actions;
@ -38,13 +35,13 @@ falco::app::run_result falco::app::actions::open_offline_inspector(falco::app::s
{ {
try try
{ {
s.offline_inspector->open_savefile(s.options.trace_filename); s.offline_inspector->open_savefile(s.config->m_replay.m_scap_file);
falco_logger::log(falco_logger::level::INFO, "Reading system call events from file: " + s.options.trace_filename + "\n"); falco_logger::log(falco_logger::level::INFO, "Reading system call events from file: " + s.config->m_replay.m_scap_file + "\n");
return run_result::ok(); return run_result::ok();
} }
catch (sinsp_exception &e) catch (sinsp_exception &e)
{ {
return run_result::fatal("Could not open trace filename " + s.options.trace_filename + " for reading: " + e.what()); return run_result::fatal("Could not open trace filename " + s.config->m_replay.m_scap_file + " for reading: " + e.what());
} }
} }
@ -53,13 +50,6 @@ falco::app::run_result falco::app::actions::open_live_inspector(
std::shared_ptr<sinsp> inspector, std::shared_ptr<sinsp> inspector,
const std::string& source) const std::string& source)
{ {
bool is_driver_mode_from_cmdline = (s.options.nodriver ||
s.is_gvisor_enabled() ||
s.options.modern_bpf ||
getenv(FALCO_BPF_ENV_VARIABLE) != NULL
);
try try
{ {
if (source != falco_common::syscall_source) /* Plugin engine */ if (source != falco_common::syscall_source) /* Plugin engine */
@ -79,7 +69,7 @@ falco::app::run_result falco::app::actions::open_live_inspector(
} }
return run_result::fatal("Can't find plugin for event source: " + source); return run_result::fatal("Can't find plugin for event source: " + source);
} }
else if (s.options.nodriver || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::NODRIVER)) /* nodriver engine. */ else if (s.config->m_driver_mode == driver_mode_type::NONE) /* nodriver engine. */
{ {
// when opening a capture with no driver, Falco will first check // when opening a capture with no driver, Falco will first check
// if a plugin is capable of generating raw events from the libscap // if a plugin is capable of generating raw events from the libscap
@ -98,20 +88,20 @@ falco::app::run_result falco::app::actions::open_live_inspector(
falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with no driver\n"); falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with no driver\n");
inspector->open_nodriver(); inspector->open_nodriver();
} }
else if(s.is_gvisor_enabled() || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::GVISOR)) /* gvisor engine. */ else if(s.is_gvisor_enabled()) /* gvisor engine. */
{ {
falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.options.gvisor_config); falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.config->m_gvisor.m_config);
inspector->open_gvisor(s.options.gvisor_config, s.options.gvisor_root); inspector->open_gvisor(s.config->m_gvisor.m_config, s.config->m_gvisor.m_root);
} }
else if(s.options.modern_bpf || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::MODERN_BPF)) /* modern BPF engine. */ else if(s.config->m_driver_mode == driver_mode_type::MODERN_EBPF) /* modern BPF engine. */
{ {
falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with modern BPF probe."); falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with modern BPF probe.");
falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_cpus_for_each_syscall_buffer) + "' CPUs."); falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer) + "' CPUs.");
inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_cpus_for_each_syscall_buffer, true, s.selected_sc_set); inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer, true, s.selected_sc_set);
} }
else if(getenv(FALCO_BPF_ENV_VARIABLE) != NULL || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::BPF)) /* BPF engine. */ else if(s.config->m_driver_mode == driver_mode_type::EBPF) /* BPF engine. */
{ {
const char *bpf_probe_path = std::getenv(FALCO_BPF_ENV_VARIABLE); const char *bpf_probe_path = s.config->m_bpf.m_probe_path.c_str();
char full_path[PATH_MAX]; char full_path[PATH_MAX];
/* If the path is empty try to load the probe from the default path. */ /* If the path is empty try to load the probe from the default path. */
if(strncmp(bpf_probe_path, "", 1) == 0) if(strncmp(bpf_probe_path, "", 1) == 0)

View File

@ -49,7 +49,7 @@ static void init_syscall_inspector(falco::app::state& s, std::shared_ptr<sinsp>
inspector->set_snaplen(s.options.snaplen); inspector->set_snaplen(s.options.snaplen);
} }
if (s.config->m_syscall_drop_failed_exit) if (s.is_driver_drop_failed_exit_enabled())
{ {
falco_logger::log(falco_logger::level::INFO, "Failed syscall exit events are dropped in the kernel driver\n"); falco_logger::log(falco_logger::level::INFO, "Failed syscall exit events are dropped in the kernel driver\n");
inspector->set_dropfailed(true); inspector->set_dropfailed(true);

View File

@ -18,15 +18,42 @@ limitations under the License.
#include "actions.h" #include "actions.h"
#include "falco_utils.h" #include "falco_utils.h"
/* DEPRECATED: we will remove it in Falco 0.38. */
#define FALCO_BPF_ENV_VARIABLE "FALCO_BPF_PROBE"
using namespace falco::app; using namespace falco::app;
using namespace falco::app::actions; using namespace falco::app::actions;
// applies legacy/in-deprecation options to the current config // applies legacy/in-deprecation options to the current state
static void apply_deprecated_options( static falco::app::run_result apply_deprecated_options(falco::app::state& s)
const falco::app::options& opts,
const std::shared_ptr<falco_configuration>& cfg)
{ {
// Keep for future use cases. // If overridden from CLI options (soon to be removed),
// use the requested driver.
if (getenv(FALCO_BPF_ENV_VARIABLE))
{
s.config->m_driver_mode = driver_mode_type::EBPF;
s.config->m_bpf.m_probe_path = getenv(FALCO_BPF_ENV_VARIABLE);
}
else if (s.options.modern_bpf)
{
s.config->m_driver_mode = driver_mode_type::MODERN_EBPF;
}
if (!s.options.gvisor_config.empty())
{
s.config->m_driver_mode = driver_mode_type::GVISOR;
s.config->m_gvisor.m_config = s.options.gvisor_config;
s.config->m_gvisor.m_root = s.options.gvisor_root;
}
if (s.options.nodriver)
{
s.config->m_driver_mode = driver_mode_type::NONE;
}
if (!s.options.trace_filename.empty())
{
s.config->m_driver_mode = driver_mode_type::REPLAY;
s.config->m_replay.m_scap_file = s.options.trace_filename;
}
return run_result::ok();
} }
falco::app::run_result falco::app::actions::load_config(falco::app::state& s) falco::app::run_result falco::app::actions::load_config(falco::app::state& s)
@ -61,9 +88,7 @@ falco::app::run_result falco::app::actions::load_config(falco::app::state& s)
s.config->m_buffered_outputs = !s.options.unbuffered_outputs; s.config->m_buffered_outputs = !s.options.unbuffered_outputs;
apply_deprecated_options(s.options, s.config); return apply_deprecated_options(s);
return run_result::ok();
} }
falco::app::run_result falco::app::actions::require_config_file(falco::app::state& s) falco::app::run_result falco::app::actions::require_config_file(falco::app::state& s)

View File

@ -22,7 +22,6 @@ limitations under the License.
#include <cxxopts.hpp> #include <cxxopts.hpp>
#include <fstream> #include <fstream>
#include <sys/syslog.h>
namespace falco { namespace falco {
namespace app { namespace app {
@ -138,24 +137,41 @@ bool options::parse(int argc, char **argv, std::string &errstr)
// You can't both disable and enable rules // You can't both disable and enable rules
if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) && if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) &&
enabled_rule_tags.size() > 0) !enabled_rule_tags.empty())
{ {
errstr = std::string("You can not specify both disabled (-D/-T) and enabled (-t) rules"); errstr = std::string("You can not specify both disabled (-D/-T) and enabled (-t) rules");
return false; return false;
} }
list_fields = m_cmdline_parsed.count("list") > 0 ? true : false; list_fields = m_cmdline_parsed.count("list") > 0;
// TODO: remove for Falco 0.38 since these CLI options are deprecated.
int open_modes = 0; int open_modes = 0;
open_modes += !trace_filename.empty(); if (!trace_filename.empty())
open_modes += !gvisor_config.empty(); {
open_modes += modern_bpf; open_modes++;
falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-e' cmdline option is deprecated and will be removed in Falco 0.38!\n");
}
if (!gvisor_config.empty())
{
open_modes++;
falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-g,--gvisor-config' cmdline option is deprecated and will be removed in Falco 0.38!\n");
}
if(getenv("FALCO_BPF_PROBE") != NULL) if(getenv("FALCO_BPF_PROBE") != NULL)
{ {
falco_logger::log(LOG_WARNING, "DEPRECATION NOTICE: the FALCO_BPF_PROBE environment variable will be soon deprecated!\n"); open_modes++;
open_modes += 1; falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the FALCO_BPF_PROBE environment variable is deprecated and will be removed in Falco 0.38!\n");
}
if (modern_bpf)
{
open_modes++;
falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--modern-bpf' cmdline option is deprecated and will be removed in Falco 0.38!\n");
}
if (nodriver)
{
open_modes++;
falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--nodriver' cmdline option is deprecated and will be removed in Falco 0.38!\n");
} }
open_modes += nodriver;
if (open_modes > 1) if (open_modes > 1)
{ {
errstr = std::string("You can not specify more than one of -e, -g (--gvisor-config), --modern-bpf, --nodriver, and the FALCO_BPF_PROBE env var"); errstr = std::string("You can not specify more than one of -e, -g (--gvisor-config), --modern-bpf, --nodriver, and the FALCO_BPF_PROBE env var");
@ -188,15 +204,15 @@ void options::define(cxxopts::Options& opts)
("disable-source", "Turn off a specific <event_source>. By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times, but turning off all event sources simultaneously is not permitted. This option can not be mixed with --enable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(disable_sources), "<event_source>") ("disable-source", "Turn off a specific <event_source>. By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times, but turning off all event sources simultaneously is not permitted. This option can not be mixed with --enable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(disable_sources), "<event_source>")
("dry-run", "Run Falco without processing events. It can help check that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false")) ("dry-run", "Run Falco without processing events. It can help check that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false"))
("D", "Turn off any rules with names having the substring <substring>. This option can be passed multiple times. It cannot be mixed with -t.", cxxopts::value(disabled_rule_substrings), "<substring>") ("D", "Turn off any rules with names having the substring <substring>. This option can be passed multiple times. It cannot be mixed with -t.", cxxopts::value(disabled_rule_substrings), "<substring>")
("e", "Reproduce the events by reading from the given <capture_file> instead of opening a live session. Only capture files in .scap format are supported.", cxxopts::value(trace_filename), "<events_file>") ("e", "DEPRECATED. Reproduce the events by reading from the given <capture_file> instead of opening a live session. Only capture files in .scap format are supported.", cxxopts::value(trace_filename), "<events_file>")
("enable-source", "Enable a specific <event_source>. By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. When using this option, only the event sources specified by it will be enabled. This option can not be mixed with --disable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(enable_sources), "<event_source>") ("enable-source", "Enable a specific <event_source>. By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. When using this option, only the event sources specified by it will be enabled. This option can not be mixed with --disable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(enable_sources), "<event_source>")
#ifdef HAS_GVISOR #ifdef HAS_GVISOR
("g,gvisor-config", "Collect 'syscall' events from gVisor using the specified <gvisor_config> file. A Falco-compatible configuration file can be generated with --gvisor-generate-config and utilized for both runsc and Falco.", cxxopts::value(gvisor_config), "<gvisor_config>") ("g,gvisor-config", "DEPRECATED. Collect 'syscall' events from gVisor using the specified <gvisor_config> file. A Falco-compatible configuration file can be generated with --gvisor-generate-config and utilized for both runsc and Falco.", cxxopts::value(gvisor_config), "<gvisor_config>")
("gvisor-generate-config", "Generate a configuration file that can be used for gVisor and exit. See --gvisor-config for more details.", cxxopts::value<std::string>(gvisor_generate_config_with_socket)->implicit_value("/run/falco/gvisor.sock"), "<socket_path>") ("gvisor-generate-config", "Generate a configuration file that can be used for gVisor and exit. See --gvisor-config for more details.", cxxopts::value<std::string>(gvisor_generate_config_with_socket)->implicit_value("/run/falco/gvisor.sock"), "<socket_path>")
("gvisor-root", "Set gVisor root directory for storage of container state when used in conjunction with --gvisor-config. The <gvisor_root> to be passed is the one usually passed to runsc --root flag.", cxxopts::value(gvisor_root), "<gvisor_root>") ("gvisor-root", "DEPRECATED. Set gVisor root directory for storage of container state when used in conjunction with --gvisor-config. The <gvisor_root> to be passed is the one usually passed to runsc --root flag.", cxxopts::value(gvisor_root), "<gvisor_root>")
#endif #endif
#ifdef HAS_MODERN_BPF #ifdef HAS_MODERN_BPF
("modern-bpf", "Use the BPF modern probe driver to instrument the kernel and observe 'syscall' events.", cxxopts::value(modern_bpf)->default_value("false")) ("modern-bpf", "DEPRECATED. Use the BPF modern probe driver to instrument the kernel and observe 'syscall' events.", cxxopts::value(modern_bpf)->default_value("false"))
#endif #endif
("i", "Print those events that are ignored by default for performance reasons and exit. See -A for more details.", cxxopts::value(print_ignored_events)->default_value("false")) ("i", "Print those events that are ignored by default for performance reasons and exit. See -A for more details.", cxxopts::value(print_ignored_events)->default_value("false"))
("L", "Show the name and description of all rules and exit. If json_output is set to true, it prints details about all rules, macros, and lists in JSON format.", cxxopts::value(describe_all_rules)->default_value("false")) ("L", "Show the name and description of all rules and exit. If json_output is set to true, it prints details about all rules, macros, and lists in JSON format.", cxxopts::value(describe_all_rules)->default_value("false"))
@ -207,7 +223,7 @@ void options::define(cxxopts::Options& opts)
("M", "Stop Falco execution after <num_seconds> are passed.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>") ("M", "Stop Falco execution after <num_seconds> are passed.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>")
("markdown", "Print output in Markdown format when used in conjunction with --list or --list-events options. It has no effect when used with other options.", cxxopts::value<bool>(markdown)) ("markdown", "Print output in Markdown format when used in conjunction with --list or --list-events options. It has no effect when used with other options.", cxxopts::value<bool>(markdown))
("N", "Only print field names when used in conjunction with the --list option. It has no effect when used with other options.", cxxopts::value(names_only)->default_value("false")) ("N", "Only print field names when used in conjunction with the --list option. It has no effect when used with other options.", cxxopts::value(names_only)->default_value("false"))
("nodriver", "Do not use a driver to instrument the kernel. If a loaded plugin has event-sourcing capability and can produce system events, it will be used for event collection. Otherwise, no event will be collected.", cxxopts::value(nodriver)->default_value("false")) ("nodriver", "DEPRECATED. Do not use a driver to instrument the kernel. If a loaded plugin has event-sourcing capability and can produce system events, it will be used for event collection. Otherwise, no event will be collected.", cxxopts::value(nodriver)->default_value("false"))
("o,option", "Set the value of option <opt> to <val>. Overrides values in the configuration file. <opt> can be identified using its location in the configuration file using dot notation. Elements of list entries can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "<opt>=<val>") ("o,option", "Set the value of option <opt> to <val>. Overrides values in the configuration file. <opt> can be identified using its location in the configuration file using dot notation. Elements of list entries can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "<opt>=<val>")
("plugin-info", "Print info for the plugin specified by <plugin_name> and exit.\nThis includes all descriptive information like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n<plugin_name> can be the plugin's name or its configured 'library_path'.", cxxopts::value(print_plugin_info), "<plugin_name>") ("plugin-info", "Print info for the plugin specified by <plugin_name> and exit.\nThis includes all descriptive information like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n<plugin_name> can be the plugin's name or its configured 'library_path'.", cxxopts::value(print_plugin_info), "<plugin_name>")
("p,print", "Print (or replace) additional information in the rule's output.\nUse -pc or -pcontainer to append container details.\nUse -pk or -pkubernetes to add both container and Kubernetes details.\nIf using gVisor, choose -pcg or -pkg variants (or -pcontainer-gvisor and -pkubernetes-gvisor, respectively).\nIf a rule's output contains %container.info, it will be replaced with the corresponding details. Otherwise, these details will be directly appended to the rule's output.\nAlternatively, use -p <output_format> for a custom format. In this case, the given <output_format> will be appended to the rule's output without any replacement.", cxxopts::value(print_additional), "<output_format>") ("p,print", "Print (or replace) additional information in the rule's output.\nUse -pc or -pcontainer to append container details.\nUse -pk or -pkubernetes to add both container and Kubernetes details.\nIf using gVisor, choose -pcg or -pkg variants (or -pcontainer-gvisor and -pkubernetes-gvisor, respectively).\nIf a rule's output contains %container.info, it will be replaced with the corresponding details. Otherwise, these details will be directly appended to the rule's output.\nAlternatively, use -p <output_format> for a custom format. In this case, the given <output_format> will be appended to the rule's output without any replacement.", cxxopts::value(print_additional), "<output_format>")

View File

@ -147,18 +147,60 @@ struct state
inline bool is_capture_mode() const inline bool is_capture_mode() const
{ {
return !options.trace_filename.empty(); return config->m_driver_mode == driver_mode_type::REPLAY;
} }
inline bool is_gvisor_enabled() const inline bool is_gvisor_enabled() const
{ {
return !options.gvisor_config.empty(); return config->m_driver_mode == driver_mode_type::GVISOR;
} }
inline bool is_source_enabled(const std::string& src) const inline bool is_source_enabled(const std::string& src) const
{ {
return enabled_sources.find(falco_common::syscall_source) != enabled_sources.end(); return enabled_sources.find(falco_common::syscall_source) != enabled_sources.end();
} }
inline bool is_driver_drop_failed_exit_enabled() const
{
bool drop_failed;
switch (config->m_driver_mode)
{
case driver_mode_type::KMOD:
drop_failed = config->m_kmod.m_drop_failed_exit;
break;
case driver_mode_type::EBPF:
drop_failed = config->m_bpf.m_drop_failed_exit;
break;
case driver_mode_type::MODERN_EBPF:
drop_failed = config->m_modern_bpf.m_drop_failed_exit;
break;
default:
drop_failed = false;
break;
}
return drop_failed;
}
inline int16_t driver_buf_size_preset() const
{
int16_t index;
switch (config->m_driver_mode) {
case driver_mode_type::KMOD:
index = config->m_kmod.m_buf_size_preset;
break;
case driver_mode_type::EBPF:
index = config->m_bpf.m_buf_size_preset;
break;
case driver_mode_type::MODERN_EBPF:
index = config->m_modern_bpf.m_buf_size_preset;
break;
default:
// unsupported
index = - 1;
break;
}
return index;
}
}; };
}; // namespace app }; // namespace app

View File

@ -64,9 +64,6 @@ falco_configuration::falco_configuration():
m_syscall_evt_drop_max_burst(1), m_syscall_evt_drop_max_burst(1),
m_syscall_evt_simulate_drops(false), m_syscall_evt_simulate_drops(false),
m_syscall_evt_timeout_max_consecutives(1000), m_syscall_evt_timeout_max_consecutives(1000),
m_syscall_buf_size_preset(4),
m_cpus_for_each_syscall_buffer(2),
m_syscall_drop_failed_exit(false),
m_base_syscalls_repair(false), m_base_syscalls_repair(false),
m_metrics_enabled(false), m_metrics_enabled(false),
m_metrics_interval_str("5000"), m_metrics_interval_str("5000"),
@ -106,27 +103,72 @@ void falco_configuration::init(const std::string& conf_filename, const std::vect
load_yaml(conf_filename, config); load_yaml(conf_filename, config);
} }
static driver_mode_type get_driver_mode(const std::string& input){ void falco_configuration::load_driver_config(const std::string& config_name, const yaml_helper& config)
{
// Set driver mode if not already set. // Set driver mode if not already set.
const std::unordered_map<std::string, driver_mode_type> driver_mode_lut = { const std::unordered_map<std::string, driver_mode_type> driver_mode_lut = {
{"kmod",driver_mode_type::KMOD}, {"kmod",driver_mode_type::KMOD},
{"bpf",driver_mode_type::BPF}, {"ebpf",driver_mode_type::EBPF},
{"modern_bpf",driver_mode_type::MODERN_BPF}, {"modern-ebpf",driver_mode_type::MODERN_EBPF},
{"replay",driver_mode_type::REPLAY},
{"gvisor",driver_mode_type::GVISOR}, {"gvisor",driver_mode_type::GVISOR},
{"nodriver",driver_mode_type::NODRIVER}, {"none",driver_mode_type::NONE},
{"custom",driver_mode_type::CUSTOM},
}; };
if(driver_mode_lut.find(input) != driver_mode_lut.end()) { auto driver_mode_str = config.get_scalar<std::string>("driver.kind", "kmod");
return driver_mode_lut.at(input); if (driver_mode_lut.find(driver_mode_str) != driver_mode_lut.end())
} else { {
return driver_mode_type::KMOD; m_driver_mode = driver_mode_lut.at(driver_mode_str);
}
else
{
throw std::logic_error("Error reading config file (" + config_name + "): wrong driver.kind specified.");
}
switch (m_driver_mode)
{
case driver_mode_type::KMOD:
m_kmod.m_buf_size_preset = config.get_scalar<int16_t>("driver.kmod.buf_size_preset", 4);
m_kmod.m_drop_failed_exit = config.get_scalar<bool>("driver.kmod.drop_failed", false);
break;
case driver_mode_type::EBPF:
// TODO: default value for `probe` should be $HOME/FALCO_PROBE_BPF_FILEPATH,
// to be done once we drop the CLI option otherwise we would need to make the check twice,
// once here, and once when we merge the CLI options in the config file.
m_bpf.m_probe_path = config.get_scalar<std::string>("driver.ebpf.probe", "");
m_bpf.m_buf_size_preset = config.get_scalar<int16_t>("driver.ebpf.buf_size_preset", 4);
m_bpf.m_drop_failed_exit = config.get_scalar<bool>("driver.ebpf.drop_failed", false);
break;
case driver_mode_type::MODERN_EBPF:
m_modern_bpf.m_cpus_for_each_syscall_buffer = config.get_scalar<uint16_t>("driver.modern-ebpf.cpus_for_each_syscall_buffer", 2);
m_modern_bpf.m_buf_size_preset = config.get_scalar<int16_t>("driver.modern-ebpf.buf_size_preset", 4);
m_modern_bpf.m_drop_failed_exit = config.get_scalar<bool>("driver.modern-ebpf.drop_failed", false);
break;
case driver_mode_type::REPLAY:
m_replay.m_scap_file = config.get_scalar<std::string>("driver.replay.scap_file", "");
if (m_replay.m_scap_file.empty())
{
throw std::logic_error("Error reading config file (" + config_name + "): driver.kind is 'replay' but no driver.replay.scap_file specified.");
}
break;
case driver_mode_type::GVISOR:
m_gvisor.m_config = config.get_scalar<std::string>("driver.gvisor.config", "");
if (m_gvisor.m_config.empty())
{
throw std::logic_error("Error reading config file (" + config_name + "): driver.kind is 'gvisor' but no driver.gvisor.config specified.");
}
m_gvisor.m_root = config.get_scalar<std::string>("driver.gvisor.root", "");
break;
case driver_mode_type::NONE:
default:
break;
} }
} }
void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config) void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config)
{ {
m_driver_mode = get_driver_mode(config.get_scalar<std::string>("driver_mode", "")); load_driver_config(config_name, config);
m_log_level = config.get_scalar<std::string>("log_level", "info");
std::list<std::string> rules_files; std::list<std::string> rules_files;
@ -385,11 +427,14 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
/* We put this value in the configuration file because in this way we can change the dimension at every reload. /* We put this value in the configuration file because in this way we can change the dimension at every reload.
* The default value is `4` -> 8 MB. * The default value is `4` -> 8 MB.
*/ */
m_syscall_buf_size_preset = config.get_scalar<uint16_t>("syscall_buf_size_preset", 4); // TODO: remove in Falco 0.38 since they are deprecated.
m_kmod.m_buf_size_preset = config.get_scalar<uint16_t>("syscall_buf_size_preset", 4);
m_cpus_for_each_syscall_buffer = config.get_scalar<uint16_t>("modern_bpf.cpus_for_each_syscall_buffer", 2); m_bpf.m_buf_size_preset = config.get_scalar<uint16_t>("syscall_buf_size_preset", 4);
m_modern_bpf.m_buf_size_preset = config.get_scalar<uint16_t>("syscall_buf_size_preset", 4);
m_syscall_drop_failed_exit = config.get_scalar<bool>("syscall_drop_failed_exit", false); m_modern_bpf.m_cpus_for_each_syscall_buffer = config.get_scalar<uint16_t>("modern_bpf.cpus_for_each_syscall_buffer", 2);
m_kmod.m_drop_failed_exit = config.get_scalar<bool>("syscall_drop_failed_exit", false);
m_bpf.m_drop_failed_exit = config.get_scalar<bool>("syscall_drop_failed_exit", false);
m_modern_bpf.m_drop_failed_exit = config.get_scalar<bool>("syscall_drop_failed_exit", false);
m_base_syscalls_custom_set.clear(); m_base_syscalls_custom_set.clear();
config.get_sequence<std::unordered_set<std::string>>(m_base_syscalls_custom_set, std::string("base_syscalls.custom_set")); config.get_sequence<std::unordered_set<std::string>>(m_base_syscalls_custom_set, std::string("base_syscalls.custom_set"));

View File

@ -39,13 +39,12 @@ limitations under the License.
enum class driver_mode_type : uint8_t enum class driver_mode_type : uint8_t
{ {
INVALID = 0,
KMOD, KMOD,
BPF, EBPF,
MODERN_BPF, MODERN_EBPF,
REPLAY,
GVISOR, GVISOR,
NODRIVER, NONE
CUSTOM
}; };
class falco_configuration class falco_configuration
@ -60,6 +59,37 @@ public:
std::string m_open_params; std::string m_open_params;
} plugin_config; } plugin_config;
typedef struct {
public:
int16_t m_buf_size_preset;
bool m_drop_failed_exit;
} kmod_config;
typedef struct {
public:
std::string m_probe_path;
int16_t m_buf_size_preset;
bool m_drop_failed_exit;
} bpf_config;
typedef struct {
public:
uint16_t m_cpus_for_each_syscall_buffer;
int16_t m_buf_size_preset;
bool m_drop_failed_exit;
} modern_bpf_config;
typedef struct {
public:
std::string m_scap_file;
} replay_config;
typedef struct {
public:
std::string m_config;
std::string m_root;
} gvisor_config;
falco_configuration(); falco_configuration();
virtual ~falco_configuration() = default; virtual ~falco_configuration() = default;
@ -114,14 +144,6 @@ public:
uint32_t m_syscall_evt_timeout_max_consecutives; uint32_t m_syscall_evt_timeout_max_consecutives;
// Index corresponding to the syscall buffer dimension.
uint16_t m_syscall_buf_size_preset;
// Number of CPUs associated with a single ring buffer.
uint16_t m_cpus_for_each_syscall_buffer;
bool m_syscall_drop_failed_exit;
// User supplied base_syscalls, overrides any Falco state engine enforcement. // User supplied base_syscalls, overrides any Falco state engine enforcement.
std::unordered_set<std::string> m_base_syscalls_custom_set; std::unordered_set<std::string> m_base_syscalls_custom_set;
bool m_base_syscalls_repair; bool m_base_syscalls_repair;
@ -138,11 +160,18 @@ public:
bool m_metrics_convert_memory_to_mb; bool m_metrics_convert_memory_to_mb;
bool m_metrics_include_empty_values; bool m_metrics_include_empty_values;
kmod_config m_kmod;
bpf_config m_bpf;
modern_bpf_config m_modern_bpf;
replay_config m_replay;
gvisor_config m_gvisor;
std::vector<plugin_config> m_plugins; std::vector<plugin_config> m_plugins;
private: private:
void load_yaml(const std::string& config_name, const yaml_helper& config); void load_yaml(const std::string& config_name, const yaml_helper& config);
void load_driver_config(const std::string& config_name, const yaml_helper& config);
void init_cmdline_options(yaml_helper& config, const std::vector<std::string>& cmdline_options); void init_cmdline_options(yaml_helper& config, const std::vector<std::string>& cmdline_options);
/** /**