diff --git a/userspace/falco/app_actions/init_falco_engine.cpp b/userspace/falco/app_actions/init_falco_engine.cpp index 824bf2e8..fd354ae7 100644 --- a/userspace/falco/app_actions/init_falco_engine.cpp +++ b/userspace/falco/app_actions/init_falco_engine.cpp @@ -76,6 +76,8 @@ runnable_action::run_result act_init_falco_engine::run() throw std::invalid_argument("The event source \"syscall\" and \"k8s_audit\" can not be disabled together"); } + app().state().engine->set_min_priority(app().state().config->m_min_priority); + return ret; } diff --git a/userspace/falco/app_actions/list_fields.cpp b/userspace/falco/app_actions/list_fields.cpp new file mode 100644 index 00000000..1dfc4a07 --- /dev/null +++ b/userspace/falco/app_actions/list_fields.cpp @@ -0,0 +1,66 @@ +/* +Copyright (C) 2022 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "list_fields.h" + +namespace falco { +namespace app { + +act_list_fields::act_list_fields(application &app) + : action(app), m_name("list fields"), + m_prerequsites({"load plugins"}) +{ +} + +act_list_fields::~act_list_fields() +{ +} + +const std::string &act_list_fields::name() +{ + return m_name; +} + +const std::list &act_list_fields::prerequsites() +{ + return m_prerequsites; +} + +runnable_action::run_result act_list_fields::run() +{ + run_result ret = {true, "", true}; + + if(app().options().list_fields) + { + if(app().options().list_source_fields != "" && + !app().state().engine->is_source_valid(app().options().list_source_fields)) + { + ret.success = false; + ret.errstr = "Value for --list must be a valid source type"; + ret.proceed = false; + return ret; + } + app().state().engine->list_fields(app().options().list_source_fields, app().options().verbose, app().options().names_only); + + ret.proceed = false; + } + + return ret; +} + +}; // namespace application +}; // namespace falco + diff --git a/userspace/falco/app_actions/list_fields.h b/userspace/falco/app_actions/list_fields.h new file mode 100644 index 00000000..97df2f42 --- /dev/null +++ b/userspace/falco/app_actions/list_fields.h @@ -0,0 +1,45 @@ +/* +Copyright (C) 2022 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#pragma once + +#include + +#include "app_action.h" + +namespace falco { +namespace app { + +class act_list_fields : public action { +public: + act_list_fields(application &app); + virtual ~act_list_fields(); + + const std::string &name() override; + + const std::list &prerequsites() override; + + run_result run() override; + +private: + std::string m_name; + std::list m_prerequsites; +}; + +}; // namespace application +}; // namespace falco + diff --git a/userspace/falco/app_actions/load_config.cpp b/userspace/falco/app_actions/load_config.cpp index 33bce3c1..22f46ada 100644 --- a/userspace/falco/app_actions/load_config.cpp +++ b/userspace/falco/app_actions/load_config.cpp @@ -63,6 +63,8 @@ runnable_action::run_result act_load_config::run() #endif } + app().state().config->m_buffered_outputs = !app().options().unbuffered_outputs; + return ret; } diff --git a/userspace/falco/app_actions/load_rules_files.cpp b/userspace/falco/app_actions/load_rules_files.cpp new file mode 100644 index 00000000..4a5a7423 --- /dev/null +++ b/userspace/falco/app_actions/load_rules_files.cpp @@ -0,0 +1,200 @@ +/* +Copyright (C) 2022 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "load_rules_files.h" + +namespace falco { +namespace app { + +act_load_rules_files::act_load_rules_files(application &app) + : action(app), m_name("load rules files"), + m_prerequsites({"load plugins"}) +{ +} + +act_load_rules_files::~act_load_rules_files() +{ +} + +const std::string &act_load_rules_files::name() +{ + return m_name; +} + +const std::list &act_load_rules_files::prerequsites() +{ + return m_prerequsites; +} + +runnable_action::run_result act_load_rules_files::run() +{ + run_result ret = {true, "", true}; + + string all_rules; + + if (app().options().rules_filenames.size()) + { + app().state().config->m_rules_filenames = app().options().rules_filenames; + } + + if(app().state().config->m_rules_filenames.size() == 0) + { + ret.success = false; + ret.errstr = "You must specify at least one rules file/directory via -r or a rules_file entry in falco.yaml"; + ret.proceed = false; + return ret; + } + + falco_logger::log(LOG_DEBUG, "Configured rules filenames:\n"); + for (auto filename : app().state().config->m_rules_filenames) + { + falco_logger::log(LOG_DEBUG, string(" ") + filename + "\n"); + } + + for (auto filename : app().state().config->m_rules_filenames) + { + falco_logger::log(LOG_INFO, "Loading rules from file " + filename + ":\n"); + uint64_t required_engine_version; + + try { + app().state().engine->load_rules_file(filename, app().options().verbose, app().options().all_events, required_engine_version); + } + catch(falco_exception &e) + { + ret.success = false; + ret.errstr = string("Could not load rules file ") + filename + ": " + e.what(); + ret.proceed = false; + return ret; + } + app().state().required_engine_versions[filename] = required_engine_version; + } + + // Ensure that all plugins are compatible with the loaded set of rules + for(auto &info : app().state().plugin_infos) + { + std::string required_version; + + if(!app().state().engine->is_plugin_compatible(info.name, info.plugin_version.as_string(), required_version)) + { + ret.success = false; + ret.errstr = std::string("Plugin ") + info.name + " version " + info.plugin_version.as_string() + " not compatible with required plugin version " + required_version; + ret.proceed = false; + } + } + + for (auto substring : app().options().disabled_rule_substrings) + { + falco_logger::log(LOG_INFO, "Disabling rules matching substring: " + substring + "\n"); + app().state().engine->enable_rule(substring, false); + } + + if(app().options().disabled_rule_tags.size() > 0) + { + for(auto &tag : app().options().disabled_rule_tags) + { + falco_logger::log(LOG_INFO, "Disabling rules with tag: " + tag + "\n"); + } + app().state().engine->enable_rule_by_tag(app().options().disabled_rule_tags, false); + } + + if(app().options().enabled_rule_tags.size() > 0) + { + // Since we only want to enable specific + // rules, first disable all rules. + app().state().engine->enable_rule(all_rules, false); + for(auto &tag : app().options().enabled_rule_tags) + { + falco_logger::log(LOG_INFO, "Enabling rules with tag: " + tag + "\n"); + } + app().state().engine->enable_rule_by_tag(app().options().enabled_rule_tags, true); + } + + if(!app().options().all_events) + { + // For syscalls, see if any event types used by the + // loaded rules are ones with the EF_DROP_SIMPLE_CONS + // label. + check_for_ignored_events(); + } + + if (app().options().describe_all_rules) + { + app().state().engine->describe_rule(NULL); + ret.proceed = false; + return ret; + } + + if (!app().options().describe_rule.empty()) + { + app().state().engine->describe_rule(&(app().options().describe_rule)); + ret.proceed = false; + return ret; + } + + return ret; +} + +void act_load_rules_files::check_for_ignored_events() +{ + std::set evttypes; + sinsp_evttables* einfo = app().state().inspector->get_event_info_tables(); + const struct ppm_event_info* etable = einfo->m_event_info; + + app().state().engine->evttypes_for_ruleset(application::s_syscall_source, evttypes); + + // Save event names so we don't warn for both the enter and exit event. + std::set warn_event_names; + + for(auto evtnum : evttypes) + { + if(evtnum == PPME_GENERIC_E || evtnum == PPME_GENERIC_X) + { + continue; + } + + if(!sinsp::simple_consumer_consider_evtnum(evtnum)) + { + std::string name = etable[evtnum].name; + if(warn_event_names.find(name) == warn_event_names.end()) + { + warn_event_names.insert(name); + } + } + } + + // Print a single warning with the list of ignored events + if (!warn_event_names.empty()) + { + std::string skipped_events; + bool first = true; + for (const auto& evtname : warn_event_names) + { + if (first) + { + skipped_events += evtname; + first = false; + } else + { + skipped_events += "," + evtname; + } + } + fprintf(stderr,"Rules match ignored syscall: warning (ignored-evttype):\n loaded rules match the following events: %s;\n but these events are not returned unless running falco with -A\n", skipped_events.c_str()); + } +} + +}; // namespace application +}; // namespace falco + diff --git a/userspace/falco/app_actions/load_rules_files.h b/userspace/falco/app_actions/load_rules_files.h new file mode 100644 index 00000000..41449db8 --- /dev/null +++ b/userspace/falco/app_actions/load_rules_files.h @@ -0,0 +1,47 @@ +/* +Copyright (C) 2022 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#pragma once + +#include + +#include "app_action.h" + +namespace falco { +namespace app { + +class act_load_rules_files : public action { +public: + act_load_rules_files(application &app); + virtual ~act_load_rules_files(); + + const std::string &name() override; + + const std::list &prerequsites() override; + + run_result run() override; + +private: + void check_for_ignored_events(); + + std::string m_name; + std::list m_prerequsites; +}; + +}; // namespace application +}; // namespace falco + diff --git a/userspace/falco/app_actions/print_support.cpp b/userspace/falco/app_actions/print_support.cpp new file mode 100644 index 00000000..2cfe1833 --- /dev/null +++ b/userspace/falco/app_actions/print_support.cpp @@ -0,0 +1,100 @@ +/* +Copyright (C) 2022 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +#include "falco_engine_version.h" +#include "print_support.h" + +namespace falco { +namespace app { + +act_print_support::act_print_support(application &app) + : action(app), m_name("print support"), + m_prerequsites({"load rules files"}) +{ +} + +act_print_support::~act_print_support() +{ +} + +const std::string &act_print_support::name() +{ + return m_name; +} + +const std::list &act_print_support::prerequsites() +{ + return m_prerequsites; +} + +runnable_action::run_result act_print_support::run() +{ + run_result ret = {true, "", true}; + + if(app().options().print_support) + { + nlohmann::json support; + struct utsname sysinfo; + std::string cmdline; + + if(uname(&sysinfo) != 0) + { + ret.success = false; + ret.errstr = string("Could not uname() to find system info: ") + strerror(errno); + ret.proceed = false; + return ret; + } + + support["version"] = FALCO_VERSION; + support["system_info"]["sysname"] = sysinfo.sysname; + support["system_info"]["nodename"] = sysinfo.nodename; + support["system_info"]["release"] = sysinfo.release; + support["system_info"]["version"] = sysinfo.version; + support["system_info"]["machine"] = sysinfo.machine; + support["cmdline"] = app().state().cmdline; + support["engine_info"]["engine_version"] = FALCO_ENGINE_VERSION; + support["config"] = read_file(app().options().conf_filename); + support["rules_files"] = nlohmann::json::array(); + for(auto filename : app().state().config->m_rules_filenames) + { + nlohmann::json finfo; + finfo["name"] = filename; + nlohmann::json variant; + variant["required_engine_version"] = app().state().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()); + } + + return ret; +} + +std::string act_print_support::read_file(std::string &filename) +{ + std::ifstream t(filename); + std::string str((std::istreambuf_iterator(t)), + std::istreambuf_iterator()); + + return str; +} + +}; // namespace application +}; // namespace falco + diff --git a/userspace/falco/app_actions/print_support.h b/userspace/falco/app_actions/print_support.h new file mode 100644 index 00000000..e24b343e --- /dev/null +++ b/userspace/falco/app_actions/print_support.h @@ -0,0 +1,46 @@ +/* +Copyright (C) 2022 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#pragma once + +#include + +#include "app_action.h" + +namespace falco { +namespace app { + +class act_print_support : public action { +public: + act_print_support(application &app); + virtual ~act_print_support(); + + const std::string &name() override; + + const std::list &prerequsites() override; + + run_result run() override; + +private: + std::string read_file(std::string &filename); + std::string m_name; + std::list m_prerequsites; +}; + +}; // namespace application +}; // namespace falco + diff --git a/userspace/falco/app_actions/start_webserver.cpp b/userspace/falco/app_actions/start_webserver.cpp new file mode 100644 index 00000000..0bece460 --- /dev/null +++ b/userspace/falco/app_actions/start_webserver.cpp @@ -0,0 +1,68 @@ +/* +Copyright (C) 2022 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "start_webserver.h" + +#ifndef MINIMAL_BUILD + +namespace falco { +namespace app { + +act_start_webserver::act_start_webserver(application &app) + : action(app), m_name("start webserver"), + m_prerequsites({"init outputs"}) +{ +} + +act_start_webserver::~act_start_webserver() +{ +} + +const std::string &act_start_webserver::name() +{ + return m_name; +} + +const std::list &act_start_webserver::prerequsites() +{ + return m_prerequsites; +} + +runnable_action::run_result act_start_webserver::run() +{ + run_result ret = {true, "", true}; + + if(app().options().trace_filename.empty() && app().state().config->m_webserver_enabled && app().state().enabled_sources.find(application::s_k8s_audit_source) != app().state().enabled_sources.end()) + { + std::string ssl_option = (app().state().config->m_webserver_ssl_enabled ? " (SSL)" : ""); + falco_logger::log(LOG_INFO, "Starting internal webserver, listening on port " + to_string(app().state().config->m_webserver_listen_port) + ssl_option + "\n"); + m_webserver.init(app().state().config, app().state().engine, app().state().outputs); + m_webserver.start(); + } + + return ret; +} + +void act_start_webserver::deinit() +{ + m_webserver.stop(); +} + +#endif + +}; // namespace application +}; // namespace falco + diff --git a/userspace/falco/app_actions/start_webserver.h b/userspace/falco/app_actions/start_webserver.h new file mode 100644 index 00000000..68fcf7e1 --- /dev/null +++ b/userspace/falco/app_actions/start_webserver.h @@ -0,0 +1,49 @@ +/* +Copyright (C) 2022 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#pragma once + +#include + +#include "app_action.h" +#include "webserver.h" + +namespace falco { +namespace app { + +class act_start_webserver : public action { +public: + act_start_webserver(application &app); + virtual ~act_start_webserver(); + + const std::string &name() override; + + const std::list &prerequsites() override; + + run_result run() override; + + void deinit() override; + +private: + falco_webserver m_webserver; + std::string m_name; + std::list m_prerequsites; +}; + +}; // namespace application +}; // namespace falco + diff --git a/userspace/falco/app_actions/validate_rules_files.cpp b/userspace/falco/app_actions/validate_rules_files.cpp new file mode 100644 index 00000000..e3d20006 --- /dev/null +++ b/userspace/falco/app_actions/validate_rules_files.cpp @@ -0,0 +1,77 @@ +/* +Copyright (C) 2022 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "validate_rules_files.h" + +namespace falco { +namespace app { + +act_validate_rules_files::act_validate_rules_files(application &app) + : action(app), m_name("validate rules files"), + m_prerequsites({"load plugins"}) +{ +} + +act_validate_rules_files::~act_validate_rules_files() +{ +} + +const std::string &act_validate_rules_files::name() +{ + return m_name; +} + +const std::list &act_validate_rules_files::prerequsites() +{ + return m_prerequsites; +} + +runnable_action::run_result act_validate_rules_files::run() +{ + run_result ret = {true, "", true}; + + if(app().options().validate_rules_filenames.size() > 0) + { + falco_logger::log(LOG_INFO, "Validating rules file(s):\n"); + for(auto file : app().options().validate_rules_filenames) + { + falco_logger::log(LOG_INFO, " " + file + "\n"); + } + for(auto file : app().options().validate_rules_filenames) + { + // Only include the prefix if there is more than one file + std::string prefix = (app().options().validate_rules_filenames.size() > 1 ? file + ": " : ""); + try { + app().state().engine->load_rules_file(file, app().options().verbose, app().options().all_events); + } + catch(falco_exception &e) + { + ret.success = false; + ret.errstr = prefix + e.what(); + ret.proceed = false; + return ret; + } + printf("%sOk\n", prefix.c_str()); + } + falco_logger::log(LOG_INFO, "Ok\n"); + } + + return ret; +} + +}; // namespace application +}; // namespace falco + diff --git a/userspace/falco/app_actions/validate_rules_files.h b/userspace/falco/app_actions/validate_rules_files.h new file mode 100644 index 00000000..e59300ef --- /dev/null +++ b/userspace/falco/app_actions/validate_rules_files.h @@ -0,0 +1,45 @@ +/* +Copyright (C) 2022 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#pragma once + +#include + +#include "app_action.h" + +namespace falco { +namespace app { + +class act_validate_rules_files : public action { +public: + act_validate_rules_files(application &app); + virtual ~act_validate_rules_files(); + + const std::string &name() override; + + const std::list &prerequsites() override; + + run_result run() override; + +private: + std::string m_name; + std::list m_prerequsites; +}; + +}; // namespace application +}; // namespace falco + diff --git a/userspace/falco/defined_app_actions.h b/userspace/falco/defined_app_actions.h index d24d1594..d4e47e03 100644 --- a/userspace/falco/defined_app_actions.h +++ b/userspace/falco/defined_app_actions.h @@ -19,11 +19,16 @@ limitations under the License. #include "app_actions/init_inspector.h" #include "app_actions/init_outputs.h" #include "app_actions/list_plugins.h" +#include "app_actions/list_fields.h" #include "app_actions/load_config.h" #include "app_actions/load_plugins.h" +#include "app_actions/load_rules_files.h" #include "app_actions/print_help.h" #include "app_actions/print_ignored_events.h" +#include "app_actions/print_support.h" #include "app_actions/print_version.h" #include "app_actions/start_grpc_server.h" +#include "app_actions/start_webserver.h" +#include "app_actions/validate_rules_files.h"