From 0f45cf49db8fecb3f52dda21b00c545a1c2644d3 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Mon, 22 Aug 2022 16:15:48 -0700 Subject: [PATCH] Use enums for rules content item type Use an enum instead of a string for the item_type aka "parts of a rules file" field of contexts. The set of values is mostly defined by the contexts that were already created. There are a couple of forward-looking values for rule outputs/macro conditions/etc. that may be useful for later. Signed-off-by: Mark Stemm --- userspace/engine/rule_loader.cpp | 43 +++++++++++++++++++---- userspace/engine/rule_loader.h | 37 ++++++++++++++++++-- userspace/engine/rule_reader.cpp | 58 ++++++++++++++++---------------- 3 files changed, 99 insertions(+), 39 deletions(-) diff --git a/userspace/engine/rule_loader.cpp b/userspace/engine/rule_loader.cpp index 7f2dc854..89e625e1 100644 --- a/userspace/engine/rule_loader.cpp +++ b/userspace/engine/rule_loader.cpp @@ -21,6 +21,7 @@ limitations under the License. #include "filter_evttype_resolver.h" #include "filter_warning_resolver.h" #include +#include #include #define MAX_VISIBILITY ((uint32_t) -1) @@ -35,16 +36,45 @@ static string s_default_extra_fmt = "%container.name (id=%container.id)"; using namespace std; using namespace libsinsp::filter; +static const std::string item_type_strings[] = { + "value for", + "exceptions", + "exception", + "exception values", + "exception value", + "rules content", + "rules content item", + "required_engine_version", + "required plugin versions", + "required plugin versions entry", + "required plugin versions alternative", + "list", + "list item", + "macro", + "macro condition", + "rule", + "rule condition", + "condition expression", + "rule output", + "rule output expression", + "rule priority" +}; + +const std::string& rule_loader::context::item_type_as_string(enum item_type it) +{ + return item_type_strings[it]; +} + rule_loader::context::context(const std::string& name) { // This ensures that every context has one location, even if // that location is effectively the whole document. - location loc = {name, position(), "rules content", ""}; + location loc = {name, position(), rule_loader::context::RULES_CONTENT, ""}; m_locs.push_back(loc); } rule_loader::context::context(const YAML::Node &item, - const std::string item_type, + const item_type item_type, const std::string item_name, const context& parent) { @@ -64,7 +94,6 @@ rule_loader::context::context(const libsinsp::filter::parser::pos_info& pos, std::replace(name.begin(), name.end(), '\n', ' '); std::replace(name.begin(), name.end(), '\r', ' '); - std::string item_type = "condition expression"; std::string item_name = ""; // Convert the parser position to a context location. Both @@ -76,7 +105,7 @@ rule_loader::context::context(const libsinsp::filter::parser::pos_info& pos, condpos.line = pos.line-1; condpos.column = pos.col-1; - init(name, condpos, item_type, item_name, parent); + init(name, condpos, rule_loader::context::CONDITION_EXPRESSION, item_name, parent); } const std::string& rule_loader::context::name() const @@ -92,7 +121,7 @@ const std::string& rule_loader::context::name() const void rule_loader::context::init(const std::string& name, const position& pos, - const std::string item_type, + const item_type item_type, const std::string item_name, const context& parent) { @@ -121,7 +150,7 @@ std::string rule_loader::context::as_string() os << (first ? "In " : " "); first = false; - os << loc.item_type; + os << item_type_as_string(loc.item_type); if(!loc.item_name.empty()) { os << " '" << loc.item_name << "'"; @@ -154,7 +183,7 @@ nlohmann::json rule_loader::context::as_json() { nlohmann::json jloc, jpos; - jloc["item_type"] = loc.item_type; + jloc["item_type"] = item_type_as_string(loc.item_type); jloc["item_name"] = loc.item_name; jpos["name"] = loc.name; diff --git a/userspace/engine/rule_loader.h b/userspace/engine/rule_loader.h index 993c3460..5f070c54 100644 --- a/userspace/engine/rule_loader.h +++ b/userspace/engine/rule_loader.h @@ -33,9 +33,40 @@ limitations under the License. class rule_loader { public: + class context { public: + // The kinds of items that can be in rules + // content. These generally map to yaml items but a + // few are more specific (e.g. "within condition + // expression", "value for yaml node", etc.) + enum item_type { + VALUE_FOR = 0, + EXCEPTIONS, + EXCEPTION, + EXCEPTION_VALUES, + EXCEPTION_VALUE, + RULES_CONTENT, + RULES_CONTENT_ITEM, + REQUIRED_ENGINE_VERSION, + REQUIRED_PLUGIN_VERSIONS, + REQUIRED_PLUGIN_VERSIONS_ENTRY, + REQUIRED_PLUGIN_VERSIONS_ALTERNATIVE, + LIST, + LIST_ITEM, + MACRO, + MACRO_CONDITION, + RULE, + RULE_CONDITION, + CONDITION_EXPRESSION, + RULE_OUTPUT, + RULE_OUTPUT_EXPRESSION, + RULE_PRIORITY + }; + + static const std::string& item_type_as_string(enum item_type it); + static const size_t default_snippet_width = 160; struct position @@ -61,7 +92,7 @@ public: // The kind of item at this location // (e.g. "list", "macro", "rule", "exception", etc) - std::string item_type; + context::item_type item_type; // The name of this item (e.g. "Write Below Etc", // etc). @@ -70,7 +101,7 @@ public: context(const std::string& name); context(const YAML::Node& item, - const std::string item_type, + item_type item_type, const std::string item_name, const context& parent); @@ -106,7 +137,7 @@ public: private: void init(const std::string& name, const position& pos, - const std::string item_type, + const item_type item_type, const std::string item_name, const context& parent); diff --git a/userspace/engine/rule_reader.cpp b/userspace/engine/rule_reader.cpp index 36564a34..81686f28 100644 --- a/userspace/engine/rule_reader.cpp +++ b/userspace/engine/rule_reader.cpp @@ -34,7 +34,7 @@ static void decode_val_generic(const YAML::Node& item, const char *key, T& out, THROW(!val.IsDefined(), std::string("Item has no mapping for key '") + key + "'", ctx); THROW(val.IsNull(), std::string("Mapping for key '") + key + "' is empty", ctx); - rule_loader::context valctx(val, "value for", key, ctx); + rule_loader::context valctx(val, rule_loader::context::VALUE_FOR, key, ctx); THROW(!val.IsScalar(), "Value is not a scalar value", valctx); THROW(val.Scalar().empty(), "Value must be non-empty", valctx); @@ -72,13 +72,13 @@ static void decode_seq(const YAML::Node& item, const char *key, THROW(!val.IsDefined(), std::string("Item has no mapping for key '") + key + "'", ctx); - rule_loader::context valctx(val, "value for", key, ctx); + rule_loader::context valctx(val, rule_loader::context::VALUE_FOR, key, ctx); THROW(!val.IsSequence(), "Value is not a sequence", valctx); T value; for(const YAML::Node& v : val) { - rule_loader::context ictx(v, "list item", "", valctx); + rule_loader::context ictx(v, rule_loader::context::LIST_ITEM, "", valctx); THROW(!v.IsScalar(), "sequence value is not scalar", ictx); THROW(!YAML::convert::decode(v, value), "Can't decode YAML sequence value", ictx); inserter(value); @@ -128,7 +128,7 @@ static void decode_exception_info_entry( THROW(!val.IsDefined(), std::string("Item has no mapping for key '") + key + "'", ctx); - rule_loader::context valctx(val, "value for", (key == NULL ? "" : key), ctx); + rule_loader::context valctx(val, rule_loader::context::VALUE_FOR, (key == NULL ? "" : key), ctx); if (val.IsScalar()) { @@ -142,7 +142,7 @@ static void decode_exception_info_entry( rule_loader::rule_exception_info::entry tmp; for(const YAML::Node& v : val) { - rule_loader::context lctx(v, "list exception entry", "", valctx); + rule_loader::context lctx(v, rule_loader::context::EXCEPTION, "", valctx); // Optional is always false once you get past the outer values optional = false; @@ -196,7 +196,7 @@ static void read_rule_exceptions( return; } - rule_loader::context exes_ctx(exs, "exceptions", "", parent); + rule_loader::context exes_ctx(exs, rule_loader::context::EXCEPTIONS, "", parent); THROW(!exs.IsSequence(), "Rule exceptions must be a sequence", exes_ctx); @@ -205,13 +205,13 @@ static void read_rule_exceptions( // Make a temp context to verify simple properties // about the exception. std::string name; - rule_loader::context tmp(ex, "exception", "", exes_ctx); + rule_loader::context tmp(ex, rule_loader::context::EXCEPTION, "", exes_ctx); THROW(!ex.IsMap(), "Rule exception must be a mapping", tmp); decode_val(ex, "name", name, tmp); // Now use a real context including the exception name. - rule_loader::context ex_ctx(ex, "exception", name, parent); + rule_loader::context ex_ctx(ex, rule_loader::context::EXCEPTION, name, parent); rule_loader::rule_exception_info v_ex(ex_ctx); v_ex.name = name; @@ -223,12 +223,12 @@ static void read_rule_exceptions( const YAML::Node& exvals = ex["values"]; if (exvals.IsDefined()) { - rule_loader::context vals_ctx(exvals, "exception values", "", ex_ctx); + rule_loader::context vals_ctx(exvals, rule_loader::context::EXCEPTION_VALUES, "", ex_ctx); THROW(!exvals.IsSequence(), "Rule exception values must be a sequence", vals_ctx); for (auto &val : exvals) { - rule_loader::context vctx(val, "exception value", "", vals_ctx); + rule_loader::context vctx(val, rule_loader::context::EXCEPTION_VALUE, "", vals_ctx); rule_loader::rule_exception_info::entry v_ex_val; decode_exception_values(val, v_ex_val, vctx); @@ -245,13 +245,13 @@ static void read_item( const YAML::Node& item, const rule_loader::context& parent) { - rule_loader::context tmp(item, "item", "", parent); + rule_loader::context tmp(item, rule_loader::context::RULES_CONTENT_ITEM, "", parent); THROW(!item.IsMap(), "Unexpected element type. " "Each element should be a yaml associative array.", tmp); if (item["required_engine_version"].IsDefined()) { - rule_loader::context ctx(item, "required_engine_version", "", parent); + rule_loader::context ctx(item, rule_loader::context::REQUIRED_ENGINE_VERSION, "", parent); rule_loader::engine_version_info v(ctx); decode_val(item, "required_engine_version", v.version, ctx); @@ -260,7 +260,7 @@ static void read_item( else if(item["required_plugin_versions"].IsDefined()) { const YAML::Node& req_plugin_vers = item["required_plugin_versions"]; - rule_loader::context ctx(req_plugin_vers, "required_plugin_versions", "", parent); + rule_loader::context ctx(req_plugin_vers, rule_loader::context::REQUIRED_PLUGIN_VERSIONS, "", parent); THROW(!req_plugin_vers.IsSequence(), "Value of required_plugin_versions must be a sequence", @@ -271,10 +271,10 @@ static void read_item( rule_loader::plugin_version_info::requirement r; // Use a temp context until we can get a name - rule_loader::context tmp(plugin, "plugin version", "", ctx); + rule_loader::context tmp(plugin, rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ENTRY, "", ctx); THROW(!plugin.IsMap(), "Plugin version must be a mapping", tmp); decode_val(plugin, "name", r.name, tmp); - rule_loader::context pctx(plugin, "plugin version", r.name, ctx); + rule_loader::context pctx(plugin, rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ENTRY, r.name, ctx); rule_loader::plugin_version_info v(pctx); decode_val(plugin, "version", r.version, pctx); v.alternatives.push_back(r); @@ -287,10 +287,10 @@ static void read_item( pctx); for (const auto &req : alternatives) { - tmp = rule_loader::context(req, "plugin version alternative", "", pctx); + tmp = rule_loader::context(req, rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ALTERNATIVE, "", pctx); THROW(!req.IsMap(), "Plugin version alternative must be a mapping", tmp); decode_val(req, "name", r.name, tmp); - tmp = rule_loader::context(req, "plugin version alternative", r.name, pctx); + tmp = rule_loader::context(req, rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ALTERNATIVE, r.name, pctx); decode_val(req, "version", r.version, tmp); v.alternatives.push_back(r); } @@ -303,10 +303,10 @@ static void read_item( { std::string name; // Using tmp context until name is decoded - rule_loader::context tmp(item, "list", "", parent); + rule_loader::context tmp(item, rule_loader::context::LIST, "", parent); decode_val(item, "list", name, tmp); - rule_loader::context ctx(item, "list", name, parent); + rule_loader::context ctx(item, rule_loader::context::LIST, name, parent); rule_loader::list_info v(ctx); bool append = false; @@ -328,10 +328,10 @@ static void read_item( { std::string name; // Using tmp context until name is decoded - rule_loader::context tmp(item, "macro", "", parent); + rule_loader::context tmp(item, rule_loader::context::MACRO, "", parent); decode_val(item, "macro", name, tmp); - rule_loader::context ctx(item, "macro", name, parent); + rule_loader::context ctx(item, rule_loader::context::MACRO, name, parent); rule_loader::macro_info v(ctx); v.name = name; @@ -339,7 +339,7 @@ static void read_item( decode_val(item, "condition", v.cond, ctx); // Now set the proper context for the condition now that we know it exists - v.cond_ctx = rule_loader::context(item["condition"], "condition", "", ctx); + v.cond_ctx = rule_loader::context(item["condition"], rule_loader::context::MACRO_CONDITION, "", ctx); decode_optional_val(item, "append", append, ctx); @@ -357,10 +357,10 @@ static void read_item( std::string name; // Using tmp context until name is decoded - rule_loader::context tmp(item, "rule", "", parent); + rule_loader::context tmp(item, rule_loader::context::RULE, "", parent); decode_val(item, "rule", name, tmp); - rule_loader::context ctx(item, "rule", name, parent); + rule_loader::context ctx(item, rule_loader::context::RULE, name, parent); rule_loader::rule_info v(ctx); v.name = name; @@ -376,7 +376,7 @@ static void read_item( decode_optional_val(item, "condition", v.cond, ctx); if(item["condition"].IsDefined()) { - v.cond_ctx = rule_loader::context(item["condition"], "condition", "", ctx); + v.cond_ctx = rule_loader::context(item["condition"], rule_loader::context::RULE_CONDITION, "", ctx); } read_rule_exceptions(item, v, ctx, append); loader.append(cfg, v); @@ -402,17 +402,17 @@ static void read_item( // All of these are required decode_val(item, "condition", v.cond, ctx); - v.cond_ctx = rule_loader::context(item["condition"], "condition", "", ctx); + v.cond_ctx = rule_loader::context(item["condition"], rule_loader::context::RULE_CONDITION, "", ctx); decode_val(item, "output", v.output, ctx); - v.output_ctx = rule_loader::context(item["output"], "output", "", ctx); + v.output_ctx = rule_loader::context(item["output"], rule_loader::context::RULE_OUTPUT, "", ctx); decode_val(item, "desc", v.desc, ctx); decode_val(item, "priority", priority, ctx); v.output = trim(v.output); v.source = falco_common::syscall_source; - rule_loader::context prictx(item["priority"], "priority value", "", ctx); + rule_loader::context prictx(item["priority"], rule_loader::context::RULE_PRIORITY, "", ctx); THROW(!falco_common::parse_priority(priority, v.priority), "Invalid priority", prictx); decode_optional_val(item, "source", v.source, ctx); @@ -427,7 +427,7 @@ static void read_item( } else { - rule_loader::context ctx(item, "unknown", "", parent); + rule_loader::context ctx(item, rule_loader::context::RULES_CONTENT_ITEM, "", parent); cfg.res->add_warning(load_result::LOAD_UNKNOWN_ITEM, "Unknown top level item", ctx); } }