mirror of
https://github.com/falcosecurity/falco.git
synced 2025-07-17 00:01:52 +00:00
refactor(userspace/falco): adapt event set selection to only use ppm_sc and new engine features
Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com> Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
parent
19ffadc763
commit
fb37d8f365
@ -19,7 +19,10 @@ limitations under the License.
|
|||||||
using namespace falco::app;
|
using namespace falco::app;
|
||||||
using namespace falco::app::actions;
|
using namespace falco::app::actions;
|
||||||
|
|
||||||
void extract_base_syscalls_names(const std::unordered_set<std::string>& base_syscalls_names, std::unordered_set<std::string>& positive_names, std::unordered_set<std::string>& negative_names)
|
static void extract_base_syscalls_names(
|
||||||
|
const std::unordered_set<std::string>& base_syscalls_names,
|
||||||
|
std::unordered_set<std::string>& user_positive_names,
|
||||||
|
std::unordered_set<std::string>& user_negative_names)
|
||||||
{
|
{
|
||||||
for (const std::string &ev : base_syscalls_names)
|
for (const std::string &ev : base_syscalls_names)
|
||||||
{
|
{
|
||||||
@ -27,58 +30,41 @@ void extract_base_syscalls_names(const std::unordered_set<std::string>& base_sys
|
|||||||
{
|
{
|
||||||
if (ev.at(0) == '!')
|
if (ev.at(0) == '!')
|
||||||
{
|
{
|
||||||
negative_names.insert(ev.substr(1, ev.size()));
|
user_negative_names.insert(ev.substr(1, ev.size()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
positive_names.insert(ev);
|
user_positive_names.insert(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static libsinsp::events::set<ppm_event_code> extract_rules_event_set(falco::app::state& s)
|
static void check_for_rules_unsupported_events(falco::app::state& s, const libsinsp::events::set<ppm_sc_code>& rules_sc_set)
|
||||||
{
|
|
||||||
/* Get all (positive) PPME events from all rules as idx codes.
|
|
||||||
* Events names from negative filter expression statements are NOT included.
|
|
||||||
* PPME events in libsinsp are needed to map each event type into it's enter
|
|
||||||
* and exit event if applicable (e.g. for syscall events). */
|
|
||||||
std::set<uint16_t> tmp;
|
|
||||||
libsinsp::events::set<ppm_event_code> events;
|
|
||||||
auto source = falco_common::syscall_source;
|
|
||||||
s.engine->evttypes_for_ruleset(source, tmp);
|
|
||||||
for (const auto &ev : tmp)
|
|
||||||
{
|
|
||||||
events.insert((ppm_event_code) ev);
|
|
||||||
}
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void check_for_rules_unsupported_events(falco::app::state& s, const libsinsp::events::set<ppm_event_code>& rules_event_set)
|
|
||||||
{
|
{
|
||||||
/* Unsupported events are those events that are used in the rules
|
/* Unsupported events are those events that are used in the rules
|
||||||
* but that are not part of the selected event set. For now, this
|
* 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 I/O syscalls for
|
||||||
* performance reasons. */
|
* performance reasons. */
|
||||||
auto unsupported_event_set = rules_event_set.diff(s.selected_event_set);
|
auto unsupported_sc_set = rules_sc_set.diff(s.selected_sc_set);
|
||||||
if (unsupported_event_set.empty())
|
if (unsupported_sc_set.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the names of the events (syscall and non syscall events) that were not activated and print them. */
|
/* Get the names of the events (syscall and non syscall events) that were not activated and print them. */
|
||||||
auto names = libsinsp::events::event_set_to_names(unsupported_event_set);
|
auto names = libsinsp::events::sc_set_to_names(unsupported_sc_set);
|
||||||
std::cerr << "Loaded rules match event types that are not activated or unsupported with current configuration: warning (unsupported-evttype): " + concat_set_in_order(names) << std::endl;
|
std::cerr << "Loaded rules match event types that are not activated 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 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 I/O syscalls (-> activate via `-A` flag), else syscalls 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, libsinsp::events::set<ppm_event_code>& rules_event_set)
|
static void select_event_set(falco::app::state& s, const libsinsp::events::set<ppm_sc_code>& rules_sc_set)
|
||||||
{
|
{
|
||||||
/* PPM syscall codes (sc) can be viewed as condensed libsinsp lookup table
|
/* PPM syscall codes (sc) can be viewed as condensed libsinsp lookup table
|
||||||
* to map a system call name to it's actual system syscall id (as defined
|
* 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. */
|
* by the Linux kernel). Hence here we don't need syscall enter and exit distinction. */
|
||||||
auto rules_names = libsinsp::events::event_set_to_names(rules_event_set);
|
auto rules_names = libsinsp::events::sc_set_to_names(rules_sc_set);
|
||||||
if (!rules_event_set.empty())
|
if (!rules_sc_set.empty())
|
||||||
{
|
{
|
||||||
falco_logger::log(LOG_DEBUG, "(" + std::to_string(rules_names.size())
|
falco_logger::log(LOG_DEBUG, "(" + std::to_string(rules_names.size())
|
||||||
+ ") events in rules: " + concat_set_in_order(rules_names) + "\n");
|
+ ") events in rules: " + concat_set_in_order(rules_names) + "\n");
|
||||||
@ -94,68 +80,55 @@ static void select_event_set(falco::app::state& s, libsinsp::events::set<ppm_eve
|
|||||||
* Fall-back if no valid positive syscalls in "base_syscalls",
|
* Fall-back if no valid positive syscalls in "base_syscalls",
|
||||||
* e.g. when using "base_syscalls" only for negative syscalls.
|
* e.g. when using "base_syscalls" only for negative syscalls.
|
||||||
*/
|
*/
|
||||||
auto base_event_set = libsinsp::events::sinsp_state_event_set();
|
auto base_sc_set = libsinsp::events::sinsp_state_sc_set();
|
||||||
s.selected_event_set = rules_event_set.merge(base_event_set);
|
|
||||||
|
|
||||||
auto user_base_syscalls_names = s.config->m_base_syscalls;
|
/* USER OVERRIDE INPUT OPTION "base_syscalls". */
|
||||||
libsinsp::events::set<ppm_sc_code> valid_positive_syscalls;
|
std::unordered_set<std::string> user_positive_names = {};
|
||||||
if (!user_base_syscalls_names.empty())
|
std::unordered_set<std::string> user_negative_names = {};
|
||||||
|
extract_base_syscalls_names(s.config->m_base_syscalls, 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())
|
||||||
{
|
{
|
||||||
/* USER OVERRIDE INPUT OPTION "base_syscalls". */
|
// user overrides base event set
|
||||||
std::unordered_set<std::string> positive_names = {};
|
base_sc_set = user_positive_sc_set;
|
||||||
std::unordered_set<std::string> negative_names = {};
|
|
||||||
extract_base_syscalls_names(user_base_syscalls_names, positive_names, negative_names);
|
|
||||||
|
|
||||||
valid_positive_syscalls = libsinsp::events::names_to_sc_set(positive_names);
|
// we re-transform from events set to names to make
|
||||||
auto valid_negative_syscalls = libsinsp::events::names_to_sc_set(negative_names);
|
// sure that bad user inputs are ignored
|
||||||
|
auto user_positive_sc_set_names = libsinsp::events::sc_set_to_names(user_positive_sc_set);
|
||||||
|
falco_logger::log(LOG_DEBUG, "+(" + std::to_string(user_positive_sc_set_names.size())
|
||||||
|
+ ") syscalls added (base_syscalls override): "
|
||||||
|
+ concat_set_in_order(user_positive_sc_set_names) + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (!valid_positive_syscalls.empty())
|
// selected events are the union of the rules events set and the
|
||||||
{
|
// base events set (either the default or the user-defined one)
|
||||||
/* Convert valid syscalls codes to event codes. */
|
s.selected_sc_set = rules_sc_set.merge(base_sc_set);
|
||||||
auto valid_positive_events = libsinsp::events::sc_set_to_event_set(valid_positive_syscalls);
|
|
||||||
|
|
||||||
/* For now remove the sinsp_state_sc_set again. A possible future libs refactor can remove this need.
|
if (!user_negative_sc_set.empty())
|
||||||
* That way we consistently use sinsp_state_event_set() which adds critical non syscalls events.
|
{
|
||||||
* This step prepares the sinsp state enforcement override w/ "base_syscalls" user input.
|
/* Remove negative base_syscalls events. */
|
||||||
*/
|
s.selected_sc_set = s.selected_sc_set.diff(user_negative_sc_set);
|
||||||
auto sc_state_event_set = libsinsp::events::sc_set_to_event_set(libsinsp::events::sinsp_state_sc_set());
|
|
||||||
s.selected_event_set = s.selected_event_set.diff(sc_state_event_set);
|
|
||||||
s.selected_event_set = rules_event_set.merge(s.selected_event_set);
|
|
||||||
|
|
||||||
/* Add valid base_syscalls events. */
|
// we re-transform from events set to names to make
|
||||||
s.selected_event_set = s.selected_event_set.merge(valid_positive_events);
|
// sure that bad user inputs are ignored
|
||||||
|
auto user_negative_sc_set_names = libsinsp::events::sc_set_to_names(user_negative_sc_set);
|
||||||
auto valid_positive_syscalls_names = libsinsp::events::sc_set_to_names(valid_positive_syscalls);
|
falco_logger::log(LOG_DEBUG, "-(" + std::to_string(user_negative_sc_set_names.size())
|
||||||
falco_logger::log(LOG_DEBUG, "+(" + std::to_string(valid_positive_syscalls_names.size())
|
+ ") syscalls removed (base_syscalls override): "
|
||||||
+ ") syscalls added (base_syscalls override): "
|
+ concat_set_in_order(user_negative_sc_set_names) + "\n");
|
||||||
+ concat_set_in_order(valid_positive_syscalls_names) + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!valid_negative_syscalls.empty())
|
|
||||||
{
|
|
||||||
/* Convert valid syscalls codes to event codes. */
|
|
||||||
auto valid_negative_events = libsinsp::events::sc_set_to_event_set(valid_negative_syscalls);
|
|
||||||
|
|
||||||
/* Remove negative base_syscalls events. */
|
|
||||||
s.selected_event_set = s.selected_event_set.diff(valid_negative_events);
|
|
||||||
rules_event_set = rules_event_set.diff(valid_negative_events);
|
|
||||||
|
|
||||||
auto valid_negative_syscalls_names = libsinsp::events::sc_set_to_names(valid_negative_syscalls);
|
|
||||||
falco_logger::log(LOG_DEBUG, "-(" + std::to_string(valid_negative_syscalls_names.size())
|
|
||||||
+ ") syscalls removed (base_syscalls override): "
|
|
||||||
+ concat_set_in_order(valid_negative_syscalls_names) + "\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Derive the diff between the additional syscalls added via libsinsp state
|
/* Derive the diff between the additional syscalls added via libsinsp state
|
||||||
enforcement and the syscalls from each Falco rule. */
|
enforcement and the syscalls from each Falco rule. We avoid printing
|
||||||
auto non_rules_event_set = s.selected_event_set.diff(rules_event_set);
|
this in case the user specified a custom set of base syscalls */
|
||||||
if (!non_rules_event_set.empty() && valid_positive_syscalls.empty())
|
auto non_rules_sc_set = s.selected_sc_set.diff(rules_sc_set);
|
||||||
|
if (!non_rules_sc_set.empty() && user_positive_sc_set.empty())
|
||||||
{
|
{
|
||||||
auto non_rules_event_set_names = libsinsp::events::event_set_to_names(non_rules_event_set);
|
auto non_rules_sc_set_names = libsinsp::events::sc_set_to_names(non_rules_sc_set);
|
||||||
falco_logger::log(LOG_DEBUG, "+(" + std::to_string(non_rules_event_set_names.size())
|
falco_logger::log(LOG_DEBUG, "+(" + std::to_string(non_rules_sc_set_names.size())
|
||||||
+ ") events (Falco's state engine set of events): "
|
+ ") events (Falco's state engine set of events): "
|
||||||
+ concat_set_in_order(non_rules_event_set_names) + "\n");
|
+ concat_set_in_order(non_rules_sc_set_names) + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -A flag behavior:
|
/* -A flag behavior:
|
||||||
@ -165,35 +138,23 @@ static void select_event_set(falco::app::state& s, libsinsp::events::set<ppm_eve
|
|||||||
and allowing high volume I/O syscalls */
|
and allowing high volume I/O syscalls */
|
||||||
if(!s.options.all_events)
|
if(!s.options.all_events)
|
||||||
{
|
{
|
||||||
auto ignored_event_set = libsinsp::events::sc_set_to_event_set(libsinsp::events::io_sc_set());
|
auto ignored_sc_set = libsinsp::events::io_sc_set();
|
||||||
auto erased_event_set = s.selected_event_set.intersect(ignored_event_set);
|
auto erased_sc_set = s.selected_sc_set.intersect(ignored_sc_set);
|
||||||
s.selected_event_set = s.selected_event_set.diff(ignored_event_set);
|
s.selected_sc_set = s.selected_sc_set.diff(ignored_sc_set);
|
||||||
if (!erased_event_set.empty())
|
if (!erased_sc_set.empty())
|
||||||
{
|
{
|
||||||
auto erased_event_set_names = libsinsp::events::event_set_to_names(erased_event_set);
|
auto erased_sc_set_names = libsinsp::events::sc_set_to_names(erased_sc_set);
|
||||||
falco_logger::log(LOG_DEBUG, "-(" + std::to_string(erased_event_set_names.size())
|
falco_logger::log(LOG_DEBUG, "-(" + std::to_string(erased_sc_set_names.size())
|
||||||
+ ") ignored events (-> activate via `-A` flag): "
|
+ ") ignored events (-> activate via `-A` flag): "
|
||||||
+ concat_set_in_order(erased_event_set_names) + "\n");
|
+ concat_set_in_order(erased_sc_set_names) + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s.selected_event_set.empty())
|
|
||||||
{
|
|
||||||
auto selected_event_set_names = libsinsp::events::event_set_to_names(s.selected_event_set);
|
|
||||||
falco_logger::log(LOG_DEBUG, "(" + std::to_string(selected_event_set_names.size())
|
|
||||||
+ ") events selected in total (final set): "
|
|
||||||
+ concat_set_in_order(selected_event_set_names) + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void select_syscall_set(falco::app::state& s, const libsinsp::events::set<ppm_event_code>& rules_event_set)
|
|
||||||
{
|
|
||||||
s.selected_sc_set = libsinsp::events::event_set_to_sc_set(s.selected_event_set);
|
|
||||||
if (!s.selected_sc_set.empty())
|
if (!s.selected_sc_set.empty())
|
||||||
{
|
{
|
||||||
auto selected_sc_set_names = libsinsp::events::sc_set_to_names(s.selected_sc_set);
|
auto selected_sc_set_names = libsinsp::events::sc_set_to_names(s.selected_sc_set);
|
||||||
falco_logger::log(LOG_DEBUG, "(" + std::to_string(selected_sc_set_names.size())
|
falco_logger::log(LOG_DEBUG, "(" + std::to_string(selected_sc_set_names.size())
|
||||||
+ ") syscalls selected in total (final set): "
|
+ ") events selected in total (final set): "
|
||||||
+ concat_set_in_order(selected_sc_set_names) + "\n");
|
+ concat_set_in_order(selected_sc_set_names) + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,7 +171,11 @@ static void select_kernel_tracepoint_set(falco::app::state& s)
|
|||||||
|
|
||||||
falco::app::run_result falco::app::actions::configure_interesting_sets(falco::app::state& s)
|
falco::app::run_result falco::app::actions::configure_interesting_sets(falco::app::state& s)
|
||||||
{
|
{
|
||||||
s.selected_event_set.clear();
|
if (s.engine == nullptr || s.config == nullptr)
|
||||||
|
{
|
||||||
|
return run_result::fatal("Broken 'configure_interesting_sets' preconditions: engine and config must be non-null");
|
||||||
|
}
|
||||||
|
|
||||||
s.selected_sc_set.clear();
|
s.selected_sc_set.clear();
|
||||||
s.selected_tp_set.clear();
|
s.selected_tp_set.clear();
|
||||||
|
|
||||||
@ -222,10 +187,9 @@ falco::app::run_result falco::app::actions::configure_interesting_sets(falco::ap
|
|||||||
* of syscall codes. Those last two sets will be passed down to the
|
* of syscall codes. Those last two sets will be passed down to the
|
||||||
* inspector to instruct the kernel drivers on which kernel event should
|
* inspector to instruct the kernel drivers on which kernel event should
|
||||||
* be collected at runtime. */
|
* be collected at runtime. */
|
||||||
auto rules_event_set = extract_rules_event_set(s);
|
auto rules_sc_set = s.engine->sc_codes_for_ruleset(falco_common::syscall_source);
|
||||||
select_event_set(s, rules_event_set);
|
select_event_set(s, rules_sc_set);
|
||||||
check_for_rules_unsupported_events(s, rules_event_set);
|
check_for_rules_unsupported_events(s, rules_sc_set);
|
||||||
select_syscall_set(s, rules_event_set);
|
|
||||||
select_kernel_tracepoint_set(s);
|
select_kernel_tracepoint_set(s);
|
||||||
return run_result::ok();
|
return run_result::ok();
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,6 @@ struct state
|
|||||||
enabled_sources(),
|
enabled_sources(),
|
||||||
source_infos(),
|
source_infos(),
|
||||||
plugin_configs(),
|
plugin_configs(),
|
||||||
selected_event_set(),
|
|
||||||
selected_sc_set(),
|
selected_sc_set(),
|
||||||
selected_tp_set(),
|
selected_tp_set(),
|
||||||
syscall_buffer_bytes_size(DEFAULT_DRIVER_BUFFER_BYTES_DIM)
|
syscall_buffer_bytes_size(DEFAULT_DRIVER_BUFFER_BYTES_DIM)
|
||||||
@ -106,9 +105,6 @@ struct state
|
|||||||
// by their sinsp_plugin::name method
|
// by their sinsp_plugin::name method
|
||||||
indexed_vector<falco_configuration::plugin_config> plugin_configs;
|
indexed_vector<falco_configuration::plugin_config> plugin_configs;
|
||||||
|
|
||||||
// Set of events we want the driver to capture
|
|
||||||
libsinsp::events::set<ppm_event_code> selected_event_set;
|
|
||||||
|
|
||||||
// Set of syscalls we want the driver to capture
|
// Set of syscalls we want the driver to capture
|
||||||
libsinsp::events::set<ppm_sc_code> selected_sc_set;
|
libsinsp::events::set<ppm_sc_code> selected_sc_set;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user