update(userspace/engine): better modularize the code for getting json details

Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
This commit is contained in:
Lorenzo Susini
2023-05-18 06:58:43 +00:00
committed by poiana
parent e11b4c4430
commit 1195b1e7f0
6 changed files with 176 additions and 93 deletions

View File

@@ -462,29 +462,23 @@ void falco_engine::describe_rule(std::string *rule, bool json) const
Json::FastWriter writer; Json::FastWriter writer;
std::string json_str; std::string json_str;
filter_details details;
for(const auto &m : m_rule_collector.macros())
{
// Assumption: no exception because rules have already been loaded.
auto cond_ast = libsinsp::filter::parser(m.cond).parse();
std::shared_ptr<libsinsp::filter::ast::expr> cond_ast_ptr = std::move(cond_ast);
details.known_macros[m.name] = cond_ast_ptr;
}
for(const auto &l : m_rule_collector.lists())
{
details.known_lists.insert(l.name);
}
if(!rule) if(!rule)
{ {
// In this case we build json information about
// all rules, macros and lists
Json::Value output; Json::Value output;
// 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 : m_rules)
{ {
auto json_details = get_json_rule_details(r, details); auto ri = m_rule_collector.rules().at(r.name);
rules_array.append(json_details); Json::Value rule;
get_json_details(r, *ri, rule);
// Append to rule array
rules_array.append(rule);
} }
output["rules"] = rules_array; output["rules"] = rules_array;
@@ -492,7 +486,9 @@ void falco_engine::describe_rule(std::string *rule, bool json) const
Json::Value macros_array; Json::Value macros_array;
for(const auto &m : m_rule_collector.macros()) for(const auto &m : m_rule_collector.macros())
{ {
macros_array.append(m.name); Json::Value macro;
get_json_details(m, macro);
macros_array.append(macro);
} }
output["macros"] = macros_array; output["macros"] = macros_array;
@@ -501,16 +497,8 @@ void falco_engine::describe_rule(std::string *rule, bool json) const
for(const auto &l : m_rule_collector.lists()) for(const auto &l : m_rule_collector.lists())
{ {
Json::Value list; Json::Value list;
list["name"] = l.name; get_json_details(l, list);
lists_array.append(list);
Json::Value items = Json::arrayValue;
for(const auto& i : l.items)
{
items.append(i);
}
list["items"] = items;
lists_array.append(list);
} }
output["lists"] = lists_array; output["lists"] = lists_array;
@@ -518,30 +506,49 @@ void falco_engine::describe_rule(std::string *rule, bool json) const
} }
else else
{ {
auto r = m_rules.at(*rule); // build json information for just the specified rule
if(r == nullptr) auto ri = m_rule_collector.rules().at(*rule);
if(ri == nullptr)
{ {
throw falco_exception("Rule \"" + *rule + "\" is not loaded"); throw falco_exception("Rule \"" + *rule + "\" is not loaded");
} }
auto r = m_rules.at(ri->name);
auto json_details = get_json_rule_details(*r, details); Json::Value rule;
json_str = writer.write(json_details); get_json_details(*r, *ri, rule);
json_str = writer.write(rule);
} }
fprintf(stdout, "%s", json_str.c_str()); fprintf(stdout, "%s", json_str.c_str());
} }
Json::Value falco_engine::get_json_rule_details(const falco_rule& r, filter_details& details) const void falco_engine::get_json_details(const falco_rule &r,
const rule_loader::rule_info &ri,
Json::Value &rule) const
{ {
// Parse rule condition and build the AST Json::Value rule_info;
// Assumption: the parsing will not throw an exception because
// rules have already been loaded.
auto rule_info = m_rule_collector.rules().at(r.name);
auto ast = libsinsp::filter::parser(rule_info->cond).parse();
// Resolve the AST details // Fill general rule information
filter_details_resolver resolver; rule_info["name"] = r.name;
resolver.run(ast.get(), details); rule_info["condition"] = ri.cond;
rule_info["priority"] = format_priority(r.priority, false);
rule_info["output"] = r.output;
rule_info["description"] = r.description;
rule_info["enabled"] = ri.enabled;
rule_info["source"] = r.source;
Json::Value tags = Json::arrayValue;
for(const auto &t : ri.tags)
{
tags.append(t);
}
rule_info["tags"] = tags;
rule["info"] = rule_info;
// Parse rule condition and build the AST
// Assumption: no exception because rules have already been loaded.
auto ast = libsinsp::filter::parser(ri.cond).parse();
Json::Value json_details;
get_json_details(ast.get(), json_details);
rule["details"] = json_details;
// Get fields from output string // Get fields from output string
auto insp = new sinsp; auto insp = new sinsp;
@@ -549,15 +556,110 @@ Json::Value falco_engine::get_json_rule_details(const falco_rule& r, filter_deta
std::vector<std::string> out_fields; std::vector<std::string> out_fields;
fmt.get_field_names(out_fields); fmt.get_field_names(out_fields);
delete insp; delete insp;
Json::Value outputFields = Json::arrayValue;
for(const auto &of : out_fields)
{
outputFields.append(of);
}
rule["details"]["outputFields"] = outputFields;
// Build JSON object for the output // Get fields from exceptions
Json::Value output; Json::Value exception_fields = Json::arrayValue;
for(const auto &f : r.exception_fields)
{
exception_fields.append(f);
}
rule["details"]["exceptionFields"] = exception_fields;
output["name"] = r.name; // Get operators from exceptions
output["description"] = r.description; Json::Value exception_operators = Json::arrayValue;
output["priority"] = format_priority(r.priority, false); for(const auto &e : ri.exceptions)
output["output"] = r.output; {
output["enabled"] = rule_info->enabled; if(e.comps.is_list)
{
for(const auto& c : e.comps.items)
{
exception_operators.append(c.item);
}
}
else
{
exception_operators.append(e.comps.item);
}
}
rule["details"]["exceptionOperators"] = exception_operators;
if(ri.source == falco_common::syscall_source)
{
// Store event types
Json::Value events;
get_json_evt_types(ast.get(), events);
rule["details"]["events"] = events;
}
}
void falco_engine::get_json_details(const rule_loader::macro_info& m,
Json::Value& macro) const
{
Json::Value macro_info;
macro_info["name"] = m.name;
macro_info["condition"] = m.cond;
macro["info"] = macro_info;
// Assumption: no exception because rules have already been loaded.
auto ast = libsinsp::filter::parser(m.cond).parse();
Json::Value json_details;
get_json_details(ast.get(), json_details);
macro["details"] = json_details;
// Store event types
Json::Value events;
get_json_evt_types(ast.get(), events);
macro["details"]["events"] = events;
}
void falco_engine::get_json_details(const rule_loader::list_info& l,
Json::Value& list) const
{
Json::Value list_info;
list_info["name"] = l.name;
list["info"] = list_info;
Json::Value items = Json::arrayValue;
Json::Value lists = Json::arrayValue;
for(const auto &i : l.items)
{
if(m_rule_collector.lists().at(i) != nullptr)
{
lists.append(i);
continue;
}
items.append(i);
}
list["details"]["items"] = items;
list["details"]["lists"] = lists;
}
void falco_engine::get_json_details(libsinsp::filter::ast::expr* ast,
Json::Value& output) const
{
filter_details details;
for(const auto &m : m_rule_collector.macros())
{
details.known_macros.insert(m.name);
}
for(const auto &l : m_rule_collector.lists())
{
details.known_lists.insert(l.name);
}
// Resolve the AST details
filter_details_resolver resolver;
resolver.run(ast, details);
Json::Value macros = Json::arrayValue; Json::Value macros = Json::arrayValue;
for(const auto &m : details.macros) for(const auto &m : details.macros)
@@ -580,57 +682,37 @@ Json::Value falco_engine::get_json_rule_details(const falco_rule& r, filter_deta
} }
output["conditionFields"] = condition_fields; output["conditionFields"] = condition_fields;
Json::Value output_fields = Json::arrayValue;
for(const auto &f : out_fields)
{
output_fields.append(f);
}
output["outputFields"] = output_fields;
Json::Value exception_fields = Json::arrayValue;
for(const auto &f : r.exception_fields)
{
exception_fields.append(f);
}
output["exceptionFields"] = exception_fields;
Json::Value lists = Json::arrayValue; Json::Value lists = Json::arrayValue;
for(const auto &l : details.lists) for(const auto &l : details.lists)
{ {
lists.append(l); lists.append(l);
} }
output["lists"] = lists; output["lists"] = lists;
details.reset();
}
if (rule_info->source == falco_common::syscall_source) void falco_engine::get_json_evt_types(libsinsp::filter::ast::expr* ast,
Json::Value& output) const
{
output = Json::arrayValue;
auto evttypes = libsinsp::filter::ast::ppm_event_codes(ast);
if(evttypes.size() != libsinsp::events::all_event_set().size())
{ {
Json::Value events = Json::arrayValue;
std::unordered_set<std::string> evts; std::unordered_set<std::string> evts;
for(const auto &e : rule_info->evttypes) for(const auto &e : evttypes)
{ {
auto evt_info = libsinsp::events::info(e); auto evt_info = libsinsp::events::info(e);
auto res = evts.insert(std::string(evt_info->name)); auto res = evts.insert(std::string(evt_info->name));
if(res.second) if(res.second)
{ {
events.append(evt_info->name); output.append(evt_info->name);
} }
} }
output["events"] = events;
} }
output["source"] = rule_info->source;
Json::Value tags = Json::arrayValue;
for(const auto &t : rule_info->tags)
{
tags.append(t);
}
output["tags"] = tags;
details.reset();
return output;
} }
void falco_engine::print_stats() const void falco_engine::print_stats() const
{ {
std::string out; std::string out;

View File

@@ -299,8 +299,18 @@ private:
// //
inline bool should_drop_evt() const; inline bool should_drop_evt() const;
// Retrieve details of a rule in json format // Retrieve json details from rules, macros, lists
Json::Value get_json_rule_details(const falco_rule& r, filter_details& details) const; void get_json_details(const falco_rule& r,
const rule_loader::rule_info& ri,
Json::Value& rule) const;
void get_json_details(const rule_loader::macro_info& m,
Json::Value& macro) const;
void get_json_details(const rule_loader::list_info& l,
Json::Value& list) const;
void get_json_details(libsinsp::filter::ast::expr* ast,
Json::Value& output) const;
void get_json_evt_types(libsinsp::filter::ast::expr* ast,
Json::Value& output) const;
rule_loader::collector m_rule_collector; rule_loader::collector m_rule_collector;
indexed_vector<falco_rule> m_rules; indexed_vector<falco_rule> m_rules;

View File

@@ -92,8 +92,5 @@ void filter_details_resolver::visitor::visit(ast::value_expr* e)
return; return;
} }
m_details.macros.insert(it->first); m_details.macros.insert(e->value);
// Recursively visit the macro AST as well
it->second->accept(this);
} }

View File

@@ -24,7 +24,7 @@ limitations under the License.
struct filter_details struct filter_details
{ {
// input macros and lists // input macros and lists
std::unordered_map<std::string, std::shared_ptr<libsinsp::filter::ast::expr>> known_macros; std::unordered_set<std::string> known_macros;
std::unordered_set<std::string> known_lists; std::unordered_set<std::string> known_lists;
// output details // output details

View File

@@ -456,7 +456,6 @@ namespace rule_loader
std::set<std::string> tags; std::set<std::string> tags;
std::vector<rule_exception_info> exceptions; std::vector<rule_exception_info> exceptions;
falco_common::priority_type priority; falco_common::priority_type priority;
libsinsp::events::set<ppm_event_code> evttypes;
bool enabled; bool enabled;
bool warn_evttypes; bool warn_evttypes;
bool skip_if_unknown_filter; bool skip_if_unknown_filter;

View File

@@ -386,11 +386,7 @@ void rule_loader::compiler::compile_rule_infos(
std::string err, condition; std::string err, condition;
std::set<falco::load_result::load_result::warning_code> warn_codes; std::set<falco::load_result::load_result::warning_code> warn_codes;
filter_warning_resolver warn_resolver; filter_warning_resolver warn_resolver;
for (auto &r : col.rules())
// note: cast away the const qualifier in the for loop
// this is needed because we want to store information about evttypes
// used by any rules, which might come in handy when describing rules.
for (auto &r : const_cast<indexed_vector<rule_info>&>(col.rules()))
{ {
// skip the rule if below the minimum priority // skip the rule if below the minimum priority
if (r.priority > cfg.min_priority) if (r.priority > cfg.min_priority)
@@ -509,7 +505,6 @@ void rule_loader::compiler::compile_rule_infos(
"Rule matches too many evt.type values. This has a significant performance penalty.", "Rule matches too many evt.type values. This has a significant performance penalty.",
r.ctx); r.ctx);
} }
r.evttypes = evttypes;
} }
} }
} }