diff --git a/falco.yaml b/falco.yaml index 5ed1ee5e..cb90ac34 100644 --- a/falco.yaml +++ b/falco.yaml @@ -460,66 +460,86 @@ metadata_download: watch_freq_sec: 1 -# base_syscalls ! Use with caution ! +# base_syscalls ! Use with caution, read carefully ! # # --- [Description] # -# With this option you are in full control of the total set of syscalls that +# With this option you are in full control of the set of syscalls that # Falco will enable in the kernel for active tracing. -# All syscalls and events from each enabled Falco rule will automatically be activated -# even when choosing this option. This option provides full end user control to specifically -# define a static set of base syscalls that will be activated in addition to the +# All syscalls and events from each enabled Falco rule are activated +# even when choosing this option. This option allows you to define a +# set of base syscalls that will be activated in addition to the # syscalls defined in the rules. # -# When using this option, Falco does not add any other syscalls that may be needed for -# Falco's state engine. The union of all syscalls from the rules (including resolved macros) -# and the ones specified here compose the final set of syscalls that are traced in the kernel. -# This puts the end user in the driver seat, but if not used correctly Falco logs may be -# incomplete or wrong. This option however can be very useful to lower CPU utilization and -# allowing you to tailor Falco to specific environments according to your -# organization's threat model and security posture as well as cost budget. - -# !!! When NOT using this option, Falco defaults to adding a static set of syscalls in addition -# to the rules system calls you need for Falco's state engine build-up and life-cycle management. +# You may ask yourself why do we need to activate syscalls in addition to the rules? # +# Falco requires a set of syscalls to build up state in userspace. This is because for +# example when spawning a new process or creating a network connection more than one syscall +# is involved. Furthermore, properties of a process during its life time can be modified +# by syscalls. Falco takes care of this by activating more syscalls than the ones defined +# in the rules and by managing a smart process cache table in userspace. +# Processes are purged when a process exits. +# +# Looking back to what this option does, it activates all syscalls from the rules +# (including resolved macros) and the ones specified here. +# +# This puts the end user in the driver seat to tell Falco what it needs, but if not used correctly +# Falco logs may be incomplete or wrong or Falco won't work at all. This option however can be +# very useful to lower CPU utilization and allowing you to tailor Falco to specific environments +# according to your organization's threat model and cost budget. +# +# !!! When NOT using this option, Falco defaults to adding a static set of syscalls in addition +# to the rules system calls Falco needs for its state engine build-up and life-cycle management. +# +# If you like the recommendations below you can automate them via setting `base_syscalls.repair` +# to true. `base_syscalls.repair` is an experimental alternative to Falco's default state engine +# enforcement. `base_syscalls.repair` is designed to be the most resourceful option to ensure +# Falco runs correctly while activating a most minimal set of additional syscalls. # # --- [Usage] # # List of system calls names () plus negative ("!") notation supported. # -# base_syscalls: [, , "!"] +# base_syscalls.repair: +# base_syscalls.custom_set: [, , "!"] # # # --- [Suggestions] # -# Here are a few recommendations that may help you to use the full power of this option: +# Here are a few recommendations that may help you. +# Setting `base_syscalls.repair: true` automates the recommendations. # # Consider to at minimum add the following syscalls regardless of the syscalls used in the rules. # # [clone, clone3, fork, vfork, execve, execveat, close] # -# This is because some Falco fields you may output for an execve* system call are retrieved -# from the associated "clone", "clone3", "fork", "vfork" syscall when spawning a new process. -# The "close" system call is used to purge file descriptors from Falco's internal -# thread / process cache table and therefore should always be added when you have rules around fds +# This is because some Falco fields for an execve* system call are retrieved +# from the associated `clone`, `clone3`, `fork`, `vfork` syscall when spawning a +# new process. The `close` system call is used to purge file descriptors from Falco's +# internal thread / process cache table and should always be added when you have +# rules around file descriptors. # (e.g. open, openat, openat2, socket, connect, accept, accept4 ... and many more) # # When network syscalls are used in rules we recommend to at minimum set # # [clone, clone3, fork, vfork, execve, execveat, close, socket, bind, getsockopt] # -# It turns out that while you absolutely can log connect or accept* syscalls without the socket +# It turns out that while you can log `connect` or `accept*` syscalls without the socket # system call, the log however would not contain the ip tuples. -# For listen and accept* system calls you also need the bind system call. -# -# Lastly, if you care about the correct uid, gid or sid, pgid of a process when that process then -# opens a file or makes a network connection or any other action, consider also -# adding the following syscalls: +# For listen and accept* system calls you also need the `bind` system call. +#` +# Lastly, if you care about the correct `uid`, `gid` or `sid`, `pgid of a process when the +# running process opens a file or makes a network connection, consider adding the following syscalls: # # setresuid, setsid, setuid, setgid, setpgid, setresgid, setsid, capset, chdir, chroot, fchdir # -# Only exclude syscalls, e.g. "!mprotect" if you need a fast deployment update (overriding rules), -# else rather remove unwanted or not needed syscalls from the Falco rules. +# We recommend to exclude syscalls, e.g. "!mprotect" only if you need a fast deployment update +# (overriding rules), else remove unwanted syscalls from the Falco rules. +# +# Passing `-o "log_level=debug"` to Falco's cmd args during a dry-run will print the +# final set of syscalls to STDOUT. -base_syscalls: [] +base_syscalls: + repair: false + custom_set: [] diff --git a/userspace/falco/app/actions/configure_interesting_sets.cpp b/userspace/falco/app/actions/configure_interesting_sets.cpp index 178da0c2..28d5a742 100644 --- a/userspace/falco/app/actions/configure_interesting_sets.cpp +++ b/userspace/falco/app/actions/configure_interesting_sets.cpp @@ -85,13 +85,15 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set

user_positive_names = {}; std::unordered_set user_negative_names = {}; - extract_base_syscalls_names(s.config->m_base_syscalls, user_positive_names, user_negative_names); + extract_base_syscalls_names(s.config->m_base_syscalls_custom_set, user_positive_names, user_negative_names); auto user_positive_sc_set = libsinsp::events::names_to_sc_set(user_positive_names); auto user_negative_sc_set = libsinsp::events::names_to_sc_set(user_negative_names); - if (!user_positive_sc_set.empty()) + if (!user_positive_sc_set.empty() || s.config->m_base_syscalls_repair) { // user overrides base event set + // in case `user_positive_sc_set` is empty, but `base_syscalls.repair` is set + // this has the effect of clearing the default `sinsp_state_sc_set()` base_sc_set = user_positive_sc_set; // we re-transform from sc_set to names to make @@ -111,6 +113,17 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set

m_base_syscalls_repair) + { + /* If base_syscalls.repair set enforce `libsinsp` state based on rules set + * and merge with user supplied base_syscalls.custom_set + * + * Also applies when base_syscalls.custom_set empty but base_syscalls.repair set + * effectively bypassing the default `libsinsp` state enforcement and using + * `sinsp_repair_state_sc_set` instead. */ + s.selected_sc_set = libsinsp::events::sinsp_repair_state_sc_set(rules_sc_set).merge(base_sc_set); + } + if (!user_negative_sc_set.empty()) { /* Remove negative base_syscalls events. */ diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 9e7d7ae8..4813e621 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -332,8 +332,9 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h m_syscall_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); - m_base_syscalls.clear(); - config.get_sequence>(m_base_syscalls, std::string("base_syscalls")); + m_base_syscalls_custom_set.clear(); + config.get_sequence>(m_base_syscalls_custom_set, std::string("base_syscalls.custom_set")); + m_base_syscalls_repair = config.get_scalar("base_syscalls.repair", false); std::set load_plugins; diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 3b9c8310..b1a8f577 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -109,7 +109,8 @@ public: bool m_syscall_drop_failed_exit; // User supplied base_syscalls, overrides any Falco state engine enforcement. - std::unordered_set m_base_syscalls; + std::unordered_set m_base_syscalls_custom_set; + bool m_base_syscalls_repair; std::vector m_plugins;