From dfe03f603466446b8e1b416d1fadb311dd08fb86 Mon Sep 17 00:00:00 2001 From: Luca Guerra Date: Thu, 12 Sep 2024 08:16:43 +0000 Subject: [PATCH 1/4] update(engine): modify append_output format Signed-off-by: Luca Guerra --- falco.yaml | 26 +++--- unit_tests/engine/test_extra_output.cpp | 21 +++-- .../test_configuration_output_options.cpp | 44 ++++++---- userspace/engine/falco_engine.cpp | 12 +-- userspace/engine/falco_engine.h | 6 +- userspace/engine/rule_loader.h | 4 +- userspace/engine/rule_loader_compiler.cpp | 27 +++++- .../falco/app/actions/init_falco_engine.cpp | 16 ++-- userspace/falco/configuration.h | 83 +++++++------------ 9 files changed, 129 insertions(+), 110 deletions(-) diff --git a/falco.yaml b/falco.yaml index 4e243992fec..e052a441109 100644 --- a/falco.yaml +++ b/falco.yaml @@ -595,24 +595,30 @@ outputs_queue: # This allows you to add custom fields that can help you filter your Falco events without # polluting the message text. # -# Each append_output entry has optional fields (ANDed together) to filter events: +# Each append_output entry has an optional `match` map which specifies which rules will be +# affected. +# `match`: # `rule`: append output only to a specific rule # `source`: append output only to a specific source -# `tag`: append output only to a specific tag -# If none of the above are specified output is appended to all events, if more than one is -# specified output will be appended to events that match all conditions. +# `tags`: append output only to rules that have all of the specified tags +# If none of the above are specified (or `match` is omitted) +# output is appended to all events. +# If more than one match condition is specified output will be appended to events +# that match all conditions. # And several options to add output: -# `format`: add output to the Falco message -# `fields`: add new fields to the JSON output and structured output, which will not +# `extra_output`: add output to the Falco message +# `extra_fields`: add new fields to the JSON output and structured output, which will not # affect the regular Falco message in any way. These can be specified as a # custom name with a custom format or as any supported field # (see: https://falco.org/docs/reference/rules/supported-fields/) # # Example: -# -# - source: syscall -# format: "on CPU %evt.cpu" -# fields: +# +# append_output: +# - match: +# source: syscall +# extra_output: "on CPU %evt.cpu" +# extra_fields: # - home_directory: "${HOME}" # - evt.hostname # diff --git a/unit_tests/engine/test_extra_output.cpp b/unit_tests/engine/test_extra_output.cpp index 845d22d160c..a2480a6a706 100644 --- a/unit_tests/engine/test_extra_output.cpp +++ b/unit_tests/engine/test_extra_output.cpp @@ -29,7 +29,7 @@ TEST_F(test_falco_engine, extra_format_all) priority: INFO )END"; - m_engine->add_extra_output_format("evt.type=%evt.type", "", "", "", false); + m_engine->add_extra_output_format("evt.type=%evt.type", "", {}, "", false); ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; EXPECT_EQ(get_compiled_rule_output("legit_rule"),"user=%user.name command=%proc.cmdline file=%fd.name evt.type=%evt.type"); @@ -51,7 +51,7 @@ TEST_F(test_falco_engine, extra_format_by_rule) priority: INFO )END"; - m_engine->add_extra_output_format("evt.type=%evt.type", "", "", "legit_rule", false); + m_engine->add_extra_output_format("evt.type=%evt.type", "", {}, "legit_rule", false); ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; EXPECT_EQ(get_compiled_rule_output("legit_rule"),"out 1 evt.type=%evt.type"); @@ -74,15 +74,24 @@ TEST_F(test_falco_engine, extra_format_by_tag_rule) output: out 2 priority: INFO tags: [tag1] + +- rule: a_third_rule + desc: legit rule description + condition: evt.type=open + output: out 3 + priority: INFO + tags: [tag1, tag2] )END"; - m_engine->add_extra_output_format("extra 1", "", "tag1", "", false); - m_engine->add_extra_output_format("extra 2", "", "", "another_rule", false); + m_engine->add_extra_output_format("extra 1", "", {"tag1"}, "", false); + m_engine->add_extra_output_format("extra 2", "", {}, "another_rule", false); + m_engine->add_extra_output_format("extra 3", "", {"tag1", "tag2"}, "", false); ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; EXPECT_EQ(get_compiled_rule_output("legit_rule"),"out 1 extra 1"); EXPECT_EQ(get_compiled_rule_output("another_rule"),"out 2 extra 1 extra 2"); + EXPECT_EQ(get_compiled_rule_output("a_third_rule"),"out 3 extra 1 extra 3"); } TEST_F(test_falco_engine, extra_format_replace_container_info) @@ -103,7 +112,7 @@ TEST_F(test_falco_engine, extra_format_replace_container_info) tags: [tag1] )END"; - m_engine->add_extra_output_format("extra 1", "", "", "", true); + m_engine->add_extra_output_format("extra 1", "", {}, "", true); ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; @@ -141,7 +150,7 @@ TEST_F(test_falco_engine, extra_fields_all) std::unordered_map extra_formatted_fields = {{"my_field", "hello %evt.num"}}; for (auto const& f : extra_formatted_fields) { - m_engine->add_extra_output_formatted_field(f.first, f.second, "", "", ""); + m_engine->add_extra_output_formatted_field(f.first, f.second, "", {}, ""); } ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; diff --git a/unit_tests/falco/test_configuration_output_options.cpp b/unit_tests/falco/test_configuration_output_options.cpp index 1d10decc173..d579bc7c43e 100644 --- a/unit_tests/falco/test_configuration_output_options.cpp +++ b/unit_tests/falco/test_configuration_output_options.cpp @@ -23,20 +23,24 @@ TEST(ConfigurationRuleOutputOptions, parse_yaml) falco_configuration falco_config; ASSERT_NO_THROW(falco_config.init_from_content(R"( append_output: - - source: syscall - tag: persistence - rule: some rule name - format: "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]" - - - tag: persistence - fields: + - match: + source: syscall + tags: ["persistence"] + rule: some rule name + + extra_output: "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]" + + - match: + tags: ["persistence", "execution"] + extra_fields: - proc.aname[2]: "%proc.aname[2]" - proc.aname[3]: "%proc.aname[3]" - proc.aname[4]: "%proc.aname[4]" - format: "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]" + extra_output: "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]" - - source: k8s_audit - fields: + - match: + source: k8s_audit + extra_fields: - ka.verb - static_field: "static content" @@ -45,12 +49,15 @@ TEST(ConfigurationRuleOutputOptions, parse_yaml) EXPECT_EQ(falco_config.m_append_output.size(), 3); EXPECT_EQ(falco_config.m_append_output[0].m_source, "syscall"); - EXPECT_EQ(falco_config.m_append_output[0].m_tag, "persistence"); + EXPECT_EQ(falco_config.m_append_output[0].m_tags.size(), 1); + EXPECT_EQ(falco_config.m_append_output[0].m_tags.count("persistence"), 1); EXPECT_EQ(falco_config.m_append_output[0].m_rule, "some rule name"); EXPECT_EQ(falco_config.m_append_output[0].m_formatted_fields.size(), 0); EXPECT_EQ(falco_config.m_append_output[0].m_format, "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); - EXPECT_EQ(falco_config.m_append_output[1].m_tag, "persistence"); + EXPECT_EQ(falco_config.m_append_output[1].m_tags.size(), 2); + EXPECT_EQ(falco_config.m_append_output[1].m_tags.count("persistence"), 1); + EXPECT_EQ(falco_config.m_append_output[1].m_tags.count("execution"), 1); EXPECT_EQ(falco_config.m_append_output[1].m_format, "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields.size(), 3); @@ -73,19 +80,22 @@ TEST(ConfigurationRuleOutputOptions, cli_options) ASSERT_NO_THROW(falco_config.init_from_content("", std::vector{ - R"(append_output[]={"source": "syscall", "tag": "persistence", "rule": "some rule name", "format": "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"})", - R"(append_output[]={"tag": "persistence", "fields": [{"proc.aname[2]": "%proc.aname[2]"}, {"proc.aname[3]": "%proc.aname[3]"}, {"proc.aname[4]": "%proc.aname[4]"}], "format": "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"})", - R"(append_output[]={"source": "k8s_audit", "fields": ["ka.verb", {"static_field": "static content"}]})"})); + R"(append_output[]={"match": {"source": "syscall", "tags": ["persistence"], "rule": "some rule name"}, "extra_output": "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"})", + R"(append_output[]={"match": {"tags": ["persistence", "execution"]}, "extra_fields": [{"proc.aname[2]": "%proc.aname[2]"}, {"proc.aname[3]": "%proc.aname[3]"}, {"proc.aname[4]": "%proc.aname[4]"}], "extra_output": "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"})", + R"(append_output[]={"match": {"source": "k8s_audit"}, "extra_fields": ["ka.verb", {"static_field": "static content"}]})"})); EXPECT_EQ(falco_config.m_append_output.size(), 3); EXPECT_EQ(falco_config.m_append_output[0].m_source, "syscall"); - EXPECT_EQ(falco_config.m_append_output[0].m_tag, "persistence"); + EXPECT_EQ(falco_config.m_append_output[0].m_tags.size(), 1); + EXPECT_EQ(falco_config.m_append_output[0].m_tags.count("persistence"), 1); EXPECT_EQ(falco_config.m_append_output[0].m_rule, "some rule name"); EXPECT_EQ(falco_config.m_append_output[0].m_formatted_fields.size(), 0); EXPECT_EQ(falco_config.m_append_output[0].m_format, "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); - EXPECT_EQ(falco_config.m_append_output[1].m_tag, "persistence"); + EXPECT_EQ(falco_config.m_append_output[1].m_tags.size(), 2); + EXPECT_EQ(falco_config.m_append_output[1].m_tags.count("persistence"), 1); + EXPECT_EQ(falco_config.m_append_output[1].m_tags.count("execution"), 1); EXPECT_EQ(falco_config.m_append_output[1].m_format, "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields.size(), 3); diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index f7f79268988..5581604db36 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -1103,34 +1103,34 @@ void falco_engine::set_sampling_multiplier(double sampling_multiplier) void falco_engine::add_extra_output_format( const std::string &format, const std::string &source, - const std::string &tag, + const std::set &tags, const std::string &rule, bool replace_container_info ) { - m_extra_output_format.push_back({format, source, tag, rule, replace_container_info}); + m_extra_output_format.push_back({format, source, tags, rule, replace_container_info}); } void falco_engine::add_extra_output_formatted_field( const std::string &key, const std::string &format, const std::string &source, - const std::string &tag, + const std::set &tags, const std::string &rule ) { - m_extra_output_fields.push_back({key, format, source, tag, rule, false}); + m_extra_output_fields.push_back({key, format, source, tags, rule, false}); } void falco_engine::add_extra_output_raw_field( const std::string &key, const std::string &source, - const std::string &tag, + const std::set &tags, const std::string &rule ) { std::string format = "%" + key; - m_extra_output_fields.push_back({key, format, source, tag, rule, true}); + m_extra_output_fields.push_back({key, format, source, tags, rule, true}); } inline bool falco_engine::should_drop_evt() const diff --git a/userspace/engine/falco_engine.h b/userspace/engine/falco_engine.h index 17171c4c436..d4d709821ee 100644 --- a/userspace/engine/falco_engine.h +++ b/userspace/engine/falco_engine.h @@ -186,7 +186,7 @@ class falco_engine void add_extra_output_format( const std::string &format, const std::string &source, - const std::string &tag, + const std::set &tags, const std::string &rule, bool replace_container_info ); @@ -200,14 +200,14 @@ class falco_engine const std::string &key, const std::string &format, const std::string &source, - const std::string &tag, + const std::set &tags, const std::string &rule ); void add_extra_output_raw_field( const std::string &key, const std::string &source, - const std::string &tag, + const std::set &tags, const std::string &rule ); diff --git a/userspace/engine/rule_loader.h b/userspace/engine/rule_loader.h index 25f047d4099..5c45d78b40e 100644 --- a/userspace/engine/rule_loader.h +++ b/userspace/engine/rule_loader.h @@ -270,7 +270,7 @@ namespace rule_loader { std::string m_format; std::string m_source; - std::string m_tag; + std::set m_tags; std::string m_rule; bool m_replace_container_info; }; @@ -280,7 +280,7 @@ namespace rule_loader std::string m_key; std::string m_format; std::string m_source; - std::string m_tag; + std::set m_tags; std::string m_rule; bool m_raw; }; diff --git a/userspace/engine/rule_loader_compiler.cpp b/userspace/engine/rule_loader_compiler.cpp index 0996045e30a..a370176d434 100644 --- a/userspace/engine/rule_loader_compiler.cpp +++ b/userspace/engine/rule_loader_compiler.cpp @@ -19,6 +19,7 @@ limitations under the License. #include #include #include +#include #include "rule_loader_compiler.h" #include "filter_warning_resolver.h" @@ -501,9 +502,18 @@ void rule_loader::compiler::compile_rule_infos( continue; } - if (extra.m_tag != "" && r.tags.count(extra.m_tag) == 0) + if (extra.m_tags.size() != 0) { - continue; + std::set intersect; + + set_intersection(extra.m_tags.begin(), extra.m_tags.end(), + r.tags.begin(), r.tags.end(), + inserter(intersect, intersect.begin())); + + if (intersect.size() != extra.m_tags.size()) + { + continue; + } } if (extra.m_rule != "" && r.name != extra.m_rule) @@ -541,9 +551,18 @@ void rule_loader::compiler::compile_rule_infos( continue; } - if (extra.m_tag != "" && r.tags.count(extra.m_tag) == 0) + if (extra.m_tags.size() != 0) { - continue; + std::set intersect; + + set_intersection(extra.m_tags.begin(), extra.m_tags.end(), + r.tags.begin(), r.tags.end(), + inserter(intersect, intersect.begin())); + + if (intersect.size() != extra.m_tags.size()) + { + continue; + } } if (extra.m_rule != "" && r.name != extra.m_rule) diff --git a/userspace/falco/app/actions/init_falco_engine.cpp b/userspace/falco/app/actions/init_falco_engine.cpp index 58286df658a..483f827ca37 100644 --- a/userspace/falco/app/actions/init_falco_engine.cpp +++ b/userspace/falco/app/actions/init_falco_engine.cpp @@ -28,17 +28,17 @@ void configure_output_format(falco::app::state& s) { if (eo.m_format != "") { - s.engine->add_extra_output_format(eo.m_format, eo.m_source, eo.m_tag, eo.m_rule, false); + s.engine->add_extra_output_format(eo.m_format, eo.m_source, eo.m_tags, eo.m_rule, false); } for (auto const& ff : eo.m_formatted_fields) { - s.engine->add_extra_output_formatted_field(ff.first, ff.second, eo.m_source, eo.m_tag, eo.m_rule); + s.engine->add_extra_output_formatted_field(ff.first, ff.second, eo.m_source, eo.m_tags, eo.m_rule); } for (auto const& rf : eo.m_raw_fields) { - s.engine->add_extra_output_raw_field(rf, eo.m_source, eo.m_tag, eo.m_rule); + s.engine->add_extra_output_raw_field(rf, eo.m_source, eo.m_tags, eo.m_rule); } } @@ -49,23 +49,23 @@ void configure_output_format(falco::app::state& s) if(s.options.print_additional == "c" || s.options.print_additional == "container") { - s.engine->add_extra_output_format(container_info, falco_common::syscall_source, "", "", true); + s.engine->add_extra_output_format(container_info, falco_common::syscall_source, {}, "", true); } else if(s.options.print_additional == "cg" || s.options.print_additional == "container-gvisor") { - s.engine->add_extra_output_format(gvisor_info + " " + container_info, falco_common::syscall_source, "", "", true); + s.engine->add_extra_output_format(gvisor_info + " " + container_info, falco_common::syscall_source, {}, "", true); } else if(s.options.print_additional == "k" || s.options.print_additional == "kubernetes") { - s.engine->add_extra_output_format(container_info + " " + k8s_info, falco_common::syscall_source, "", "", true); + s.engine->add_extra_output_format(container_info + " " + k8s_info, falco_common::syscall_source, {}, "", true); } else if(s.options.print_additional == "kg" || s.options.print_additional == "kubernetes-gvisor") { - s.engine->add_extra_output_format(gvisor_info + " " + container_info + " " + k8s_info, falco_common::syscall_source, "", "", true); + s.engine->add_extra_output_format(gvisor_info + " " + container_info + " " + k8s_info, falco_common::syscall_source, {}, "", true); } else if(!s.options.print_additional.empty()) { - s.engine->add_extra_output_format(s.options.print_additional, "", "", "", false); + s.engine->add_extra_output_format(s.options.print_additional, "", {}, "", false); } } diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 55110c609c9..2a3b763ea7c 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -109,7 +109,7 @@ class falco_configuration struct append_output_config { std::string m_source; - std::string m_tag; + std::set m_tags; std::string m_rule; std::string m_format; std::unordered_map m_formatted_fields; @@ -232,78 +232,53 @@ class falco_configuration namespace YAML { template<> struct convert { - static Node encode(const falco_configuration::append_output_config & rhs) { - Node node; - - if(rhs.m_source != "") - { - node["source"] = rhs.m_source; - } - - if(rhs.m_rule != "") - { - node["rule"] = rhs.m_rule; - } - - if(rhs.m_tag != "") - { - node["tag"] = rhs.m_tag; - } - - if(rhs.m_format != "") - { - node["format"] = rhs.m_format; - } - - for(auto const& field : rhs.m_formatted_fields) - { - YAML::Node field_node; - field_node[field.first] = field.second; - node["fields"].push_back(field_node); - } - - for(auto const& field : rhs.m_raw_fields) - { - node["fields"].push_back(field); - } - - return node; - } - static bool decode(const Node& node, falco_configuration::append_output_config & rhs) { if(!node.IsMap()) { return false; } - if(node["source"]) + if(node["match"]) { - rhs.m_source = node["source"].as(); - } + auto& match = node["match"]; - if(node["tag"]) - { - rhs.m_tag = node["tag"].as(); - } + if(match["source"]) + { + rhs.m_source = match["source"].as(); + } - if(node["rule"]) - { - rhs.m_rule = node["rule"].as(); + if(match["tags"] && match["tags"].IsSequence()) + { + for(auto& tag : match["tags"]) + { + if (!tag.IsScalar()) + { + return false; + } + + rhs.m_tags.insert(tag.as()); + } + } + + if(match["rule"]) + { + rhs.m_rule = match["rule"].as(); + } } - if(node["format"]) + if(node["extra_output"]) { - rhs.m_format = node["format"].as(); + rhs.m_format = node["extra_output"].as(); } - if(node["fields"]) + if(node["extra_fields"]) { - if(!node["fields"].IsSequence()) + if(!node["extra_fields"].IsSequence()) { return false; } - for(auto& field_definition : node["fields"]) + for(auto& field_definition : node["extra_fields"]) { if(field_definition.IsMap() && field_definition.size() == 1) { From 02308b332e00e68615e32d6c3e7a9bffa14eb3f0 Mon Sep 17 00:00:00 2001 From: Luca Guerra Date: Fri, 13 Sep 2024 11:26:21 +0000 Subject: [PATCH 2/4] update(falco): update json schema Signed-off-by: Luca Guerra --- userspace/falco/configuration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 01bca7664d8..2ecb23606d1 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -54,7 +54,7 @@ static re2::RE2 ip_address_re("((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]| // Just use any available online tool, eg: https://jsonformatter.org/json-minify // to format the json, add the new fields, and then minify it again. static const std::string config_schema_string = R"( -{"$schema":"http://json-schema.org/draft-06/schema#","$ref":"#/definitions/FalcoConfig","definitions":{"FalcoConfig":{"type":"object","additionalProperties":false,"properties":{"append_output":{"type":"array","items":{"$ref":"#/definitions/AppendOutput"}},"config_files":{"type":"array","items":{"type":"string"}},"watch_config_files":{"type":"boolean"},"rules_files":{"type":"array","items":{"type":"string"}},"rule_files":{"type":"array","items":{"type":"string"}},"rules":{"type":"array","items":{"$ref":"#/definitions/Rule"}},"engine":{"$ref":"#/definitions/Engine"},"load_plugins":{"type":"array","items":{"type":"string"}},"plugins":{"type":"array","items":{"$ref":"#/definitions/Plugin"}},"time_format_iso_8601":{"type":"boolean"},"priority":{"type":"string"},"json_output":{"type":"boolean"},"json_include_output_property":{"type":"boolean"},"json_include_message_property":{"type":"boolean"},"json_include_tags_property":{"type":"boolean"},"buffered_outputs":{"type":"boolean"},"rule_matching":{"type":"string"},"outputs_queue":{"$ref":"#/definitions/OutputsQueue"},"stdout_output":{"$ref":"#/definitions/Output"},"syslog_output":{"$ref":"#/definitions/Output"},"file_output":{"$ref":"#/definitions/FileOutput"},"http_output":{"$ref":"#/definitions/HTTPOutput"},"program_output":{"$ref":"#/definitions/ProgramOutput"},"grpc_output":{"$ref":"#/definitions/Output"},"grpc":{"$ref":"#/definitions/Grpc"},"webserver":{"$ref":"#/definitions/Webserver"},"log_stderr":{"type":"boolean"},"log_syslog":{"type":"boolean"},"log_level":{"type":"string"},"libs_logger":{"$ref":"#/definitions/LibsLogger"},"output_timeout":{"type":"integer"},"syscall_event_timeouts":{"$ref":"#/definitions/SyscallEventTimeouts"},"syscall_event_drops":{"$ref":"#/definitions/SyscallEventDrops"},"metrics":{"$ref":"#/definitions/Metrics"},"base_syscalls":{"$ref":"#/definitions/BaseSyscalls"},"falco_libs":{"$ref":"#/definitions/FalcoLibs"},"container_engines":{"type":"object","additionalProperties":false,"properties":{"docker":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"cri":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"sockets":{"type":"array","items":{"type":"string"}},"disable_async":{"type":"boolean"}}},"podman":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"lxc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"libvirt_lxc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"bpm":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}}}}},"title":"FalcoConfig"},"AppendOutput":{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string"},"tag":{"type":"string"},"rule":{"type":"string"},"format":{"type":"string"},"fields":{"type":"array","items":{"anyOf":[{"type":"object","additionalProperties":{"type":"string"}},{"type":"string"}]}}}},"BaseSyscalls":{"type":"object","additionalProperties":false,"properties":{"custom_set":{"type":"array","items":{"type":"string"}},"repair":{"type":"boolean"}},"minProperties":1,"title":"BaseSyscalls"},"Engine":{"type":"object","additionalProperties":false,"properties":{"kind":{"type":"string"},"kmod":{"$ref":"#/definitions/Kmod"},"ebpf":{"$ref":"#/definitions/Ebpf"},"modern_ebpf":{"$ref":"#/definitions/ModernEbpf"},"replay":{"$ref":"#/definitions/Replay"},"gvisor":{"$ref":"#/definitions/Gvisor"}},"required":["kind"],"title":"Engine"},"Ebpf":{"type":"object","additionalProperties":false,"properties":{"probe":{"type":"string"},"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"required":["probe"],"title":"Ebpf"},"Gvisor":{"type":"object","additionalProperties":false,"properties":{"config":{"type":"string"},"root":{"type":"string"}},"required":["config","root"],"title":"Gvisor"},"Kmod":{"type":"object","additionalProperties":false,"properties":{"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"minProperties":1,"title":"Kmod"},"ModernEbpf":{"type":"object","additionalProperties":false,"properties":{"cpus_for_each_buffer":{"type":"integer"},"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"title":"ModernEbpf"},"Replay":{"type":"object","additionalProperties":false,"properties":{"capture_file":{"type":"string"}},"required":["capture_file"],"title":"Replay"},"FalcoLibs":{"type":"object","additionalProperties":false,"properties":{"thread_table_size":{"type":"integer"}},"minProperties":1,"title":"FalcoLibs"},"FileOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"keep_alive":{"type":"boolean"},"filename":{"type":"string"}},"minProperties":1,"title":"FileOutput"},"Grpc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"bind_address":{"type":"string"},"threadiness":{"type":"integer"}},"minProperties":1,"title":"Grpc"},"Output":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}},"minProperties":1,"title":"Output"},"HTTPOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"url":{"type":"string","format":"uri","qt-uri-protocols":["http"]},"user_agent":{"type":"string"},"insecure":{"type":"boolean"},"ca_cert":{"type":"string"},"ca_bundle":{"type":"string"},"ca_path":{"type":"string"},"mtls":{"type":"boolean"},"client_cert":{"type":"string"},"client_key":{"type":"string"},"echo":{"type":"boolean"},"compress_uploads":{"type":"boolean"},"keep_alive":{"type":"boolean"}},"minProperties":1,"title":"HTTPOutput"},"LibsLogger":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"severity":{"type":"string"}},"minProperties":1,"title":"LibsLogger"},"Metrics":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"interval":{"type":"string"},"output_rule":{"type":"boolean"},"output_file":{"type":"string"},"rules_counters_enabled":{"type":"boolean"},"resource_utilization_enabled":{"type":"boolean"},"state_counters_enabled":{"type":"boolean"},"kernel_event_counters_enabled":{"type":"boolean"},"kernel_event_counters_per_cpu_enabled":{"type":"boolean"},"libbpf_stats_enabled":{"type":"boolean"},"plugins_metrics_enabled":{"type":"boolean"},"convert_memory_to_mb":{"type":"boolean"},"include_empty_values":{"type":"boolean"}},"minProperties":1,"title":"Metrics"},"OutputsQueue":{"type":"object","additionalProperties":false,"properties":{"capacity":{"type":"integer"}},"minProperties":1,"title":"OutputsQueue"},"Plugin":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"library_path":{"type":"string"},"init_config":{"type":"string"},"open_params":{"type":"string"}},"required":["library_path","name"],"title":"Plugin"},"ProgramOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"keep_alive":{"type":"boolean"},"program":{"type":"string"}},"required":["program"],"title":"ProgramOutput"},"Rule":{"type":"object","additionalProperties":false,"properties":{"disable":{"$ref":"#/definitions/Able"},"enable":{"$ref":"#/definitions/Able"}},"minProperties":1,"title":"Rule"},"Able":{"type":"object","additionalProperties":false,"properties":{"rule":{"type":"string"},"tag":{"type":"string"}},"minProperties":1,"title":"Able"},"SyscallEventDrops":{"type":"object","additionalProperties":false,"properties":{"threshold":{"type":"number"},"actions":{"type":"array","items":{"type":"string"}},"rate":{"type":"number"},"max_burst":{"type":"integer"},"simulate_drops":{"type":"boolean"}},"minProperties":1,"title":"SyscallEventDrops"},"SyscallEventTimeouts":{"type":"object","additionalProperties":false,"properties":{"max_consecutives":{"type":"integer"}},"minProperties":1,"title":"SyscallEventTimeouts"},"Webserver":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"threadiness":{"type":"integer"},"listen_port":{"type":"integer"},"listen_address":{"type":"string"},"k8s_healthz_endpoint":{"type":"string"},"prometheus_metrics_enabled":{"type":"boolean"},"ssl_enabled":{"type":"boolean"},"ssl_certificate":{"type":"string"}},"minProperties":1,"title":"Webserver"}}} +{"$schema":"http://json-schema.org/draft-06/schema#","$ref":"#/definitions/FalcoConfig","definitions":{"FalcoConfig":{"type":"object","additionalProperties":false,"properties":{"append_output":{"type":"array","items":{"$ref":"#/definitions/AppendOutput"}},"config_files":{"type":"array","items":{"type":"string"}},"watch_config_files":{"type":"boolean"},"rules_files":{"type":"array","items":{"type":"string"}},"rule_files":{"type":"array","items":{"type":"string"}},"rules":{"type":"array","items":{"$ref":"#/definitions/Rule"}},"engine":{"$ref":"#/definitions/Engine"},"load_plugins":{"type":"array","items":{"type":"string"}},"plugins":{"type":"array","items":{"$ref":"#/definitions/Plugin"}},"time_format_iso_8601":{"type":"boolean"},"priority":{"type":"string"},"json_output":{"type":"boolean"},"json_include_output_property":{"type":"boolean"},"json_include_message_property":{"type":"boolean"},"json_include_tags_property":{"type":"boolean"},"buffered_outputs":{"type":"boolean"},"rule_matching":{"type":"string"},"outputs_queue":{"$ref":"#/definitions/OutputsQueue"},"stdout_output":{"$ref":"#/definitions/Output"},"syslog_output":{"$ref":"#/definitions/Output"},"file_output":{"$ref":"#/definitions/FileOutput"},"http_output":{"$ref":"#/definitions/HTTPOutput"},"program_output":{"$ref":"#/definitions/ProgramOutput"},"grpc_output":{"$ref":"#/definitions/Output"},"grpc":{"$ref":"#/definitions/Grpc"},"webserver":{"$ref":"#/definitions/Webserver"},"log_stderr":{"type":"boolean"},"log_syslog":{"type":"boolean"},"log_level":{"type":"string"},"libs_logger":{"$ref":"#/definitions/LibsLogger"},"output_timeout":{"type":"integer"},"syscall_event_timeouts":{"$ref":"#/definitions/SyscallEventTimeouts"},"syscall_event_drops":{"$ref":"#/definitions/SyscallEventDrops"},"metrics":{"$ref":"#/definitions/Metrics"},"base_syscalls":{"$ref":"#/definitions/BaseSyscalls"},"falco_libs":{"$ref":"#/definitions/FalcoLibs"},"container_engines":{"type":"object","additionalProperties":false,"properties":{"docker":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"cri":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"sockets":{"type":"array","items":{"type":"string"}},"disable_async":{"type":"boolean"}}},"podman":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"lxc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"libvirt_lxc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"bpm":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}}}}},"title":"FalcoConfig"},"AppendOutput":{"type":"object","additionalProperties":false,"properties":{"match":{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"rule":{"type":"string"}}},"extra_output":{"type":"string"},"extra_fields":{"type":"array","items":{"anyOf":[{"type":"object","additionalProperties":{"type":"string"}},{"type":"string"}]}}}},"BaseSyscalls":{"type":"object","additionalProperties":false,"properties":{"custom_set":{"type":"array","items":{"type":"string"}},"repair":{"type":"boolean"}},"minProperties":1,"title":"BaseSyscalls"},"Engine":{"type":"object","additionalProperties":false,"properties":{"kind":{"type":"string"},"kmod":{"$ref":"#/definitions/Kmod"},"ebpf":{"$ref":"#/definitions/Ebpf"},"modern_ebpf":{"$ref":"#/definitions/ModernEbpf"},"replay":{"$ref":"#/definitions/Replay"},"gvisor":{"$ref":"#/definitions/Gvisor"}},"required":["kind"],"title":"Engine"},"Ebpf":{"type":"object","additionalProperties":false,"properties":{"probe":{"type":"string"},"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"required":["probe"],"title":"Ebpf"},"Gvisor":{"type":"object","additionalProperties":false,"properties":{"config":{"type":"string"},"root":{"type":"string"}},"required":["config","root"],"title":"Gvisor"},"Kmod":{"type":"object","additionalProperties":false,"properties":{"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"minProperties":1,"title":"Kmod"},"ModernEbpf":{"type":"object","additionalProperties":false,"properties":{"cpus_for_each_buffer":{"type":"integer"},"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"title":"ModernEbpf"},"Replay":{"type":"object","additionalProperties":false,"properties":{"capture_file":{"type":"string"}},"required":["capture_file"],"title":"Replay"},"FalcoLibs":{"type":"object","additionalProperties":false,"properties":{"thread_table_size":{"type":"integer"}},"minProperties":1,"title":"FalcoLibs"},"FileOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"keep_alive":{"type":"boolean"},"filename":{"type":"string"}},"minProperties":1,"title":"FileOutput"},"Grpc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"bind_address":{"type":"string"},"threadiness":{"type":"integer"}},"minProperties":1,"title":"Grpc"},"Output":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}},"minProperties":1,"title":"Output"},"HTTPOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"url":{"type":"string","format":"uri","qt-uri-protocols":["http"]},"user_agent":{"type":"string"},"insecure":{"type":"boolean"},"ca_cert":{"type":"string"},"ca_bundle":{"type":"string"},"ca_path":{"type":"string"},"mtls":{"type":"boolean"},"client_cert":{"type":"string"},"client_key":{"type":"string"},"echo":{"type":"boolean"},"compress_uploads":{"type":"boolean"},"keep_alive":{"type":"boolean"}},"minProperties":1,"title":"HTTPOutput"},"LibsLogger":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"severity":{"type":"string"}},"minProperties":1,"title":"LibsLogger"},"Metrics":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"interval":{"type":"string"},"output_rule":{"type":"boolean"},"output_file":{"type":"string"},"rules_counters_enabled":{"type":"boolean"},"resource_utilization_enabled":{"type":"boolean"},"state_counters_enabled":{"type":"boolean"},"kernel_event_counters_enabled":{"type":"boolean"},"kernel_event_counters_per_cpu_enabled":{"type":"boolean"},"libbpf_stats_enabled":{"type":"boolean"},"plugins_metrics_enabled":{"type":"boolean"},"convert_memory_to_mb":{"type":"boolean"},"include_empty_values":{"type":"boolean"}},"minProperties":1,"title":"Metrics"},"OutputsQueue":{"type":"object","additionalProperties":false,"properties":{"capacity":{"type":"integer"}},"minProperties":1,"title":"OutputsQueue"},"Plugin":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"library_path":{"type":"string"},"init_config":{"type":"string"},"open_params":{"type":"string"}},"required":["library_path","name"],"title":"Plugin"},"ProgramOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"keep_alive":{"type":"boolean"},"program":{"type":"string"}},"required":["program"],"title":"ProgramOutput"},"Rule":{"type":"object","additionalProperties":false,"properties":{"disable":{"$ref":"#/definitions/Able"},"enable":{"$ref":"#/definitions/Able"}},"minProperties":1,"title":"Rule"},"Able":{"type":"object","additionalProperties":false,"properties":{"rule":{"type":"string"},"tag":{"type":"string"}},"minProperties":1,"title":"Able"},"SyscallEventDrops":{"type":"object","additionalProperties":false,"properties":{"threshold":{"type":"number"},"actions":{"type":"array","items":{"type":"string"}},"rate":{"type":"number"},"max_burst":{"type":"integer"},"simulate_drops":{"type":"boolean"}},"minProperties":1,"title":"SyscallEventDrops"},"SyscallEventTimeouts":{"type":"object","additionalProperties":false,"properties":{"max_consecutives":{"type":"integer"}},"minProperties":1,"title":"SyscallEventTimeouts"},"Webserver":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"threadiness":{"type":"integer"},"listen_port":{"type":"integer"},"listen_address":{"type":"string"},"k8s_healthz_endpoint":{"type":"string"},"prometheus_metrics_enabled":{"type":"boolean"},"ssl_enabled":{"type":"boolean"},"ssl_certificate":{"type":"string"}},"minProperties":1,"title":"Webserver"}}} )"; falco_configuration::falco_configuration(): From 8b744aff733e9ba5e26d2aff5950ee6dadb2a288 Mon Sep 17 00:00:00 2001 From: Luca Guerra Date: Fri, 13 Sep 2024 13:26:41 +0000 Subject: [PATCH 3/4] update(falco): use std::include for readability Signed-off-by: Luca Guerra --- userspace/engine/rule_loader_compiler.cpp | 28 +++++------------------ 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/userspace/engine/rule_loader_compiler.cpp b/userspace/engine/rule_loader_compiler.cpp index a370176d434..14ad031b0a5 100644 --- a/userspace/engine/rule_loader_compiler.cpp +++ b/userspace/engine/rule_loader_compiler.cpp @@ -502,18 +502,10 @@ void rule_loader::compiler::compile_rule_infos( continue; } - if (extra.m_tags.size() != 0) + if (!std::includes(r.tags.begin(), r.tags.end(), + extra.m_tags.begin(), extra.m_tags.end())) { - std::set intersect; - - set_intersection(extra.m_tags.begin(), extra.m_tags.end(), - r.tags.begin(), r.tags.end(), - inserter(intersect, intersect.begin())); - - if (intersect.size() != extra.m_tags.size()) - { - continue; - } + continue; } if (extra.m_rule != "" && r.name != extra.m_rule) @@ -551,18 +543,10 @@ void rule_loader::compiler::compile_rule_infos( continue; } - if (extra.m_tags.size() != 0) + if (!std::includes(r.tags.begin(), r.tags.end(), + extra.m_tags.begin(), extra.m_tags.end())) { - std::set intersect; - - set_intersection(extra.m_tags.begin(), extra.m_tags.end(), - r.tags.begin(), r.tags.end(), - inserter(intersect, intersect.begin())); - - if (intersect.size() != extra.m_tags.size()) - { - continue; - } + continue; } if (extra.m_rule != "" && r.name != extra.m_rule) From 957bb6294ee6f3288c325c71a6020a001641e624 Mon Sep 17 00:00:00 2001 From: Luca Guerra Date: Fri, 13 Sep 2024 13:27:09 +0000 Subject: [PATCH 4/4] update(falco): add warning if the append condition does not appear to make sense Signed-off-by: Luca Guerra --- userspace/falco/configuration.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 2ecb23606d1..29673e6c59a 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -602,6 +602,28 @@ void falco_configuration::load_yaml(const std::string& config_name) m_config.get_sequence>(m_rules_selection, "rules"); m_config.get_sequence>(m_append_output, "append_output"); + // check if append_output matching conditions are sane, if not emit a warning + for (auto const& entry : m_append_output) + { + if (entry.m_rule != "" && entry.m_tags.size() > 0) + { + std::string tag_list; + + for (auto const& tag : entry.m_tags) + { + tag_list += tag; + tag_list += ", "; + } + + tag_list.pop_back(); + + falco_logger::log(falco_logger::level::WARNING, + "An append_ouptut entry specifies both a rule (" + entry.m_rule + ") and a list of tags (" + tag_list + std::string("). ") + + "This means that output will be appended only to the " + entry.m_rule + " rule and only if it has " + + "all the tags: " + tag_list + "."); + } + } + std::vector load_plugins; bool load_plugins_node_defined = m_config.is_defined("load_plugins");