From b1d88c509fca17b4eb1fc2e5814e470dfe5f8488 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 2 Jul 2021 17:17:41 -0700 Subject: [PATCH] Update to reflect new plugin api/config in proposal --- cmake/modules/falcosecurity-libs.cmake | 4 +- tests/CMakeLists.txt | 2 + userspace/falco/config_falco.h.in | 1 + userspace/falco/configuration.cpp | 29 +++++- userspace/falco/configuration.h | 121 ++++++++++++++++++++++++- userspace/falco/falco.cpp | 38 +++++--- 6 files changed, 172 insertions(+), 23 deletions(-) diff --git a/cmake/modules/falcosecurity-libs.cmake b/cmake/modules/falcosecurity-libs.cmake index 5a635a10..7567297d 100644 --- a/cmake/modules/falcosecurity-libs.cmake +++ b/cmake/modules/falcosecurity-libs.cmake @@ -20,8 +20,8 @@ file(MAKE_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR}) # default below In case you want to test against another falcosecurity/libs version just pass the variable - ie., `cmake # -DFALCOSECURITY_LIBS_VERSION=dev ..` if(NOT FALCOSECURITY_LIBS_VERSION) - set(FALCOSECURITY_LIBS_VERSION "new/plugin-system") - set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=91e710d0ff5cedbeac9e3249680e6f66e834a4662eaa38a5c19e43e8a2cbd2e5") + set(FALCOSECURITY_LIBS_VERSION "new/plugin-system-api-additions") + set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=5f430325d7e29747208c1f7e68d9b885a215093634fdf2f456c6993d51fc83bc") endif() # cd /path/to/build && cmake /path/to/source diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dfb87fb8..b0318095 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -46,6 +46,7 @@ if(FALCO_BUILD_TESTS) PUBLIC "${CATCH2_INCLUDE}" "${FAKEIT_INCLUDE}" "${PROJECT_SOURCE_DIR}/userspace/engine" + "${PROJECT_BINARY_DIR}/userspace/falco" "${YAMLCPP_INCLUDE_DIR}" "${PROJECT_SOURCE_DIR}/userspace/falco") else() @@ -54,6 +55,7 @@ if(FALCO_BUILD_TESTS) PUBLIC "${CATCH2_INCLUDE}" "${FAKEIT_INCLUDE}" "${PROJECT_SOURCE_DIR}/userspace/engine" + "${PROJECT_BINARY_DIR}/userspace/falco" "${YAMLCPP_INCLUDE_DIR}" "${CIVETWEB_INCLUDE_DIR}" "${PROJECT_SOURCE_DIR}/userspace/falco") diff --git a/userspace/falco/config_falco.h.in b/userspace/falco/config_falco.h.in index 1b95dae6..cd74a83a 100644 --- a/userspace/falco/config_falco.h.in +++ b/userspace/falco/config_falco.h.in @@ -28,6 +28,7 @@ limitations under the License. #define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}" #define FALCO_SOURCE_CONF_FILE "${PROJECT_SOURCE_DIR}/falco.yaml" #define FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml" +#define FALCO_ENGINE_PLUGINS_DIR "${FALCO_ABSOLUTE_SHARE_DIR}/plugins/" #define PROBE_NAME "@PROBE_NAME@" #define DRIVER_VERSION "@PROBE_VERSION@" \ No newline at end of file diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 30b1f21d..454d296a 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -16,6 +16,9 @@ limitations under the License. #include +#include +#include + #include #include #include @@ -253,10 +256,28 @@ void falco_configuration::init(string conf_filename, list &cmdline_optio throw logic_error("Error reading config file(" + m_config_file + "): the maximum consecutive timeouts without an event must be an unsigned integer > 0"); } - m_input_plugin_name = m_config->get_scalar("input_plugin", "name", ""); - m_input_plugin_path = m_config->get_scalar("input_plugin", "path", ""); - m_input_plugin_init_config = m_config->get_scalar("input_plugin", "init_config", ""); - m_input_plugin_open_params = m_config->get_scalar("input_plugin", "open_params", ""); + std::set load_plugins; + m_config->get_sequence>(load_plugins, "load_plugins"); + + std::list plugins; + try + { + m_config->get_sequence>(plugins, string("plugins")); + } + catch (exception &e) + { + // Might be thrown due to not being able to open files + throw logic_error("Error reading config file(" + m_config_file + "): could not load plugins config: " + e.what()); + } + + // If load_plugins has values, only save plugins matching those in values + for (auto &p : plugins) + { + if(load_plugins.empty() || load_plugins.find(p.m_name) != load_plugins.end()) + { + m_plugins.push_back(p); + } + } } void falco_configuration::read_rules_file_directory(const string &path, list &rules_filenames) diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 21f2c2c6..2e71c78d 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -25,6 +25,9 @@ limitations under the License. #include #include #include +#include + +#include "config_falco.h" #include "event_drops.h" #include "falco_outputs.h" @@ -177,6 +180,11 @@ public: } } + void get_node(YAML::Node &ret, const std::string &key) + { + ret = m_root[key]; + } + private: YAML::Node m_root; }; @@ -184,6 +192,15 @@ private: class falco_configuration { public: + + typedef struct { + public: + std::string m_name; + std::string m_library_path; + std::string m_init_config; + std::string m_open_params; + } plugin_config; + falco_configuration(); virtual ~falco_configuration(); @@ -229,10 +246,7 @@ public: uint32_t m_syscall_evt_timeout_max_consecutives; - std::string m_input_plugin_name; - std::string m_input_plugin_path; - std::string m_input_plugin_init_config; - std::string m_input_plugin_open_params; + std::vector m_plugins; private: void init_cmdline_options(std::list& cmdline_options); @@ -247,3 +261,102 @@ private: yaml_configuration* m_config; }; + +namespace YAML { + template<> + struct convert { + + static bool read_file_from_key(const Node &node, const std::string &prefix, std::string &value) + { + std::string key = prefix; + + if(node[key]) + { + value = node[key].as(); + return true; + } + + key += "_file"; + + if(node[key]) + { + std::string path = node[key].as(); + + // prepend share dir if path is not absolute + if(path.at(0) != '/') + { + path = string(FALCO_ENGINE_PLUGINS_DIR) + path; + } + + // Intentionally letting potential + // exception be thrown, will get + // caught when reading config. + std::ifstream f(path); + std::string str((std::istreambuf_iterator(f)), + std::istreambuf_iterator()); + + value = str; + return true; + } + + return false; + } + + // Note that the distinction between + // init_config/init_config_file and + // open_params/open_params_file is lost. But also, + // this class doesn't write yaml config anyway. + static Node encode(const falco_configuration::plugin_config & rhs) { + Node node; + node["name"] = rhs.m_name; + node["library_path"] = rhs.m_library_path; + node["init_config"] = rhs.m_init_config; + node["open_params"] = rhs.m_open_params; + return node; + } + + static bool decode(const Node& node, falco_configuration::plugin_config & rhs) { + if(!node.IsMap()) + { + return false; + } + + if(!node["name"]) + { + return false; + } + else + { + rhs.m_name = node["name"].as(); + } + + if(!node["library_path"]) + { + return false; + } + else + { + rhs.m_library_path = node["library_path"].as(); + + // prepend share dir if path is not absolute + if(rhs.m_library_path.at(0) != '/') + { + rhs.m_library_path = string(FALCO_ENGINE_PLUGINS_DIR) + rhs.m_library_path; + } + + } + + if(!read_file_from_key(node, string("init_config"), rhs.m_init_config)) + { + return false; + } + + if(!read_file_from_key(node, string("open_params"), rhs.m_open_params)) + { + return false; + } + + return true; + } + }; +} diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index 9567181d..6b0959dc 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -129,6 +129,7 @@ static void usage() " -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" + " --list-plugins Print info on all loaded plugins and exit.\n" #ifndef MINIMAL_BUILD " -m , --mesos-api \n" " Enable Mesos support by connecting to the API server\n" @@ -479,6 +480,7 @@ int falco_init(int argc, char **argv) bool print_ignored_events = false; bool list_flds = false; string list_flds_source = ""; + bool list_plugins = false; bool print_support = false; string cri_socket_path; bool cri_async = true; @@ -519,6 +521,7 @@ int falco_init(int argc, char **argv) {"k8s-api-cert", required_argument, 0, 'K'}, {"k8s-api", required_argument, 0, 'k'}, {"list", optional_argument, 0}, + {"list-plugins", no_argument, 0}, {"mesos-api", required_argument, 0, 'm'}, {"option", required_argument, 0, 'o'}, {"pidfile", required_argument, 0, 'P'}, @@ -702,6 +705,10 @@ int falco_init(int argc, char **argv) list_flds_source = optarg; } } + else if (string(long_options[long_index].name) == "list-plugins") + { + list_plugins = true; + } else if (string(long_options[long_index].name) == "stats-interval") { stats_interval = atoi(optarg); @@ -866,27 +873,32 @@ int falco_init(int argc, char **argv) throw std::runtime_error("Could not find configuration file at " + conf_filename); } - if(config.m_input_plugin_path.size() > 0) + for(auto &p : config.m_plugins) { + bool avoid_async = true; - falco_logger::log(LOG_INFO, "Loading input plugin (" + config.m_input_plugin_name + ") from file " + config.m_input_plugin_path + "\n"); + falco_logger::log(LOG_INFO, "Loading plugin (" + p.m_name + ") from file " + p.m_library_path + "\n"); - if(config.m_input_plugin_init_config.size() > 0) - { - sinsp_plugin::register_plugin(inspector, config.m_input_plugin_path, (char *)config.m_input_plugin_init_config.c_str()); - } - else - { - sinsp_plugin::register_plugin(inspector, config.m_input_plugin_path, NULL); - } + sinsp_plugin::register_plugin(inspector, + p.m_library_path, + (p.m_init_config.empty() ? NULL : (char *)p.m_init_config.c_str()), + avoid_async); - inspector->set_input_plugin(config.m_input_plugin_name); - if(config.m_input_plugin_open_params.size() > 0) + // XXX/mstemm adapt this to handle multiple source plugins. + inspector->set_input_plugin(p.m_name); + if(!p.m_open_params.empty()) { - inspector->set_input_plugin_open_params(config.m_input_plugin_open_params); + inspector->set_input_plugin_open_params(p.m_open_params.c_str()); } } + if(list_plugins) + { + std::string desc = sinsp_plugin::plugin_infos(inspector); + printf("%lu Plugins Loaded:\n\n%s\n", config.m_plugins.size(), desc.c_str()); + return EXIT_SUCCESS; + } + if (rules_filenames.size()) { config.m_rules_filenames = rules_filenames;