diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index e4ff682a..ec3bdcaf 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -462,29 +462,23 @@ void falco_engine::describe_rule(std::string *rule, bool json) const Json::FastWriter writer; 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 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) { + // In this case we build json information about + // all rules, macros and lists Json::Value output; + // Store information about rules Json::Value rules_array = Json::arrayValue; for(const auto& r : m_rules) { - auto json_details = get_json_rule_details(r, details); - rules_array.append(json_details); + auto ri = m_rule_collector.rules().at(r.name); + Json::Value rule; + get_json_details(r, *ri, rule); + + // Append to rule array + rules_array.append(rule); } output["rules"] = rules_array; @@ -492,7 +486,9 @@ void falco_engine::describe_rule(std::string *rule, bool json) const Json::Value macros_array; 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; @@ -501,16 +497,8 @@ void falco_engine::describe_rule(std::string *rule, bool json) const for(const auto &l : m_rule_collector.lists()) { Json::Value list; - list["name"] = l.name; - - Json::Value items = Json::arrayValue; - for(const auto& i : l.items) - { - items.append(i); - } - list["items"] = items; - - lists_array.append(list); + get_json_details(l, list); + lists_array.append(list); } output["lists"] = lists_array; @@ -518,30 +506,49 @@ void falco_engine::describe_rule(std::string *rule, bool json) const } else { - auto r = m_rules.at(*rule); - if(r == nullptr) + // build json information for just the specified rule + auto ri = m_rule_collector.rules().at(*rule); + if(ri == nullptr) { throw falco_exception("Rule \"" + *rule + "\" is not loaded"); } - - auto json_details = get_json_rule_details(*r, details); - json_str = writer.write(json_details); + auto r = m_rules.at(ri->name); + Json::Value rule; + get_json_details(*r, *ri, rule); + json_str = writer.write(rule); } 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 - // 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(); + Json::Value rule_info; - // Resolve the AST details - filter_details_resolver resolver; - resolver.run(ast.get(), details); + // Fill general rule information + rule_info["name"] = r.name; + 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 auto insp = new sinsp; @@ -549,15 +556,110 @@ Json::Value falco_engine::get_json_rule_details(const falco_rule& r, filter_deta std::vector out_fields; fmt.get_field_names(out_fields); 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 - Json::Value output; + // Get fields from exceptions + 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; - output["description"] = r.description; - output["priority"] = format_priority(r.priority, false); - output["output"] = r.output; - output["enabled"] = rule_info->enabled; + // Get operators from exceptions + Json::Value exception_operators = Json::arrayValue; + for(const auto &e : ri.exceptions) + { + 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; 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; - 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; for(const auto &l : details.lists) { lists.append(l); } 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 evts; - for(const auto &e : rule_info->evttypes) + for(const auto &e : evttypes) { auto evt_info = libsinsp::events::info(e); auto res = evts.insert(std::string(evt_info->name)); 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 { std::string out; diff --git a/userspace/engine/falco_engine.h b/userspace/engine/falco_engine.h index dbb41985..7566a464 100644 --- a/userspace/engine/falco_engine.h +++ b/userspace/engine/falco_engine.h @@ -299,8 +299,18 @@ private: // inline bool should_drop_evt() const; - // Retrieve details of a rule in json format - Json::Value get_json_rule_details(const falco_rule& r, filter_details& details) const; + // Retrieve json details from rules, macros, lists + 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; indexed_vector m_rules; diff --git a/userspace/engine/filter_details_resolver.cpp b/userspace/engine/filter_details_resolver.cpp index cb2b2a9e..c28e9e13 100644 --- a/userspace/engine/filter_details_resolver.cpp +++ b/userspace/engine/filter_details_resolver.cpp @@ -92,8 +92,5 @@ void filter_details_resolver::visitor::visit(ast::value_expr* e) return; } - m_details.macros.insert(it->first); - - // Recursively visit the macro AST as well - it->second->accept(this); + m_details.macros.insert(e->value); } \ No newline at end of file diff --git a/userspace/engine/filter_details_resolver.h b/userspace/engine/filter_details_resolver.h index 3e096373..743566b2 100644 --- a/userspace/engine/filter_details_resolver.h +++ b/userspace/engine/filter_details_resolver.h @@ -24,7 +24,7 @@ limitations under the License. struct filter_details { // input macros and lists - std::unordered_map> known_macros; + std::unordered_set known_macros; std::unordered_set known_lists; // output details diff --git a/userspace/engine/rule_loader.h b/userspace/engine/rule_loader.h index 95d2e923..c0c30522 100644 --- a/userspace/engine/rule_loader.h +++ b/userspace/engine/rule_loader.h @@ -456,7 +456,6 @@ namespace rule_loader std::set tags; std::vector exceptions; falco_common::priority_type priority; - libsinsp::events::set evttypes; bool enabled; bool warn_evttypes; bool skip_if_unknown_filter; diff --git a/userspace/engine/rule_loader_compiler.cpp b/userspace/engine/rule_loader_compiler.cpp index f8719f38..6be6b219 100644 --- a/userspace/engine/rule_loader_compiler.cpp +++ b/userspace/engine/rule_loader_compiler.cpp @@ -386,11 +386,7 @@ void rule_loader::compiler::compile_rule_infos( std::string err, condition; std::set warn_codes; filter_warning_resolver warn_resolver; - - // 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&>(col.rules())) + for (auto &r : col.rules()) { // skip the rule if below the minimum 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.", r.ctx); } - r.evttypes = evttypes; } } }