From f87e6f18712e574ba7e21eb9ee089b521a05aa03 Mon Sep 17 00:00:00 2001 From: Lorenzo Fontana Date: Mon, 9 Nov 2020 17:15:40 +0100 Subject: [PATCH] chore: restore the classic flags for a future refactor for the new functionalities Co-Authored-By: Leonardo Di Donato Signed-off-by: Lorenzo Fontana --- CMakeLists.txt | 2 +- userspace/engine/CMakeLists.txt | 11 +- userspace/engine/falco_engine.cpp | 145 ++++------ userspace/engine/falco_engine.h | 34 +-- userspace/falco/CMakeLists.txt | 14 + userspace/falco/configuration.cpp | 75 ++++- userspace/falco/configuration.h | 3 + userspace/falco/falco.cpp | 465 +++++++++++++++++------------- 8 files changed, 440 insertions(+), 309 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 10eb4242..8efa759f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,7 @@ if(MUSL_OPTIMIZED_BUILD) set(MUSL_FLAGS "-static -Os") endif() -set(CMAKE_COMMON_FLAGS "-Wall -pg -ggdb ${DRAIOS_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}") +set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${DRAIOS_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}") if(BUILD_WARNINGS_AS_ERRORS) set(CMAKE_SUPPRESSED_WARNINGS diff --git a/userspace/engine/CMakeLists.txt b/userspace/engine/CMakeLists.txt index 3d723ab5..ba4a431d 100644 --- a/userspace/engine/CMakeLists.txt +++ b/userspace/engine/CMakeLists.txt @@ -38,8 +38,7 @@ if(MINIMAL_BUILD) "${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp" "${SYSDIG_SOURCE_DIR}/userspace/libscap" "${SYSDIG_SOURCE_DIR}/userspace/libsinsp" - "${PROJECT_BINARY_DIR}/userspace/engine" - "${PROJECT_SOURCE_DIR}/userspace/libhawk") + "${PROJECT_BINARY_DIR}/userspace/engine") else() target_include_directories( falco_engine @@ -52,17 +51,11 @@ else() "${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp" "${SYSDIG_SOURCE_DIR}/userspace/libscap" "${SYSDIG_SOURCE_DIR}/userspace/libsinsp" - "${PROJECT_BINARY_DIR}/userspace/engine" - "${PROJECT_SOURCE_DIR}/userspace/libhawk") + "${PROJECT_BINARY_DIR}/userspace/engine") endif() target_link_libraries(falco_engine "${FALCO_SINSP_LIBRARY}" "${LPEG_LIB}" "${LYAML_LIB}" "${LIBYAML_LIB}") -if(DEFINED LIBHAWK_LIBRARIES) - message(STATUS "Using externally provided libhawk implementations: ${LIBHAWK_LIBRARIES}") - target_link_libraries(falco_engine ${LIBHAWK_LIBRARIES}) -endif() - configure_file(config_falco_engine.h.in config_falco_engine.h) if(DEFINED FALCO_COMPONENT) diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index e7d0cc77..5d44dbc4 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -26,8 +26,7 @@ limitations under the License. #include "formats.h" -extern "C" -{ +extern "C" { #include "lpeg.h" #include "lyaml.h" } @@ -35,6 +34,7 @@ extern "C" #include "utils.h" #include "banned.h" // This raises a compilation error when certain functions are used + string lua_on_event = "on_event"; string lua_print_stats = "print_stats"; @@ -42,24 +42,25 @@ using namespace std; nlohmann::json::json_pointer falco_engine::k8s_audit_time = "/stageTimestamp"_json_pointer; -falco_engine::falco_engine(bool seed_rng, const std::string &alternate_lua_dir): - m_rules(NULL), m_next_ruleset_id(0), - m_min_priority(falco_common::PRIORITY_DEBUG), - m_sampling_ratio(1), m_sampling_multiplier(0), - m_replace_container_info(false) +falco_engine::falco_engine(bool seed_rng, const std::string& alternate_lua_dir) + : m_rules(NULL), m_next_ruleset_id(0), + m_min_priority(falco_common::PRIORITY_DEBUG), + m_sampling_ratio(1), m_sampling_multiplier(0), + m_replace_container_info(false) { luaopen_lpeg(m_ls); luaopen_yaml(m_ls); - m_alternate_lua_dir = alternate_lua_dir; + falco_common::init(m_lua_main_filename.c_str(), alternate_lua_dir.c_str()); falco_rules::init(m_ls); - clear_filters(); + m_sinsp_rules.reset(new falco_sinsp_ruleset()); + m_k8s_audit_rules.reset(new falco_ruleset()); if(seed_rng) { - srandom((unsigned)getpid()); + srandom((unsigned) getpid()); } m_default_ruleset_id = find_ruleset_id(m_default_ruleset); @@ -70,7 +71,7 @@ falco_engine::falco_engine(bool seed_rng, const std::string &alternate_lua_dir): falco_engine::~falco_engine() { - if(m_rules) + if (m_rules) { delete m_rules; } @@ -87,7 +88,7 @@ falco_engine *falco_engine::clone() uint32_t falco_engine::engine_version() { - return (uint32_t)FALCO_ENGINE_VERSION; + return (uint32_t) FALCO_ENGINE_VERSION; } #define DESCRIPTION_TEXT_START 16 @@ -153,28 +154,17 @@ void falco_engine::list_fields(bool names_only) } } -void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events) -{ - ifstream is; - - is.open(rules_filename); - if(!is.is_open()) - { - throw falco_exception("Could not open rules filename " + - rules_filename + " " + - "for reading"); - } - - string rules_content((istreambuf_iterator(is)), - istreambuf_iterator()); - - load_rules(rules_content, verbose, all_events); -} - void falco_engine::load_rules(const string &rules_content, bool verbose, bool all_events) +{ + uint64_t dummy; + + return load_rules(rules_content, verbose, all_events, dummy); +} + +void falco_engine::load_rules(const string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version) { // The engine must have been given an inspector by now. - if(!m_inspector) + if(! m_inspector) { throw falco_exception("No inspector provided"); } @@ -186,52 +176,45 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al if(!m_rules) { - // Note that falco_formats is added to the lua state used by the falco engine only. - // Within the engine, only formats. - // Formatter is used, so we can unconditionally set json_output to false. - bool json_output = false; - bool json_include_output_property = false; - falco_formats::init(m_inspector, this, m_ls, json_output, json_include_output_property); - m_rules = new falco_rules(m_inspector, this, m_ls); + m_rules = new falco_rules(m_inspector, + this, + m_ls); } - uint64_t dummy; - // m_sinsp_rules.reset(new falco_sinsp_ruleset()); - // m_k8s_audit_rules.reset(new falco_ruleset()); - m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, dummy); + // Note that falco_formats is added to the lua state used + // by the falco engine only. Within the engine, only + // formats.formatter is used, so we can unconditionally set + // json_output to false. + bool json_output = false; + bool json_include_output_property = false; + falco_formats::init(m_inspector, this, m_ls, json_output, json_include_output_property); - m_is_ready = true; - - return; - - // - // auto local_rules = new falco_rules(m_inspector, this, m_ls); - // try - // { - // uint64_t dummy; - // local_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, dummy); - - // // m_rules = local_rules - // // std::atomic lore(m_rules); - // // std::atomic_exchange(&lore, local_rules); - // // SCHEDULE LOCAL_RULES AS NEXT RULESET - // } - // catch(const falco_exception &e) - // { - // // todo - // printf("IGNORE BECAUSE OF ERROR LOADING RULESET!\n"); - // } + m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, required_engine_version); } -// // todo(fntlnz): not sure we want this in falco_engine -// void falco_engine::watch_rules(bool verbose, bool all_events) -// { -// hawk_watch_rules((hawk_watch_rules_cb)rules_cb, reinterpret_cast(this)); -// } - -bool falco_engine::is_ready() +void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events) { - return m_is_ready; + uint64_t dummy; + + return load_rules_file(rules_filename, verbose, all_events, dummy); +} + +void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events, uint64_t &required_engine_version) +{ + ifstream is; + + is.open(rules_filename); + if (!is.is_open()) + { + throw falco_exception("Could not open rules filename " + + rules_filename + " " + + "for reading"); + } + + string rules_content((istreambuf_iterator(is)), + istreambuf_iterator()); + + load_rules(rules_content, verbose, all_events, required_engine_version); } void falco_engine::enable_rule(const string &substring, bool enabled, const string &ruleset) @@ -299,7 +282,7 @@ uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset) uint16_t ruleset_id = find_ruleset_id(ruleset); return m_sinsp_rules->num_rules_for_ruleset(ruleset_id) + - m_k8s_audit_rules->num_rules_for_ruleset(ruleset_id); + m_k8s_audit_rules->num_rules_for_ruleset(ruleset_id); } void falco_engine::evttypes_for_ruleset(std::vector &evttypes, const std::string &ruleset) @@ -338,7 +321,6 @@ unique_ptr falco_engine::process_sinsp_event(sinsp_ev unique_ptr falco_engine::process_sinsp_event(sinsp_evt *ev) { - // todo(leodido, fntlnz) > pass the last ruleset id return process_sinsp_event(ev, m_default_ruleset_id); } @@ -350,7 +332,7 @@ unique_ptr falco_engine::process_k8s_audit_event(json } // All k8s audit events have the single tag "1". - if(!m_k8s_audit_rules->run((gen_event *)ev, 1, ruleset_id)) + if(!m_k8s_audit_rules->run((gen_event *) ev, 1, ruleset_id)) { return unique_ptr(); } @@ -373,7 +355,7 @@ void falco_engine::populate_rule_result(unique_ptr &res, gen if(lua_pcall(m_ls, 1, 4, 0) != 0) { - const char *lerr = lua_tostring(m_ls, -1); + const char* lerr = lua_tostring(m_ls, -1); string err = "Error invoking function output: " + string(lerr); throw falco_exception(err); } @@ -416,7 +398,7 @@ bool falco_engine::parse_k8s_audit_json(nlohmann::json &j, std::list { // Note we only handle a single top level array, to // avoid excessive recursion. - if(!parse_k8s_audit_json(item, evts, false)) + if(! parse_k8s_audit_json(item, evts, false)) { return false; } @@ -494,7 +476,7 @@ void falco_engine::print_stats() { if(lua_pcall(m_ls, 0, 0, 0) != 0) { - const char *lerr = lua_tostring(m_ls, -1); + const char* lerr = lua_tostring(m_ls, -1); string err = "Error invoking function print_stats: " + string(lerr); throw falco_exception(err); } @@ -503,20 +485,21 @@ void falco_engine::print_stats() { throw falco_exception("No function " + lua_print_stats + " found in lua rule loader module"); } + } void falco_engine::add_sinsp_filter(string &rule, set &evttypes, set &syscalls, set &tags, - sinsp_filter *filter) + sinsp_filter* filter) { m_sinsp_rules->add(rule, evttypes, syscalls, tags, filter); } void falco_engine::add_k8s_audit_filter(string &rule, set &tags, - json_event_filter *filter) + json_event_filter* filter) { // All k8s audit events have a single tag "1". std::set event_tags = {1}; @@ -558,8 +541,8 @@ inline bool falco_engine::should_drop_evt() return false; } - double coin = (random() * (1.0 / RAND_MAX)); - return (coin >= (1.0 / (m_sampling_multiplier * m_sampling_ratio))); + double coin = (random() * (1.0/RAND_MAX)); + return (coin >= (1.0/(m_sampling_multiplier * m_sampling_ratio))); } sinsp_filter_factory &falco_engine::sinsp_factory() diff --git a/userspace/engine/falco_engine.h b/userspace/engine/falco_engine.h index 1dde641d..e6b38f63 100644 --- a/userspace/engine/falco_engine.h +++ b/userspace/engine/falco_engine.h @@ -38,11 +38,6 @@ limitations under the License. #include "config_falco_engine.h" #include "falco_common.h" -extern "C" -{ -#include "hawk.h" -} - // // This class acts as the primary interface between a program and the // falco rules engine. Falco outputs (writing to files/syslog/etc) are @@ -52,10 +47,9 @@ extern "C" class falco_engine : public falco_common { public: - falco_engine(bool seed_rng = true, const std::string &alternate_lua_dir = FALCO_ENGINE_SOURCE_LUA_DIR); + falco_engine(bool seed_rng=true, const std::string& alternate_lua_dir=FALCO_ENGINE_SOURCE_LUA_DIR); virtual ~falco_engine(); - falco_engine(const falco_engine &rhs); falco_engine *clone(); // A given engine has a version which identifies the fields @@ -65,7 +59,7 @@ public: static uint32_t engine_version(); // Print to stdout (using printf) a description of each field supported by this engine. - void list_fields(bool names_only = false); + void list_fields(bool names_only=false); // // Load rules either directly or from a filename. @@ -73,8 +67,12 @@ public: void load_rules_file(const std::string &rules_filename, bool verbose, bool all_events); void load_rules(const std::string &rules_content, bool verbose, bool all_events); - // Watch and live-reload rules using an external ABI interface provided by libhawk - void watch_rules(bool verbose, bool all_events); + // + // Identical to above, but also returns the required engine version for the file/content. + // (If no required engine version is specified, returns 0). + // + void load_rules_file(const std::string &rules_filename, bool verbose, bool all_events, uint64_t &required_engine_version); + void load_rules(const std::string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version); // // Enable/Disable any rules matching the provided substring. @@ -89,6 +87,7 @@ public: // Wrapper that assumes the default ruleset void enable_rule(const std::string &substring, bool enabled); + // Like enable_rule, but the rule name must be an exact match. void enable_rule_exact(const std::string &rule_name, bool enabled, const std::string &ruleset); @@ -157,8 +156,7 @@ public: // **Methods Related to k8s audit log events, which are // **represented as json objects. - struct rule_result - { + struct rule_result { gen_event *evt; std::string rule; std::string source; @@ -175,7 +173,7 @@ public: // Returns true if the json object was recognized as a k8s // audit event(s), false otherwise. // - bool parse_k8s_audit_json(nlohmann::json &j, std::list &evts, bool top = true); + bool parse_k8s_audit_json(nlohmann::json &j, std::list &evts, bool top=true); // // Given an event, check it against the set of rules in the @@ -200,7 +198,7 @@ public: // void add_k8s_audit_filter(std::string &rule, std::set &tags, - json_event_filter *filter); + json_event_filter* filter); // **Methods Related to Sinsp Events e.g system calls // @@ -241,14 +239,13 @@ public: std::set &evttypes, std::set &syscalls, std::set &tags, - sinsp_filter *filter); + sinsp_filter* filter); sinsp_filter_factory &sinsp_factory(); json_event_filter_factory &json_factory(); - bool is_ready(); - private: + static nlohmann::json::json_pointer k8s_audit_time; // @@ -300,6 +297,5 @@ private: std::string m_extra; bool m_replace_container_info; - - bool m_is_ready = false; }; + diff --git a/userspace/falco/CMakeLists.txt b/userspace/falco/CMakeLists.txt index e6073309..5a4d6a89 100644 --- a/userspace/falco/CMakeLists.txt +++ b/userspace/falco/CMakeLists.txt @@ -61,6 +61,8 @@ if(USE_BUNDLED_DEPS) list(APPEND FALCO_DEPENDENCIES yamlcpp) endif() + + if(NOT MINIMAL_BUILD) list( APPEND FALCO_SOURCES @@ -110,6 +112,18 @@ add_executable( ${FALCO_SOURCES} ) +if(DEFINED LIBHAWK_LIBRARIES) + message(STATUS "Using externally provided libhawk implementations: ${LIBHAWK_LIBRARIES}") + list( + APPEND FALCO_LIBRARIES + "${LIBHAWK_LIBRARIES}" + ) + list( + APPEND FALCO_INCLUDE_DIRECTORIES + "${PROJECT_SOURCE_DIR}/userspace/libhawk" + ) +endif() + add_dependencies(falco ${FALCO_DEPENDENCIES}) target_link_libraries( diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 3957b815..f53bce89 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -58,6 +58,16 @@ void falco_configuration::init(string conf_filename, list &cmdline_optio m_config->get_sequence>(rules_files, string("rules_file")); + for(auto &file : rules_files) + { + // Here, we only include files that exist + struct stat buffer; + if(stat(file.c_str(), &buffer) == 0) + { + read_rules_file_directory(file, m_rules_filenames); + } + } + m_json_output = m_config->get_scalar("json_output", false); m_json_include_output_property = m_config->get_scalar("json_include_output_property", true); @@ -224,6 +234,69 @@ void falco_configuration::init(string conf_filename, list &cmdline_optio m_syscall_evt_simulate_drops = m_config->get_scalar("syscall_event_drops", "simulate_drops", false); } +void falco_configuration::read_rules_file_directory(const string &path, list &rules_filenames) +{ + struct stat st; + + int rc = stat(path.c_str(), &st); + + if(rc != 0) + { + std::cerr << "Could not get info on rules file " << path << ": " << strerror(errno) << std::endl; + exit(-1); + } + + if(st.st_mode & S_IFDIR) + { + // It's a directory. Read the contents, sort + // alphabetically, and add every path to + // rules_filenames + vector dir_filenames; + + DIR *dir = opendir(path.c_str()); + + if(!dir) + { + std::cerr << "Could not get read contents of directory " << path << ": " << strerror(errno) << std::endl; + exit(-1); + } + + for(struct dirent *ent = readdir(dir); ent; ent = readdir(dir)) + { + string efile = path + "/" + ent->d_name; + + rc = stat(efile.c_str(), &st); + + if(rc != 0) + { + std::cerr << "Could not get info on rules file " << efile << ": " << strerror(errno) << std::endl; + exit(-1); + } + + if(st.st_mode & S_IFREG) + { + dir_filenames.push_back(efile); + } + } + + closedir(dir); + + std::sort(dir_filenames.begin(), + dir_filenames.end()); + + for(string &ent : dir_filenames) + { + rules_filenames.push_back(ent); + } + } + else + { + // Assume it's a file and just add to + // rules_filenames. If it can't be opened/etc that + // will be reported later.. + rules_filenames.push_back(path); + } +} static bool split(const string &str, char delim, pair &parts) { @@ -265,4 +338,4 @@ void falco_configuration::set_cmdline_option(const string &opt) { m_config->set_scalar(keyval.first, keyval.second); } -} +} \ No newline at end of file diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index bfc2b9c9..aa0bc2ea 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -190,6 +190,9 @@ public: void init(std::string conf_filename, std::list& cmdline_options); void init(std::list& cmdline_options); + static void read_rules_file_directory(const string& path, list& rules_filenames); + + std::list m_rules_filenames; bool m_json_output; bool m_json_include_output_property; std::string m_log_level; diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index 85796365..e03886ff 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -31,7 +31,6 @@ limitations under the License. #include #include #include -#include #include @@ -49,18 +48,22 @@ limitations under the License. #include "webserver.h" #include "grpc_server.h" #endif +extern "C" +{ +#include "hawk.h" +} #include "banned.h" // This raises a compilation error when certain functions are used -typedef function open_t; +typedef function open_t; bool g_terminate = false; bool g_reopen_outputs = false; bool g_restart = false; bool g_daemonized = false; -std::mutex engine_ready; -std::condition_variable engine_cv; -bool is_engine_ready = false; +std::mutex g_engine_ready; +std::condition_variable g_engine_cv; +bool g_is_engine_ready = false; // // Helper functions @@ -85,97 +88,100 @@ static void restart_falco(int signal) // static void usage() { - printf( - "Falco version: " FALCO_VERSION "\n" - "Usage: falco [options]\n\n" - "Options:\n" - " -h, --help Print this page\n" - " -c Configuration file (default " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ")\n" - " -A Monitor all events, including those with EF_DROP_SIMPLE_CONS flag.\n" - " --alternate-lua-dir Specify an alternate path for loading Falco lua files\n" - " -b, --print-base64 Print data buffers in base64.\n" - " This is useful for encoding binary data that needs to be used over media designed to.\n" - " --cri Path to CRI socket for container metadata.\n" - " Use the specified socket to fetch data from a CRI-compatible runtime.\n" - " -d, --daemon Run as a daemon.\n" - " --disable-cri-async Disable asynchronous CRI metadata fetching.\n" - " This is useful to let the input event wait for the container metadata fetch\n" - " to finish before moving forward. Async fetching, in some environments leads\n" - " to empty fields for container metadata when the fetch is not fast enough to be\n" - " completed asynchronously. This can have a performance penalty on your environment\n" - " depending on the number of containers and the frequency at which they are created/started/stopped\n" - " --disable-source \n" - " Disable a specific event source.\n" - " Available event sources are: syscall, k8s_audit.\n" - " It can be passed multiple times.\n" - " Can not disable both the event sources.\n" - " -D Disable any rules with names having the substring . Can be specified multiple times.\n" - " Can not be specified with -t.\n" - " -e Read the events from (in .scap format for sinsp events, or jsonl for\n" - " k8s audit events) instead of tapping into live.\n" + printf( + "Falco version: " FALCO_VERSION "\n" + "Usage: falco [options]\n\n" + "Options:\n" + " -h, --help Print this page\n" + " -c Configuration file (default " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ")\n" + " -A Monitor all events, including those with EF_DROP_SIMPLE_CONS flag.\n" + " --alternate-lua-dir Specify an alternate path for loading Falco lua files\n" + " -b, --print-base64 Print data buffers in base64.\n" + " This is useful for encoding binary data that needs to be used over media designed to.\n" + " --cri Path to CRI socket for container metadata.\n" + " Use the specified socket to fetch data from a CRI-compatible runtime.\n" + " -d, --daemon Run as a daemon.\n" + " --disable-cri-async Disable asynchronous CRI metadata fetching.\n" + " This is useful to let the input event wait for the container metadata fetch\n" + " to finish before moving forward. Async fetching, in some environments leads\n" + " to empty fields for container metadata when the fetch is not fast enough to be\n" + " completed asynchronously. This can have a performance penalty on your environment\n" + " depending on the number of containers and the frequency at which they are created/started/stopped\n" + " --disable-source \n" + " Disable a specific event source.\n" + " Available event sources are: syscall, k8s_audit.\n" + " It can be passed multiple times.\n" + " Can not disable both the event sources.\n" + " -D Disable any rules with names having the substring . Can be specified multiple times.\n" + " Can not be specified with -t.\n" + " -e Read the events from (in .scap format for sinsp events, or jsonl for\n" + " k8s audit events) instead of tapping into live.\n" #ifndef MINIMAL_BUILD - " -k , --k8s-api \n" - " Enable Kubernetes support by connecting to the API server specified as argument.\n" - " E.g. \"http://admin:password@127.0.0.1:8080\".\n" - " The API server can also be specified via the environment variable FALCO_K8S_API.\n" - " -K | :[:], --k8s-api-cert | :[:]\n" - " Use the provided files names to authenticate user and (optionally) verify the K8S API server identity.\n" - " Each entry must specify full (absolute, or relative to the current directory) path to the respective file.\n" - " Private key password is optional (needed only if key is password protected).\n" - " CA certificate is optional. For all files, only PEM file format is supported. \n" - " Specifying CA certificate only is obsoleted - when single entry is provided \n" - " for this option, it will be interpreted as the name of a file containing bearer token.\n" - " Note that the format of this command-line option prohibits use of files whose names contain\n" - " ':' or '#' characters in the file name.\n" + " -k , --k8s-api \n" + " Enable Kubernetes support by connecting to the API server specified as argument.\n" + " E.g. \"http://admin:password@127.0.0.1:8080\".\n" + " The API server can also be specified via the environment variable FALCO_K8S_API.\n" + " -K | :[:], --k8s-api-cert | :[:]\n" + " Use the provided files names to authenticate user and (optionally) verify the K8S API server identity.\n" + " Each entry must specify full (absolute, or relative to the current directory) path to the respective file.\n" + " Private key password is optional (needed only if key is password protected).\n" + " CA certificate is optional. For all files, only PEM file format is supported. \n" + " Specifying CA certificate only is obsoleted - when single entry is provided \n" + " for this option, it will be interpreted as the name of a file containing bearer token.\n" + " Note that the format of this command-line option prohibits use of files whose names contain\n" + " ':' or '#' characters in the file name.\n" #endif - " -L Show the name and description of all rules and exit.\n" - " -l Show the name and description of the rule with name and exit.\n" - " --list [] List all defined fields. If is provided, only list those fields for\n" - " the source . Current values for are \"syscall\", \"k8s_audit\"\n" + " -L Show the name and description of all rules and exit.\n" + " -l Show the name and description of the rule with name and exit.\n" + " --list [] List all defined fields. If is provided, only list those fields for\n" + " the source . Current values for are \"syscall\", \"k8s_audit\"\n" #ifndef MINIMAL_BUILD - " -m , --mesos-api \n" - " Enable Mesos support by connecting to the API server\n" - " specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\".\n" - " Marathon url is optional and defaults to Mesos address, port 8080.\n" - " The API servers can also be specified via the environment variable FALCO_MESOS_API.\n" + " -m , --mesos-api \n" + " Enable Mesos support by connecting to the API server\n" + " specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\".\n" + " Marathon url is optional and defaults to Mesos address, port 8080.\n" + " The API servers can also be specified via the environment variable FALCO_MESOS_API.\n" #endif - " -M Stop collecting after reached.\n" - " -N When used with --list, only print field names.\n" - " -o, --option = Set the value of option to . Overrides values in configuration file.\n" - " can be a two-part .\n" - " -p , --print \n" - " Add additional information to each falco notification's output.\n" - " With -pc or -pcontainer will use a container-friendly format.\n" - " With -pk or -pkubernetes will use a kubernetes-friendly format.\n" - " With -pm or -pmesos will use a mesos-friendly format.\n" - " Additionally, specifying -pc/-pk/-pm will change the interpretation\n" - " of %%container.info in rule output fields.\n" - " -P, --pidfile When run as a daemon, write pid to specified file\n" - " -s If specified, append statistics related to Falco's reading/processing of events\n" - " to this file (only useful in live mode).\n" - " --stats-interval When using -s , write statistics every ms.\n" - " This uses signals, so don't recommend intervals below 200 ms.\n" - " Defaults to 5000 (5 seconds).\n" - " -S , --snaplen \n" - " Capture the first bytes of each I/O buffer.\n" - " By default, the first 80 bytes are captured. Use this\n" - " option with caution, it can generate huge trace files.\n" - " --support Print support information including version, etc. and exit.\n" - " -T Disable any rules with a tag=. Can be specified multiple times.\n" - " Can not be specified with -t.\n" - " -t Only run those rules with a tag=. Can be specified multiple times.\n" - " Can not be specified with -T/-D.\n" - " -U,--unbuffered Turn off output buffering to configured outputs.\n" - " This causes every single line emitted by falco to be flushed,\n" - " which generates higher CPU usage but is useful when piping those outputs\n" - " into another process or into a script.\n" - " -u, --userspace Parse events from userspace.\n" - " To be used in conjunction with the ptrace(2) based driver (pdig).\n" - " -V, --validate Read the contents of the specified rules(s) file and exit.\n" - " Can be specified multiple times to validate multiple files.\n" - " -v Verbose output.\n" - " --version Print version number.\n" - "\n"); + " -M Stop collecting after reached.\n" + " -N When used with --list, only print field names.\n" + " -o, --option = Set the value of option to . Overrides values in configuration file.\n" + " can be a two-part .\n" + " -p , --print \n" + " Add additional information to each falco notification's output.\n" + " With -pc or -pcontainer will use a container-friendly format.\n" + " With -pk or -pkubernetes will use a kubernetes-friendly format.\n" + " With -pm or -pmesos will use a mesos-friendly format.\n" + " Additionally, specifying -pc/-pk/-pm will change the interpretation\n" + " of %%container.info in rule output fields.\n" + " -P, --pidfile When run as a daemon, write pid to specified file\n" + " -r Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml).\n" + " Can be specified multiple times to read from multiple files/directories.\n" + " -s If specified, append statistics related to Falco's reading/processing of events\n" + " to this file (only useful in live mode).\n" + " --stats-interval When using -s , write statistics every ms.\n" + " This uses signals, so don't recommend intervals below 200 ms.\n" + " Defaults to 5000 (5 seconds).\n" + " -S , --snaplen \n" + " Capture the first bytes of each I/O buffer.\n" + " By default, the first 80 bytes are captured. Use this\n" + " option with caution, it can generate huge trace files.\n" + " --support Print support information including version, rules files used, etc. and exit.\n" + " -T Disable any rules with a tag=. Can be specified multiple times.\n" + " Can not be specified with -t.\n" + " -t Only run those rules with a tag=. Can be specified multiple times.\n" + " Can not be specified with -T/-D.\n" + " -U,--unbuffered Turn off output buffering to configured outputs.\n" + " This causes every single line emitted by falco to be flushed,\n" + " which generates higher CPU usage but is useful when piping those outputs\n" + " into another process or into a script.\n" + " -u, --userspace Parse events from userspace.\n" + " To be used in conjunction with the ptrace(2) based driver (pdig).\n" + " -V, --validate Read the contents of the specified rules(s) file and exit.\n" + " Can be specified multiple times to validate multiple files.\n" + " -v Verbose output.\n" + " --version Print version number.\n" + "\n" + ); } static void display_fatal_err(const string &msg) @@ -186,7 +192,7 @@ static void display_fatal_err(const string &msg) * If stderr logging is not enabled, also log to stderr. When * daemonized this will simply write to /dev/null. */ - if(!falco_logger::log_stderr) + if (! falco_logger::log_stderr) { std::cerr << msg; } @@ -238,20 +244,20 @@ static std::string read_file(std::string filename) // // Event processing loop // -uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs, - sinsp *inspector, - falco_configuration &config, - syscall_evt_drop_mgr &sdropmgr, - uint64_t duration_to_tot_ns, - string &stats_filename, - uint64_t stats_interval, - bool all_events, - int &result) +uint64_t do_inspect(falco_engine **engine, + falco_outputs *outputs, + sinsp* inspector, + falco_configuration &config, + syscall_evt_drop_mgr &sdropmgr, + uint64_t duration_to_tot_ns, + string &stats_filename, + uint64_t stats_interval, + bool all_events, + int &result) { - uint64_t num_evts = 0; int32_t rc; - sinsp_evt *ev; + sinsp_evt* ev; StatsFileWriter writer; uint64_t duration_start = 0; @@ -262,11 +268,11 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs, config.m_syscall_evt_drop_max_burst, config.m_syscall_evt_simulate_drops); - if(stats_filename != "") + if (stats_filename != "") { string errstr; - if(!writer.init(inspector, stats_filename, stats_interval, errstr)) + if (!writer.init(inspector, stats_filename, stats_interval, errstr)) { throw falco_exception(errstr); } @@ -274,8 +280,8 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs, { // wait for the first engine to be ready - std::unique_lock lk(engine_ready); - engine_cv.wait(lk, [] { return is_engine_ready; }); + std::unique_lock lk(g_engine_ready); + g_engine_cv.wait(lk, [] { return g_is_engine_ready; }); } // @@ -287,6 +293,7 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs, e.compare_exchange_strong(engine_to_use, *engine); while(1) { + rc = inspector->next(&ev); writer.handle(); @@ -302,7 +309,7 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs, falco_logger::log(LOG_INFO, "SIGINT received, exiting...\n"); break; } - else if(g_restart) + else if (g_restart) { falco_logger::log(LOG_INFO, "SIGHUP received, restarting...\n"); break; @@ -325,11 +332,10 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs, throw sinsp_exception(inspector->getlasterr().c_str()); } - if(duration_start == 0) + if (duration_start == 0) { duration_start = ev->get_ts(); - } - else if(duration_to_tot_ns > 0) + } else if(duration_to_tot_ns > 0) { if(ev->get_ts() - duration_start >= duration_to_tot_ns) { @@ -372,9 +378,9 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs, static void print_all_ignored_events(sinsp *inspector) { - sinsp_evttables *einfo = inspector->get_event_info_tables(); - const struct ppm_event_info *etable = einfo->m_event_info; - const struct ppm_syscall_desc *stable = einfo->m_syscall_info_table; + sinsp_evttables* einfo = inspector->get_event_info_tables(); + const struct ppm_event_info* etable = einfo->m_event_info; + const struct ppm_syscall_desc* stable = einfo->m_syscall_info_table; std::set ignored_event_names; for(uint32_t j = 0; j < PPM_EVENT_MAX; j++) @@ -438,11 +444,11 @@ static void rules_cb(char *rules_content, hawk_engine *engine) // This mutex is only needed for the first synchronization // it can be discarded the second time rules_cb is needed // since the main engine loop is already started. - if(!is_engine_ready) + if(!g_is_engine_ready) { - std::lock_guard lk(engine_ready); - is_engine_ready = true; - engine_cv.notify_all(); + std::lock_guard lk(g_engine_ready); + g_is_engine_ready = true; + g_engine_cv.notify_all(); } } @@ -452,7 +458,7 @@ static void rules_cb(char *rules_content, hawk_engine *engine) int falco_init(int argc, char **argv) { int result = EXIT_SUCCESS; - sinsp *inspector = NULL; + sinsp* inspector = NULL; sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL; falco_engine *engine_blueprint; std::thread watchrules_thread; @@ -476,9 +482,9 @@ int falco_init(int argc, char **argv) bool names_only = false; bool all_events = false; #ifndef MINIMAL_BUILD - string *k8s_api = 0; - string *k8s_api_cert = 0; - string *mesos_api = 0; + string* k8s_api = 0; + string* k8s_api_cert = 0; + string* mesos_api = 0; #endif string output_format = ""; uint32_t snaplen = 0; @@ -503,7 +509,7 @@ int falco_init(int argc, char **argv) bool compress = false; bool buffered_outputs = true; bool buffered_cmdline = false; - std::map required_engine_versions; + std::map required_engine_versions; // Used for stats double duration; @@ -555,8 +561,8 @@ int falco_init(int argc, char **argv) // Parse the args // while((op = getopt_long(argc, argv, - "hc:AbdD:e:F:ik:K:Ll:m:M:No:P:p:S:s:T:t:UuvV:w:", - long_options, &long_index)) != -1) + "hc:AbdD:e:F:ik:K:Ll:m:M:No:P:p:r:S:s:T:t:UuvV:w:", + long_options, &long_index)) != -1) { switch(op) { @@ -649,6 +655,9 @@ int falco_init(int argc, char **argv) replace_container_info = false; } break; + case 'r': + falco_configuration::read_rules_file_directory(string(optarg), rules_filenames); + break; case 'S': snaplen = atoi(optarg); break; @@ -688,18 +697,18 @@ int falco_init(int argc, char **argv) printf("Driver version: %s\n", DRIVER_VERSION); return EXIT_SUCCESS; } - else if(string(long_options[long_index].name) == "cri") + else if (string(long_options[long_index].name) == "cri") { if(optarg != NULL) { cri_socket_path = optarg; } } - else if(string(long_options[long_index].name) == "disable-cri-async") + else if (string(long_options[long_index].name) == "disable-cri-async") { - cri_async = false; + cri_async = false; } - else if(string(long_options[long_index].name) == "list") + else if (string(long_options[long_index].name) == "list") { list_flds = true; if(optarg != NULL) @@ -707,28 +716,27 @@ int falco_init(int argc, char **argv) list_flds_source = optarg; } } - else if(string(long_options[long_index].name) == "stats-interval") + else if (string(long_options[long_index].name) == "stats-interval") { stats_interval = atoi(optarg); } - else if(string(long_options[long_index].name) == "support") + else if (string(long_options[long_index].name) == "support") { print_support = true; } - else if(string(long_options[long_index].name) == "disable-source") + else if (string(long_options[long_index].name) == "disable-source") { if(optarg != NULL) { disable_sources.insert(optarg); } } - else if(string(long_options[long_index].name) == "alternate-lua-dir") + else if (string(long_options[long_index].name)== "alternate-lua-dir") { if(optarg != NULL) { alternate_lua_dir = optarg; - if(alternate_lua_dir.back() != '/') - { + if (alternate_lua_dir.back() != '/') { alternate_lua_dir += '/'; } } @@ -738,6 +746,7 @@ int falco_init(int argc, char **argv) default: break; } + } inspector = new sinsp(); @@ -771,11 +780,11 @@ int falco_init(int argc, char **argv) engine_blueprint->set_inspector(inspector); engine_blueprint->set_extra(output_format, replace_container_info); - // if(list_flds) - // { - // list_source_fields(engine, verbose, names_only, list_flds_source); - // return EXIT_SUCCESS; - // } + if(list_flds) + { + // list_source_fields(engine, verbose, names_only, list_flds_source); + return EXIT_SUCCESS; + } if(disable_sources.size() > 0) { @@ -791,23 +800,21 @@ int falco_init(int argc, char **argv) } disable_syscall = disable_sources.count("syscall") > 0; disable_k8s_audit = disable_sources.count("k8s_audit") > 0; - if(disable_syscall && disable_k8s_audit) - { + if (disable_syscall && disable_k8s_audit) { throw std::invalid_argument("The event source \"syscall\" and \"k8s_audit\" can not be disabled together"); } } // Some combinations of arguments are not allowed. - if(daemon && pidfilename == "") - { + if (daemon && pidfilename == "") { throw std::invalid_argument("If -d is provided, a pid file must also be provided"); } ifstream conf_stream; - if(conf_filename.size()) + if (conf_filename.size()) { conf_stream.open(conf_filename); - if(!conf_stream.is_open()) + if (!conf_stream.is_open()) { throw std::runtime_error("Could not find configuration file at " + conf_filename); } @@ -815,14 +822,14 @@ int falco_init(int argc, char **argv) else { conf_stream.open(FALCO_SOURCE_CONF_FILE); - if(conf_stream.is_open()) + if (conf_stream.is_open()) { conf_filename = FALCO_SOURCE_CONF_FILE; } else { conf_stream.open(FALCO_INSTALL_CONF_FILE); - if(conf_stream.is_open()) + if (conf_stream.is_open()) { conf_filename = FALCO_INSTALL_CONF_FILE; } @@ -861,7 +868,7 @@ int falco_init(int argc, char **argv) // } falco_configuration config; - if(conf_filename.size()) + if (conf_filename.size()) { config.init(conf_filename, cmdline_options); falco_logger::set_time_format_iso_8601(config.m_time_format_iso_8601); @@ -875,6 +882,11 @@ int falco_init(int argc, char **argv) throw std::runtime_error("Could not find configuration file at " + conf_filename); } + if (rules_filenames.size()) + { + config.m_rules_filenames = rules_filenames; + } + engine_blueprint->set_min_priority(config.m_min_priority); if(buffered_cmdline) @@ -882,6 +894,60 @@ int falco_init(int argc, char **argv) config.m_buffered_outputs = buffered_outputs; } + if(config.m_rules_filenames.size() == 0) + { + // throw std::invalid_argument("You must specify at least one rules file/directory via -r or a rules_file entry in falco.yaml"); + } + + falco_logger::log(LOG_DEBUG, "Configured rules filenames:\n"); + for (auto filename : config.m_rules_filenames) + { + falco_logger::log(LOG_DEBUG, string(" ") + filename + "\n"); + } + + for (auto filename : config.m_rules_filenames) + { + falco_logger::log(LOG_INFO, "Loading rules from file " + filename + ":\n"); + uint64_t required_engine_version; + + // engine->load_rules_file(filename, verbose, all_events, required_engine_version); + required_engine_versions[filename] = required_engine_version; + } + + // You can't both disable and enable rules + if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) && + enabled_rule_tags.size() > 0) { + throw std::invalid_argument("You can not specify both disabled (-D/-T) and enabled (-t) rules"); + } + + for (auto substring : disabled_rule_substrings) + { + falco_logger::log(LOG_INFO, "Disabling rules matching substring: " + substring + "\n"); + // engine->enable_rule(substring, false); + } + + if(disabled_rule_tags.size() > 0) + { + for(auto tag : disabled_rule_tags) + { + falco_logger::log(LOG_INFO, "Disabling rules with tag: " + tag + "\n"); + } + // engine->enable_rule_by_tag(disabled_rule_tags, false); + } + + if(enabled_rule_tags.size() > 0) + { + + // Since we only want to enable specific + // rules, first disable all rules. + // engine->enable_rule(all_rules, false); + for(auto tag : enabled_rule_tags) + { + falco_logger::log(LOG_INFO, "Enabling rules with tag: " + tag + "\n"); + } + // engine->enable_rule_by_tag(enabled_rule_tags, true); + } + hawk_init(); watchrules_thread = std::thread([&] { // todo: pass verbose, and all_events @@ -980,14 +1046,24 @@ int falco_init(int argc, char **argv) support["system_info"]["machine"] = sysinfo.machine; support["cmdline"] = cmdline; support["config"] = read_file(conf_filename); - support["rules_source"] = "external"; // todo(fntlnz): do we want to let libhawk pass an identifier and maybe more dump info for this? + support["rules_files"] = nlohmann::json::array(); + for(auto filename : config.m_rules_filenames) + { + nlohmann::json finfo; + finfo["name"] = filename; + nlohmann::json variant; + variant["required_engine_version"] = required_engine_versions[filename]; + variant["content"] = read_file(filename); + finfo["variants"].push_back(variant); + support["rules_files"].push_back(finfo); + } printf("%s\n", support.dump().c_str()); goto exit; } // read hostname string hostname; - if(char *env_hostname = getenv("FALCO_GRPC_HOSTNAME")) + if(char* env_hostname = getenv("FALCO_GRPC_HOSTNAME")) { hostname = env_hostname; } @@ -1007,13 +1083,13 @@ int falco_init(int argc, char **argv) inspector->set_drop_event_flags(EF_DROP_SIMPLE_CONS); } - if(describe_all_rules) + if (describe_all_rules) { // engine->describe_rule(NULL); goto exit; } - if(describe_rule != "") + if (describe_rule != "") { // engine->describe_rule(&describe_rule); goto exit; @@ -1051,25 +1127,21 @@ int falco_init(int argc, char **argv) // If daemonizing, do it here so any init errors will // be returned in the foreground process. - if(daemon && !g_daemonized) - { + if (daemon && !g_daemonized) { pid_t pid, sid; pid = fork(); - if(pid < 0) - { + if (pid < 0) { // error falco_logger::log(LOG_ERR, "Could not fork. Exiting.\n"); result = EXIT_FAILURE; goto exit; - } - else if(pid > 0) - { + } else if (pid > 0) { // parent. Write child pid to pidfile and exit std::ofstream pidfile; pidfile.open(pidfilename); - if(!pidfile.good()) + if (!pidfile.good()) { falco_logger::log(LOG_ERR, "Could not write pid to pid file " + pidfilename + ". Exiting.\n"); result = EXIT_FAILURE; @@ -1083,8 +1155,7 @@ int falco_init(int argc, char **argv) // Become own process group. sid = setsid(); - if(sid < 0) - { + if (sid < 0) { falco_logger::log(LOG_ERR, "Could not set session id. Exiting.\n"); result = EXIT_FAILURE; goto exit; @@ -1094,8 +1165,7 @@ int falco_init(int argc, char **argv) umask(027); // Change working directory to '/' - if((chdir("/")) < 0) - { + if ((chdir("/")) < 0) { falco_logger::log(LOG_ERR, "Could not change working directory to '/'. Exiting.\n"); result = EXIT_FAILURE; goto exit; @@ -1131,15 +1201,14 @@ int falco_init(int argc, char **argv) { // Try to open the trace file as a sysdig // capture file first. - try - { + try { inspector->open(trace_filename); falco_logger::log(LOG_INFO, "Reading system call events from file: " + trace_filename + "\n"); } catch(sinsp_exception &e) { falco_logger::log(LOG_DEBUG, "Could not read trace file \"" + trace_filename + "\": " + string(e.what())); - trace_is_scap = false; + trace_is_scap=false; } if(!trace_is_scap) @@ -1150,8 +1219,7 @@ int falco_init(int argc, char **argv) result = EXIT_FAILURE; goto exit; #else - try - { + try { string line; nlohmann::json j; @@ -1163,13 +1231,13 @@ int falco_init(int argc, char **argv) falco_logger::log(LOG_INFO, "Reading k8s audit events from file: " + trace_filename + "\n"); } - catch(nlohmann::json::parse_error &e) + catch (nlohmann::json::parse_error& e) { fprintf(stderr, "Trace filename %s not recognized as system call events or k8s audit events\n", trace_filename.c_str()); result = EXIT_FAILURE; goto exit; } - catch(exception &e) + catch (exception &e) { fprintf(stderr, "Could not open trace filename %s for reading: %s\n", trace_filename.c_str(), e.what()); result = EXIT_FAILURE; @@ -1180,7 +1248,8 @@ int falco_init(int argc, char **argv) } else { - open_t open_cb = [&userspace](sinsp *inspector) { + open_t open_cb = [&userspace](sinsp* inspector) + { if(userspace) { // open_udig() is the underlying method used in the capture code to parse userspace events from the kernel. @@ -1192,22 +1261,19 @@ int falco_init(int argc, char **argv) } inspector->open(); }; - open_t open_nodriver_cb = [](sinsp *inspector) { + open_t open_nodriver_cb = [](sinsp* inspector) { inspector->open_nodriver(); }; open_t open_f; // Default mode: both event sources enabled - if(!disable_syscall && !disable_k8s_audit) - { + if (!disable_syscall && !disable_k8s_audit) { open_f = open_cb; } - if(disable_syscall) - { + if (disable_syscall) { open_f = open_nodriver_cb; } - if(disable_k8s_audit) - { + if (disable_k8s_audit) { open_f = open_cb; } @@ -1218,7 +1284,7 @@ int falco_init(int argc, char **argv) catch(sinsp_exception &e) { // If syscall input source is enabled and not through userspace instrumentation - if(!disable_syscall && !userspace) + if (!disable_syscall && !userspace) { // Try to insert the Falco kernel module if(system("modprobe " PROBE_NAME " > /dev/null 2> /dev/null")) @@ -1226,8 +1292,8 @@ int falco_init(int argc, char **argv) falco_logger::log(LOG_ERR, "Unable to load the driver.\n"); } open_f(inspector); - } - else + } + else { rethrow_exception(current_exception()); } @@ -1256,7 +1322,7 @@ int falco_init(int argc, char **argv) { if(!k8s_api_cert) { - if(char *k8s_cert_env = getenv("FALCO_K8S_API_CERT")) + if(char* k8s_cert_env = getenv("FALCO_K8S_API_CERT")) { k8s_api_cert = new string(k8s_cert_env); } @@ -1265,13 +1331,13 @@ int falco_init(int argc, char **argv) k8s_api = 0; k8s_api_cert = 0; } - else if(char *k8s_api_env = getenv("FALCO_K8S_API")) + else if(char* k8s_api_env = getenv("FALCO_K8S_API")) { if(k8s_api_env != NULL) { if(!k8s_api_cert) { - if(char *k8s_cert_env = getenv("FALCO_K8S_API_CERT")) + if(char* k8s_cert_env = getenv("FALCO_K8S_API_CERT")) { k8s_api_cert = new string(k8s_cert_env); } @@ -1295,7 +1361,7 @@ int falco_init(int argc, char **argv) { inspector->init_mesos_client(mesos_api, verbose); } - else if(char *mesos_api_env = getenv("FALCO_MESOS_API")) + else if(char* mesos_api_env = getenv("FALCO_MESOS_API")) { if(mesos_api_env != NULL) { @@ -1310,7 +1376,7 @@ int falco_init(int argc, char **argv) { // std::string ssl_option = (config.m_webserver_ssl_enabled ? " (SSL)" : ""); // falco_logger::log(LOG_INFO, "Starting internal webserver, listening on port " + to_string(config.m_webserver_listen_port) + ssl_option + "\n"); - // webserver.init(&config, engine_future.get().get(), outputs); + // webserver.init(&config, engine, outputs); // webserver.start(); } @@ -1326,17 +1392,19 @@ int falco_init(int argc, char **argv) config.m_grpc_private_key, config.m_grpc_cert_chain, config.m_grpc_root_certs, - config.m_log_level); + config.m_log_level + ); grpc_server_thread = std::thread([&grpc_server] { grpc_server.run(); }); } #endif + if(!trace_filename.empty() && !trace_is_scap) { -#ifndef MINIMAL_BUILD - // read_k8s_audit_trace_file(engine.get(), +#ifndef MINIMAL_BUILD + // read_k8s_audit_trace_file(engine, // outputs, // trace_filename); #endif @@ -1345,11 +1413,12 @@ int falco_init(int argc, char **argv) { uint64_t num_evts; - num_evts = do_inspect(&engine_blueprint, outputs, + num_evts = do_inspect(&engine_blueprint, + outputs, inspector, config, sdropmgr, - uint64_t(duration_to_tot * ONE_SECOND_IN_NS), + uint64_t(duration_to_tot*ONE_SECOND_IN_NS), stats_filename, stats_interval, all_events, @@ -1370,12 +1439,13 @@ int falco_init(int argc, char **argv) num_evts, num_evts / duration); } + } // Honor -M also when using a trace file. // Since inspection stops as soon as all events have been consumed // just await the given duration is reached, if needed. - if(!trace_filename.empty() && duration_to_tot > 0) + if(!trace_filename.empty() && duration_to_tot>0) { std::this_thread::sleep_for(std::chrono::seconds(duration_to_tot)); } @@ -1400,14 +1470,13 @@ int falco_init(int argc, char **argv) catch(exception &e) { display_fatal_err("Runtime error: " + string(e.what()) + ". Exiting.\n"); - - result = EXIT_FAILURE; - if(watchrules_thread.joinable()) { hawk_destroy(); watchrules_thread.join(); } + result = EXIT_FAILURE; + #ifndef MINIMAL_BUILD webserver.stop(); if(grpc_server_thread.joinable())