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 <mark.stemm@gmail.com>
This commit is contained in:
Mark Stemm 2022-08-22 16:15:48 -07:00 committed by poiana
parent 7a5a4c32ee
commit 0f45cf49db
3 changed files with 99 additions and 39 deletions

View File

@ -21,6 +21,7 @@ limitations under the License.
#include "filter_evttype_resolver.h" #include "filter_evttype_resolver.h"
#include "filter_warning_resolver.h" #include "filter_warning_resolver.h"
#include <version.h> #include <version.h>
#include <string>
#include <sstream> #include <sstream>
#define MAX_VISIBILITY ((uint32_t) -1) #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 std;
using namespace libsinsp::filter; 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) rule_loader::context::context(const std::string& name)
{ {
// This ensures that every context has one location, even if // This ensures that every context has one location, even if
// that location is effectively the whole document. // 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); m_locs.push_back(loc);
} }
rule_loader::context::context(const YAML::Node &item, rule_loader::context::context(const YAML::Node &item,
const std::string item_type, const item_type item_type,
const std::string item_name, const std::string item_name,
const context& parent) 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(), '\n', ' ');
std::replace(name.begin(), name.end(), '\r', ' '); std::replace(name.begin(), name.end(), '\r', ' ');
std::string item_type = "condition expression";
std::string item_name = ""; std::string item_name = "";
// Convert the parser position to a context location. Both // 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.line = pos.line-1;
condpos.column = pos.col-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 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, void rule_loader::context::init(const std::string& name,
const position& pos, const position& pos,
const std::string item_type, const item_type item_type,
const std::string item_name, const std::string item_name,
const context& parent) const context& parent)
{ {
@ -121,7 +150,7 @@ std::string rule_loader::context::as_string()
os << (first ? "In " : " "); os << (first ? "In " : " ");
first = false; first = false;
os << loc.item_type; os << item_type_as_string(loc.item_type);
if(!loc.item_name.empty()) if(!loc.item_name.empty())
{ {
os << " '" << loc.item_name << "'"; os << " '" << loc.item_name << "'";
@ -154,7 +183,7 @@ nlohmann::json rule_loader::context::as_json()
{ {
nlohmann::json jloc, jpos; 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; jloc["item_name"] = loc.item_name;
jpos["name"] = loc.name; jpos["name"] = loc.name;

View File

@ -33,9 +33,40 @@ limitations under the License.
class rule_loader class rule_loader
{ {
public: public:
class context class context
{ {
public: 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; static const size_t default_snippet_width = 160;
struct position struct position
@ -61,7 +92,7 @@ public:
// The kind of item at this location // The kind of item at this location
// (e.g. "list", "macro", "rule", "exception", etc) // (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", // The name of this item (e.g. "Write Below Etc",
// etc). // etc).
@ -70,7 +101,7 @@ public:
context(const std::string& name); context(const std::string& name);
context(const YAML::Node& item, context(const YAML::Node& item,
const std::string item_type, item_type item_type,
const std::string item_name, const std::string item_name,
const context& parent); const context& parent);
@ -106,7 +137,7 @@ public:
private: private:
void init(const std::string& name, void init(const std::string& name,
const position& pos, const position& pos,
const std::string item_type, const item_type item_type,
const std::string item_name, const std::string item_name,
const context& parent); const context& parent);

View File

@ -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.IsDefined(), std::string("Item has no mapping for key '") + key + "'", ctx);
THROW(val.IsNull(), std::string("Mapping for key '") + key + "' is empty", 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.IsScalar(), "Value is not a scalar value", valctx);
THROW(val.Scalar().empty(), "Value must be non-empty", 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); 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); THROW(!val.IsSequence(), "Value is not a sequence", valctx);
T value; T value;
for(const YAML::Node& v : val) 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(!v.IsScalar(), "sequence value is not scalar", ictx);
THROW(!YAML::convert<T>::decode(v, value), "Can't decode YAML sequence value", ictx); THROW(!YAML::convert<T>::decode(v, value), "Can't decode YAML sequence value", ictx);
inserter(value); 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); 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()) if (val.IsScalar())
{ {
@ -142,7 +142,7 @@ static void decode_exception_info_entry(
rule_loader::rule_exception_info::entry tmp; rule_loader::rule_exception_info::entry tmp;
for(const YAML::Node& v : val) 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 is always false once you get past the outer values
optional = false; optional = false;
@ -196,7 +196,7 @@ static void read_rule_exceptions(
return; 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); 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 // Make a temp context to verify simple properties
// about the exception. // about the exception.
std::string name; 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); THROW(!ex.IsMap(), "Rule exception must be a mapping", tmp);
decode_val(ex, "name", name, tmp); decode_val(ex, "name", name, tmp);
// Now use a real context including the exception name. // 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); rule_loader::rule_exception_info v_ex(ex_ctx);
v_ex.name = name; v_ex.name = name;
@ -223,12 +223,12 @@ static void read_rule_exceptions(
const YAML::Node& exvals = ex["values"]; const YAML::Node& exvals = ex["values"];
if (exvals.IsDefined()) 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(), THROW(!exvals.IsSequence(),
"Rule exception values must be a sequence", vals_ctx); "Rule exception values must be a sequence", vals_ctx);
for (auto &val : exvals) 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; rule_loader::rule_exception_info::entry v_ex_val;
decode_exception_values(val, v_ex_val, vctx); decode_exception_values(val, v_ex_val, vctx);
@ -245,13 +245,13 @@ static void read_item(
const YAML::Node& item, const YAML::Node& item,
const rule_loader::context& parent) 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. " THROW(!item.IsMap(), "Unexpected element type. "
"Each element should be a yaml associative array.", tmp); "Each element should be a yaml associative array.", tmp);
if (item["required_engine_version"].IsDefined()) 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); rule_loader::engine_version_info v(ctx);
decode_val(item, "required_engine_version", v.version, 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()) else if(item["required_plugin_versions"].IsDefined())
{ {
const YAML::Node& req_plugin_vers = item["required_plugin_versions"]; 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(), THROW(!req_plugin_vers.IsSequence(),
"Value of required_plugin_versions must be a sequence", "Value of required_plugin_versions must be a sequence",
@ -271,10 +271,10 @@ static void read_item(
rule_loader::plugin_version_info::requirement r; rule_loader::plugin_version_info::requirement r;
// Use a temp context until we can get a name // 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); THROW(!plugin.IsMap(), "Plugin version must be a mapping", tmp);
decode_val(plugin, "name", r.name, 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); rule_loader::plugin_version_info v(pctx);
decode_val(plugin, "version", r.version, pctx); decode_val(plugin, "version", r.version, pctx);
v.alternatives.push_back(r); v.alternatives.push_back(r);
@ -287,10 +287,10 @@ static void read_item(
pctx); pctx);
for (const auto &req : alternatives) 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); THROW(!req.IsMap(), "Plugin version alternative must be a mapping", tmp);
decode_val(req, "name", r.name, 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); decode_val(req, "version", r.version, tmp);
v.alternatives.push_back(r); v.alternatives.push_back(r);
} }
@ -303,10 +303,10 @@ static void read_item(
{ {
std::string name; std::string name;
// Using tmp context until name is decoded // 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); 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); rule_loader::list_info v(ctx);
bool append = false; bool append = false;
@ -328,10 +328,10 @@ static void read_item(
{ {
std::string name; std::string name;
// Using tmp context until name is decoded // 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); 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); rule_loader::macro_info v(ctx);
v.name = name; v.name = name;
@ -339,7 +339,7 @@ static void read_item(
decode_val(item, "condition", v.cond, ctx); decode_val(item, "condition", v.cond, ctx);
// Now set the proper context for the condition now that we know it exists // 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); decode_optional_val(item, "append", append, ctx);
@ -357,10 +357,10 @@ static void read_item(
std::string name; std::string name;
// Using tmp context until name is decoded // 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); 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); rule_loader::rule_info v(ctx);
v.name = name; v.name = name;
@ -376,7 +376,7 @@ static void read_item(
decode_optional_val(item, "condition", v.cond, ctx); decode_optional_val(item, "condition", v.cond, ctx);
if(item["condition"].IsDefined()) 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); read_rule_exceptions(item, v, ctx, append);
loader.append(cfg, v); loader.append(cfg, v);
@ -402,17 +402,17 @@ static void read_item(
// All of these are required // All of these are required
decode_val(item, "condition", v.cond, ctx); 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); 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, "desc", v.desc, ctx);
decode_val(item, "priority", priority, ctx); decode_val(item, "priority", priority, ctx);
v.output = trim(v.output); v.output = trim(v.output);
v.source = falco_common::syscall_source; 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), THROW(!falco_common::parse_priority(priority, v.priority),
"Invalid priority", prictx); "Invalid priority", prictx);
decode_optional_val(item, "source", v.source, ctx); decode_optional_val(item, "source", v.source, ctx);
@ -427,7 +427,7 @@ static void read_item(
} }
else 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); cfg.res->add_warning(load_result::LOAD_UNKNOWN_ITEM, "Unknown top level item", ctx);
} }
} }