diff --git a/unit_tests/engine/test_rule_loader.cpp b/unit_tests/engine/test_rule_loader.cpp index 9a937464ace..2ef90783c35 100644 --- a/unit_tests/engine/test_rule_loader.cpp +++ b/unit_tests/engine/test_rule_loader.cpp @@ -903,4 +903,59 @@ TEST_F(test_falco_engine, list_name_invalid) ASSERT_FALSE(load_rules(rules_content, "rules.yaml")); ASSERT_TRUE(check_error_message("List has an invalid name. List names must match a regular expression")); +} + +// The appended exception has a purposely miswritten field (value), +// simulating a typo or an incorrect usage. +TEST_F(test_falco_engine, exceptions_append_no_values) +{ + std::string rules_content = R"END( +- rule: test_rule + desc: test rule + condition: proc.cmdline contains curl + output: command=%proc.cmdline + priority: INFO + exceptions: + - name: test_exception + fields: [proc.cmdline] + comps: [contains] + values: + - [curl 127.0.0.1] + +- rule: test_rule + exceptions: + - name: test_exception + value: curl 1.1.1.1 + append: true +)END"; + + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_TRUE(check_warning_message("Overriding/appending exception with no values")); +} + +TEST_F(test_falco_engine, exceptions_override_no_values) +{ + std::string rules_content = R"END( +- rule: test_rule + desc: test rule + condition: proc.cmdline contains curl + output: command=%proc.cmdline + priority: INFO + exceptions: + - name: test_exception + fields: [proc.cmdline] + comps: [contains] + values: + - [curl 127.0.0.1] + +- rule: test_rule + exceptions: + - name: test_exception + value: curl 1.1.1.1 + override: + exceptions: append +)END"; + + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_TRUE(check_warning_message("Overriding/appending exception with no values")); } \ No newline at end of file diff --git a/userspace/engine/falco_load_result.cpp b/userspace/engine/falco_load_result.cpp index 11b14cf9b5b..10790acab67 100644 --- a/userspace/engine/falco_load_result.cpp +++ b/userspace/engine/falco_load_result.cpp @@ -23,7 +23,8 @@ static const std::string error_codes[] = { "LOAD_ERR_YAML_VALIDATE", "LOAD_ERR_COMPILE_CONDITION", "LOAD_ERR_COMPILE_OUTPUT", - "LOAD_ERR_VALIDATE" + "LOAD_ERR_VALIDATE", + "LOAD_ERR_EXTENSION" }; const std::string& falco::load_result::error_code_str(error_code ec) @@ -37,7 +38,8 @@ static const std::string error_strings[] = { "Error validating internal structure of YAML file", "Error compiling condition", "Error compiling output", - "Error validating rule/macro/list/exception objects" + "Error validating rule/macro/list/exception objects", + "Error in extension item" }; const std::string& falco::load_result::error_str(error_code ec) @@ -51,7 +53,8 @@ static const std::string error_descs[] = { "This occurs when the internal structure of the YAML file is incorrect. Examples include not consisting of a sequence of maps, a given rule/macro/list item not having required keys, values not having the right type (e.g. the items property of a list not being a sequence), etc.", "This occurs when a condition string can not be compiled to a filter object.", "This occurs when an output string can not be compiled to an output object.", - "This occurs when a rule/macro/list item is incorrect. Examples include a condition field referring to an undefined macro, falco engine/plugin version mismatches, items with append without any existing item, exception fields/comps having different lengths, etc." + "This occurs when a rule/macro/list item is incorrect. Examples include a condition field referring to an undefined macro, falco engine/plugin version mismatches, items with append without any existing item, exception fields/comps having different lengths, etc.", + "This occurs when there is an error in an extension item" }; const std::string& falco::load_result::error_desc(error_code ec) @@ -67,7 +70,9 @@ static const std::string warning_codes[] = { "LOAD_UNUSED_MACRO", "LOAD_UNUSED_LIST", "LOAD_UNKNOWN_ITEM", - "LOAD_DEPRECATED_ITEM" + "LOAD_DEPRECATED_ITEM", + "LOAD_WARNING_EXTENSION", + "LOAD_APPEND_NO_VALUES" }; const std::string& falco::load_result::warning_code_str(warning_code wc) @@ -83,7 +88,9 @@ static const std::string warning_strings[] = { "Unused macro", "Unused list", "Unknown rules file item", - "Used deprecated item" + "Used deprecated item", + "Warning in extension item", + "Overriding/appending with no values" }; const std::string& falco::load_result::warning_str(warning_code wc) @@ -99,7 +106,9 @@ static const std::string warning_descs[] = { "A macro is defined in the rules content but is not used by any other macro or rule.", "A list is defined in the rules content but is not used by any other list, macro, or rule.", "An unknown top-level object is in the rules content. It will be ignored.", - "A deprecated item is employed by lists, macros, or rules." + "A deprecated item is employed by lists, macros, or rules.", + "An extension item has a warning", + "A rule exception is overriding/appending with no values" }; const std::string& falco::load_result::warning_desc(warning_code wc) diff --git a/userspace/engine/falco_load_result.h b/userspace/engine/falco_load_result.h index a3641e59f38..dd707c7ede6 100644 --- a/userspace/engine/falco_load_result.h +++ b/userspace/engine/falco_load_result.h @@ -57,7 +57,8 @@ class load_result { LOAD_UNUSED_LIST, LOAD_UNKNOWN_ITEM, LOAD_DEPRECATED_ITEM, - LOAD_WARNING_EXTENSION + LOAD_WARNING_EXTENSION, + LOAD_APPEND_NO_VALUES }; virtual ~load_result() = default; diff --git a/userspace/engine/rule_loader_reader.cpp b/userspace/engine/rule_loader_reader.cpp index 1eac3ee7ec7..87c94ac3007 100644 --- a/userspace/engine/rule_loader_reader.cpp +++ b/userspace/engine/rule_loader_reader.cpp @@ -282,6 +282,7 @@ static void decode_exception_values( } static void read_rule_exceptions( + rule_loader::configuration& cfg, const YAML::Node& item, std::vector& exceptions, const rule_loader::context& parent, @@ -334,19 +335,24 @@ static void read_rule_exceptions( decode_exception_values(val, v_ex_val, vctx); v_ex.values.push_back(v_ex_val); } + } + else if (append) + { + cfg.res->add_warning(falco::load_result::LOAD_APPEND_NO_VALUES, "Overriding/appending exception with no values", ex_ctx); } exceptions.push_back(v_ex); } } static void read_rule_exceptions( + rule_loader::configuration& cfg, const YAML::Node& item, std::optional>& exceptions, const rule_loader::context& parent, bool append) { std::vector decoded; - read_rule_exceptions(item, decoded, parent, append); + read_rule_exceptions(cfg, item, decoded, parent, append); exceptions = decoded; } @@ -597,7 +603,7 @@ void rule_loader::reader::read_item( if (check_update_expected(expected_keys, override_append, "append", "exceptions", ctx)) { - read_rule_exceptions(item, v.exceptions, ctx, true); + read_rule_exceptions(cfg, item, v.exceptions, ctx, true); } if (check_update_expected(expected_keys, override_append, "append", "output", ctx)) @@ -629,7 +635,7 @@ void rule_loader::reader::read_item( if (check_update_expected(expected_keys, override_replace, "replace", "exceptions", ctx)) { - read_rule_exceptions(item, v.exceptions, ctx, true); + read_rule_exceptions(cfg, item, v.exceptions, ctx, true); } if (check_update_expected(expected_keys, override_replace, "replace", "output", ctx)) @@ -694,7 +700,7 @@ void rule_loader::reader::read_item( if(item["exceptions"].IsDefined()) { - read_rule_exceptions(item, v.exceptions, ctx, true); + read_rule_exceptions(cfg, item, v.exceptions, ctx, true); } // TODO restore this error and update testing @@ -750,7 +756,7 @@ void rule_loader::reader::read_item( decode_optional_val(item, "warn_evttypes", v.warn_evttypes, ctx); decode_optional_val(item, "skip-if-unknown-filter", v.skip_if_unknown_filter, ctx); decode_tags(item, v.tags, ctx); - read_rule_exceptions(item, v.exceptions, ctx, has_append_flag); + read_rule_exceptions(cfg, item, v.exceptions, ctx, has_append_flag); collector.define(cfg, v); } }