mirror of
https://github.com/falcosecurity/falco.git
synced 2025-08-07 01:03:53 +00:00
fix(userspace/engine): solve issues in describing rules/macros/lists
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
parent
8f411f3d3b
commit
dc264a0577
@ -506,6 +506,16 @@ std::size_t falco_engine::add_source(const std::string &source,
|
|||||||
return m_sources.insert(src, source);
|
return m_sources.insert(src, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> inline Json::Value sequence_to_json_array(const T& seq)
|
||||||
|
{
|
||||||
|
Json::Value ret = Json::arrayValue;
|
||||||
|
for (auto it = seq.begin(); it != seq.end(); it++)
|
||||||
|
{
|
||||||
|
ret.append(*it);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void falco_engine::describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins, bool json) const
|
void falco_engine::describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins, bool json) const
|
||||||
{
|
{
|
||||||
if(!json)
|
if(!json)
|
||||||
@ -535,9 +545,20 @@ void falco_engine::describe_rule(std::string *rule, const std::vector<std::share
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// use previously-loaded collector definitions to obtain a compiled
|
||||||
|
// output of rules, macros, and lists.
|
||||||
|
// note: we ignore the loading result (errors, warnings), as they should have
|
||||||
|
// already been checked when previously-loading the rules files. Thus, we
|
||||||
|
// assume that the definitions will give no compilation error.
|
||||||
|
rule_loader::configuration cfg("", m_sources, "");
|
||||||
|
cfg.output_extra = m_extra;
|
||||||
|
cfg.replace_output_container_info = m_replace_container_info;
|
||||||
|
rule_loader::compiler::compile_output compiled;
|
||||||
|
rule_loader::compiler().compile(cfg, m_rule_collector, compiled);
|
||||||
|
|
||||||
|
// use collected and compiled info to print a json output
|
||||||
Json::FastWriter writer;
|
Json::FastWriter writer;
|
||||||
std::string json_str;
|
std::string json_str;
|
||||||
|
|
||||||
if(!rule)
|
if(!rule)
|
||||||
{
|
{
|
||||||
// In this case we build json information about
|
// In this case we build json information about
|
||||||
@ -573,33 +594,33 @@ void falco_engine::describe_rule(std::string *rule, const std::vector<std::share
|
|||||||
|
|
||||||
// Store information about rules
|
// Store information about rules
|
||||||
Json::Value rules_array = Json::arrayValue;
|
Json::Value rules_array = Json::arrayValue;
|
||||||
for(const auto& r : m_rules)
|
for(const auto& r : compiled.rules)
|
||||||
{
|
{
|
||||||
auto ri = m_rule_collector.rules().at(r.name);
|
auto info = m_rule_collector.rules().at(r.name);
|
||||||
Json::Value rule;
|
Json::Value rule;
|
||||||
get_json_details(rule, r, *ri, plugins);
|
get_json_details(rule, r, *info, plugins);
|
||||||
|
|
||||||
// Append to rule array
|
|
||||||
rules_array.append(rule);
|
rules_array.append(rule);
|
||||||
}
|
}
|
||||||
output["rules"] = rules_array;
|
output["rules"] = rules_array;
|
||||||
|
|
||||||
// Store information about macros
|
// Store information about macros
|
||||||
Json::Value macros_array = Json::arrayValue;
|
Json::Value macros_array = Json::arrayValue;
|
||||||
for(const auto &m : m_rule_collector.macros())
|
for(const auto &m : compiled.macros)
|
||||||
{
|
{
|
||||||
|
auto info = m_rule_collector.macros().at(m.name);
|
||||||
Json::Value macro;
|
Json::Value macro;
|
||||||
get_json_details(macro, m);
|
get_json_details(macro, m, *info, plugins);
|
||||||
macros_array.append(macro);
|
macros_array.append(macro);
|
||||||
}
|
}
|
||||||
output["macros"] = macros_array;
|
output["macros"] = macros_array;
|
||||||
|
|
||||||
// Store information about lists
|
// Store information about lists
|
||||||
Json::Value lists_array = Json::arrayValue;
|
Json::Value lists_array = Json::arrayValue;
|
||||||
for(const auto &l : m_rule_collector.lists())
|
for(const auto &l : compiled.lists)
|
||||||
{
|
{
|
||||||
|
auto info = m_rule_collector.lists().at(l.name);
|
||||||
Json::Value list;
|
Json::Value list;
|
||||||
get_json_details(list, l);
|
get_json_details(list, l, *info, plugins);
|
||||||
lists_array.append(list);
|
lists_array.append(list);
|
||||||
}
|
}
|
||||||
output["lists"] = lists_array;
|
output["lists"] = lists_array;
|
||||||
@ -626,69 +647,61 @@ void falco_engine::describe_rule(std::string *rule, const std::vector<std::share
|
|||||||
void falco_engine::get_json_details(
|
void falco_engine::get_json_details(
|
||||||
Json::Value &out,
|
Json::Value &out,
|
||||||
const falco_rule &r,
|
const falco_rule &r,
|
||||||
const rule_loader::rule_info &ri,
|
const rule_loader::rule_info &info,
|
||||||
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
|
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
|
||||||
{
|
{
|
||||||
Json::Value rule_info;
|
Json::Value rule_info;
|
||||||
|
|
||||||
// Fill general rule information
|
// Fill general rule information
|
||||||
rule_info["name"] = r.name;
|
rule_info["name"] = r.name;
|
||||||
rule_info["condition"] = ri.cond;
|
rule_info["condition"] = info.cond;
|
||||||
rule_info["priority"] = format_priority(r.priority, false);
|
rule_info["priority"] = format_priority(r.priority, false);
|
||||||
rule_info["output"] = r.output;
|
rule_info["output"] = info.output;
|
||||||
rule_info["description"] = r.description;
|
rule_info["description"] = r.description;
|
||||||
rule_info["enabled"] = ri.enabled;
|
rule_info["enabled"] = info.enabled;
|
||||||
rule_info["source"] = r.source;
|
rule_info["source"] = r.source;
|
||||||
Json::Value tags = Json::arrayValue;
|
rule_info["tags"] = sequence_to_json_array(info.tags);
|
||||||
for(const auto &t : ri.tags)
|
|
||||||
{
|
|
||||||
tags.append(t);
|
|
||||||
}
|
|
||||||
rule_info["tags"] = tags;
|
|
||||||
out["info"] = rule_info;
|
out["info"] = rule_info;
|
||||||
|
|
||||||
// Parse rule condition and build the AST
|
// Parse rule condition and build the non-compiled AST
|
||||||
// Assumption: no exception because rules have already been loaded.
|
// Assumption: no error because rules have already been loaded.
|
||||||
auto ast = libsinsp::filter::parser(ri.cond).parse();
|
auto ast = libsinsp::filter::parser(info.cond).parse();
|
||||||
|
|
||||||
// get details related to the condition's filter
|
// get details related to the condition's filter
|
||||||
filter_details details;
|
filter_details details;
|
||||||
|
filter_details compiled_details;
|
||||||
Json::Value json_details;
|
Json::Value json_details;
|
||||||
for(const auto &m : m_rule_collector.macros())
|
for(const auto &m : m_rule_collector.macros())
|
||||||
{
|
{
|
||||||
details.known_macros.insert(m.name);
|
details.known_macros.insert(m.name);
|
||||||
|
compiled_details.known_macros.insert(m.name);
|
||||||
}
|
}
|
||||||
for(const auto &l : m_rule_collector.lists())
|
for(const auto &l : m_rule_collector.lists())
|
||||||
{
|
{
|
||||||
details.known_lists.insert(l.name);
|
details.known_lists.insert(l.name);
|
||||||
|
compiled_details.known_lists.insert(l.name);
|
||||||
}
|
}
|
||||||
filter_details_resolver().run(ast.get(), details);
|
filter_details_resolver().run(ast.get(), details);
|
||||||
get_json_filter_details(json_details, details);
|
filter_details_resolver().run(r.condition.get(), compiled_details);
|
||||||
out["details"] = json_details;
|
|
||||||
|
out["details"]["macros"] = sequence_to_json_array(details.macros);
|
||||||
|
out["details"]["lists"] = sequence_to_json_array(details.lists);
|
||||||
|
out["details"]["operators"] = sequence_to_json_array(compiled_details.operators);
|
||||||
|
out["details"]["condition_fields"] = sequence_to_json_array(compiled_details.fields);
|
||||||
|
|
||||||
// Get fields from output string
|
// Get fields from output string
|
||||||
auto fmt = create_formatter(r.source, r.output);
|
auto fmt = create_formatter(r.source, r.output);
|
||||||
std::vector<std::string> out_fields;
|
std::vector<std::string> out_fields;
|
||||||
fmt->get_field_names(out_fields);
|
fmt->get_field_names(out_fields);
|
||||||
Json::Value outputFields = Json::arrayValue;
|
out["details"]["output_fields"] = sequence_to_json_array(out_fields);
|
||||||
for(const auto &of : out_fields)
|
|
||||||
{
|
|
||||||
outputFields.append(of);
|
|
||||||
}
|
|
||||||
out["details"]["output_fields"] = outputFields;
|
|
||||||
|
|
||||||
// Get fields from exceptions
|
// Get fields from exceptions
|
||||||
Json::Value exception_fields = Json::arrayValue;
|
out["details"]["exception_fields"] = sequence_to_json_array(r.exception_fields);
|
||||||
for(const auto &f : r.exception_fields)
|
|
||||||
{
|
|
||||||
exception_fields.append(f);
|
|
||||||
}
|
|
||||||
out["details"]["exception_fields"] = exception_fields;
|
|
||||||
|
|
||||||
// Get names and operators from exceptions
|
// Get names and operators from exceptions
|
||||||
Json::Value exception_names = Json::arrayValue;
|
Json::Value exception_names = Json::arrayValue;
|
||||||
Json::Value exception_operators = Json::arrayValue;
|
Json::Value exception_operators = Json::arrayValue;
|
||||||
for(const auto &e : ri.exceptions)
|
for(const auto &e : info.exceptions)
|
||||||
{
|
{
|
||||||
exception_names.append(e.name);
|
exception_names.append(e.name);
|
||||||
if(e.comps.is_list)
|
if(e.comps.is_list)
|
||||||
@ -719,9 +732,13 @@ void falco_engine::get_json_details(
|
|||||||
|
|
||||||
// Store event types
|
// Store event types
|
||||||
Json::Value events;
|
Json::Value events;
|
||||||
get_json_evt_types(events, ri.source, details);
|
get_json_evt_types(events, info.source, r.condition.get());
|
||||||
out["details"]["events"] = events;
|
out["details"]["events"] = events;
|
||||||
|
|
||||||
|
// Store compiled condition and output
|
||||||
|
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(r.condition.get());
|
||||||
|
out["details"]["output_compiled"] = r.output;
|
||||||
|
|
||||||
// Compute the plugins that are actually used by this rule. This is involves:
|
// Compute the plugins that are actually used by this rule. This is involves:
|
||||||
// - The rule's event source, that can be implemented by a plugin
|
// - The rule's event source, that can be implemented by a plugin
|
||||||
// - The fields used in the rule's condition, output, and exceptions
|
// - The fields used in the rule's condition, output, and exceptions
|
||||||
@ -729,59 +746,86 @@ void falco_engine::get_json_details(
|
|||||||
// match plugin-provided async events
|
// match plugin-provided async events
|
||||||
Json::Value used_plugins;
|
Json::Value used_plugins;
|
||||||
// note: making a union of conditions's and output's fields
|
// note: making a union of conditions's and output's fields
|
||||||
// note: the condition's AST should include all resolved refs and exceptions
|
// note: the condition's AST accounts for all the resolved refs and exceptions
|
||||||
details.fields.insert(out_fields.begin(), out_fields.end());
|
compiled_details.fields.insert(out_fields.begin(), out_fields.end());
|
||||||
get_json_used_plugins(used_plugins, ri.source, details.evtnames, details.fields, plugins);
|
get_json_used_plugins(used_plugins, info.source, compiled_details.evtnames, compiled_details.fields, plugins);
|
||||||
out["details"]["plugins"] = used_plugins;
|
out["details"]["plugins"] = used_plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_engine::get_json_details(
|
void falco_engine::get_json_details(
|
||||||
Json::Value& out,
|
Json::Value& out,
|
||||||
const rule_loader::macro_info& m) const
|
const falco_macro& m,
|
||||||
|
const rule_loader::macro_info& info,
|
||||||
|
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
|
||||||
{
|
{
|
||||||
Json::Value macro_info;
|
Json::Value macro_info;
|
||||||
|
|
||||||
macro_info["name"] = m.name;
|
macro_info["name"] = m.name;
|
||||||
macro_info["condition"] = m.cond;
|
macro_info["condition"] = info.cond;
|
||||||
out["info"] = macro_info;
|
out["info"] = macro_info;
|
||||||
|
|
||||||
// Parse rule condition and build the AST
|
// Parse the macro condition and build the non-compiled AST
|
||||||
// Assumption: no exception because rules have already been loaded.
|
// Assumption: no exception because rules have already been loaded.
|
||||||
auto ast = libsinsp::filter::parser(m.cond).parse();
|
auto ast = libsinsp::filter::parser(info.cond).parse();
|
||||||
|
|
||||||
// get details related to the condition's filter
|
// get details related to the condition's filter
|
||||||
filter_details details;
|
filter_details details;
|
||||||
|
filter_details compiled_details;
|
||||||
Json::Value json_details;
|
Json::Value json_details;
|
||||||
for(const auto &m : m_rule_collector.macros())
|
for(const auto &m : m_rule_collector.macros())
|
||||||
{
|
{
|
||||||
details.known_macros.insert(m.name);
|
details.known_macros.insert(m.name);
|
||||||
|
compiled_details.known_macros.insert(m.name);
|
||||||
}
|
}
|
||||||
for(const auto &l : m_rule_collector.lists())
|
for(const auto &l : m_rule_collector.lists())
|
||||||
{
|
{
|
||||||
details.known_lists.insert(l.name);
|
details.known_lists.insert(l.name);
|
||||||
|
compiled_details.known_lists.insert(l.name);
|
||||||
}
|
}
|
||||||
filter_details_resolver().run(ast.get(), details);
|
filter_details_resolver().run(ast.get(), details);
|
||||||
get_json_filter_details(json_details, details);
|
filter_details_resolver().run(m.condition.get(), compiled_details);
|
||||||
out["details"] = json_details;
|
|
||||||
|
out["details"]["used"] = m.used;
|
||||||
|
out["details"]["macros"] = sequence_to_json_array(details.macros);
|
||||||
|
out["details"]["lists"] = sequence_to_json_array(details.lists);
|
||||||
|
out["details"]["operators"] = sequence_to_json_array(compiled_details.operators);
|
||||||
|
out["details"]["condition_fields"] = sequence_to_json_array(compiled_details.fields);
|
||||||
|
|
||||||
// Store event types
|
// Store event types
|
||||||
Json::Value events;
|
Json::Value events;
|
||||||
get_json_evt_types(events, "", details);
|
get_json_evt_types(events, "", m.condition.get());
|
||||||
out["details"]["events"] = events;
|
out["details"]["events"] = events;
|
||||||
|
|
||||||
|
// Store compiled condition
|
||||||
|
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(m.condition.get());
|
||||||
|
|
||||||
|
// Compute the plugins that are actually used by this macro.
|
||||||
|
// Note: macros have no specidic source, we need to set an empty list of used
|
||||||
|
// plugins because we can't be certain about their actual usage. For example,
|
||||||
|
// if a macro uses a plugin's field, we can't be sure which plugin actually
|
||||||
|
// is used until we resolve the macro ref in a rule providing a source for
|
||||||
|
// disambiguation.
|
||||||
|
out["details"]["plugins"] = Json::arrayValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_engine::get_json_details(
|
void falco_engine::get_json_details(
|
||||||
Json::Value& out,
|
Json::Value& out,
|
||||||
const rule_loader::list_info& l) const
|
const falco_list& l,
|
||||||
|
const rule_loader::list_info& info,
|
||||||
|
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
|
||||||
{
|
{
|
||||||
Json::Value list_info;
|
Json::Value list_info;
|
||||||
list_info["name"] = l.name;
|
list_info["name"] = l.name;
|
||||||
|
|
||||||
|
// note: the syntactic definitions still has the list refs unresolved
|
||||||
Json::Value items = Json::arrayValue;
|
Json::Value items = Json::arrayValue;
|
||||||
Json::Value lists = Json::arrayValue;
|
Json::Value lists = Json::arrayValue;
|
||||||
for(const auto &i : l.items)
|
for(const auto &i : info.items)
|
||||||
{
|
{
|
||||||
if(m_rule_collector.lists().at(i) != nullptr)
|
// if an item is present in the syntactic def of a list, but not
|
||||||
|
// on the compiled_items of the same list, then we can assume it
|
||||||
|
// being a resolved list ref
|
||||||
|
if(std::find(l.items.begin(), l.items.end(), i) == l.items.end())
|
||||||
{
|
{
|
||||||
lists.append(i);
|
lists.append(i);
|
||||||
continue;
|
continue;
|
||||||
@ -791,62 +835,32 @@ void falco_engine::get_json_details(
|
|||||||
|
|
||||||
list_info["items"] = items;
|
list_info["items"] = items;
|
||||||
out["info"] = list_info;
|
out["info"] = list_info;
|
||||||
|
out["details"]["used"] = l.used;
|
||||||
out["details"]["lists"] = lists;
|
out["details"]["lists"] = lists;
|
||||||
}
|
out["details"]["items_compiled"] = sequence_to_json_array(l.items);
|
||||||
|
out["details"]["plugins"] = Json::arrayValue; // always empty
|
||||||
void falco_engine::get_json_filter_details(
|
|
||||||
Json::Value& out,
|
|
||||||
const filter_details& details) const
|
|
||||||
{
|
|
||||||
Json::Value macros = Json::arrayValue;
|
|
||||||
for(const auto &m : details.macros)
|
|
||||||
{
|
|
||||||
macros.append(m);
|
|
||||||
}
|
|
||||||
out["macros"] = macros;
|
|
||||||
|
|
||||||
Json::Value operators = Json::arrayValue;
|
|
||||||
for(const auto &o : details.operators)
|
|
||||||
{
|
|
||||||
operators.append(o);
|
|
||||||
}
|
|
||||||
out["operators"] = operators;
|
|
||||||
|
|
||||||
Json::Value condition_fields = Json::arrayValue;
|
|
||||||
for(const auto &f : details.fields)
|
|
||||||
{
|
|
||||||
condition_fields.append(f);
|
|
||||||
}
|
|
||||||
out["condition_fields"] = condition_fields;
|
|
||||||
|
|
||||||
Json::Value lists = Json::arrayValue;
|
|
||||||
for(const auto &l : details.lists)
|
|
||||||
{
|
|
||||||
lists.append(l);
|
|
||||||
}
|
|
||||||
out["lists"] = lists;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_engine::get_json_evt_types(
|
void falco_engine::get_json_evt_types(
|
||||||
Json::Value& out,
|
Json::Value& out,
|
||||||
const std::string& source,
|
const std::string& source,
|
||||||
const filter_details& details) const
|
libsinsp::filter::ast::expr* ast) const
|
||||||
{
|
{
|
||||||
out = Json::arrayValue;
|
// note: this duplicates part of the logic of evttype_index_ruleset,
|
||||||
for (const auto& n : details.evtnames)
|
// not good but it's our best option for now
|
||||||
|
if (source.empty() || source == falco_common::syscall_source)
|
||||||
{
|
{
|
||||||
out.append(n);
|
auto evtcodes = libsinsp::filter::ast::ppm_event_codes(ast);
|
||||||
|
evtcodes.insert(ppm_event_code::PPME_ASYNCEVENT_E);
|
||||||
|
auto syscodes = libsinsp::filter::ast::ppm_sc_codes(ast);
|
||||||
|
auto syscodes_to_evt_names = libsinsp::events::sc_set_to_event_names(syscodes);
|
||||||
|
auto evtcodes_to_evt_names = libsinsp::events::event_set_to_names(evtcodes, false);
|
||||||
|
out = sequence_to_json_array(unordered_set_union(syscodes_to_evt_names, evtcodes_to_evt_names));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// plugin-implemented sources always match pluginevent.
|
|
||||||
// note: macros have no source and can potentially be referenced in a rule
|
|
||||||
// used for a plugin-implemented source.
|
|
||||||
if(source.empty() || source != falco_common::syscall_source)
|
|
||||||
{
|
{
|
||||||
for (const auto& n : libsinsp::events::event_set_to_names({PPME_PLUGINEVENT_E}, false))
|
out = sequence_to_json_array(libsinsp::events::event_set_to_names(
|
||||||
{
|
{ppm_event_code::PPME_PLUGINEVENT_E, ppm_event_code::PPME_ASYNCEVENT_E}));
|
||||||
out.append(n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,21 +306,22 @@ private:
|
|||||||
void get_json_details(
|
void get_json_details(
|
||||||
Json::Value& out,
|
Json::Value& out,
|
||||||
const falco_rule& r,
|
const falco_rule& r,
|
||||||
const rule_loader::rule_info& ri,
|
const rule_loader::rule_info& info,
|
||||||
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
|
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
|
||||||
void get_json_details(
|
void get_json_details(
|
||||||
Json::Value& out,
|
Json::Value& out,
|
||||||
const rule_loader::macro_info& m) const;
|
const falco_macro& m,
|
||||||
|
const rule_loader::macro_info& info,
|
||||||
|
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
|
||||||
void get_json_details(
|
void get_json_details(
|
||||||
Json::Value& out,
|
Json::Value& out,
|
||||||
const rule_loader::list_info& l) const;
|
const falco_list& l,
|
||||||
void get_json_filter_details(
|
const rule_loader::list_info& info,
|
||||||
Json::Value& out,
|
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
|
||||||
const filter_details& details) const;
|
|
||||||
void get_json_evt_types(
|
void get_json_evt_types(
|
||||||
Json::Value& out,
|
Json::Value& out,
|
||||||
const std::string& source,
|
const std::string& source,
|
||||||
const filter_details& details) const;
|
libsinsp::filter::ast::expr* ast) const;
|
||||||
void get_json_used_plugins(
|
void get_json_used_plugins(
|
||||||
Json::Value& out,
|
Json::Value& out,
|
||||||
const std::string& source,
|
const std::string& source,
|
||||||
|
Loading…
Reference in New Issue
Block a user