mirror of
https://github.com/falcosecurity/falco.git
synced 2025-09-05 00:31:38 +00:00
refactor(userspace/engine): update rule loader to use new filter_ruleset interface
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
@@ -160,10 +160,17 @@ void evttype_index_ruleset::add(
|
|||||||
sinsp_filter_compiler compiler(m_filter_factory, condition.get());
|
sinsp_filter_compiler compiler(m_filter_factory, condition.get());
|
||||||
shared_ptr<gen_event_filter> filter(compiler.compile());
|
shared_ptr<gen_event_filter> filter(compiler.compile());
|
||||||
std::shared_ptr<filter_wrapper> wrap(new filter_wrapper());
|
std::shared_ptr<filter_wrapper> wrap(new filter_wrapper());
|
||||||
filter_evttype_resolver resolver;
|
|
||||||
wrap->rule = rule;
|
wrap->rule = rule;
|
||||||
wrap->filter = filter;
|
wrap->filter = filter;
|
||||||
resolver.evttypes(condition, wrap->evttypes);
|
if(rule.source == falco_common::syscall_source)
|
||||||
|
{
|
||||||
|
filter_evttype_resolver resolver;
|
||||||
|
resolver.evttypes(condition, wrap->evttypes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wrap->evttypes = { ppm_event_type::PPME_PLUGINEVENT_E };
|
||||||
|
}
|
||||||
m_filters.insert(wrap);
|
m_filters.insert(wrap);
|
||||||
}
|
}
|
||||||
catch (const sinsp_exception& e)
|
catch (const sinsp_exception& e)
|
||||||
|
@@ -169,7 +169,7 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
|
|||||||
void falco_engine::load_rules(const string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version)
|
void falco_engine::load_rules(const string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version)
|
||||||
{
|
{
|
||||||
rule_loader::configuration cfg(rules_content);
|
rule_loader::configuration cfg(rules_content);
|
||||||
cfg.engine = this;
|
cfg.sources = m_sources;
|
||||||
cfg.min_priority = m_min_priority;
|
cfg.min_priority = m_min_priority;
|
||||||
cfg.output_extra = m_extra;
|
cfg.output_extra = m_extra;
|
||||||
cfg.replace_output_container_info = m_replace_container_info;
|
cfg.replace_output_container_info = m_replace_container_info;
|
||||||
@@ -179,7 +179,10 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
|
|||||||
bool success = reader.load(cfg, m_rule_loader);
|
bool success = reader.load(cfg, m_rule_loader);
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
clear_filters();
|
for (auto &s : m_sources)
|
||||||
|
{
|
||||||
|
s.ruleset->clear();
|
||||||
|
}
|
||||||
m_rules.clear();
|
m_rules.clear();
|
||||||
success = m_rule_loader.compile(cfg, m_rules);
|
success = m_rule_loader.compile(cfg, m_rules);
|
||||||
}
|
}
|
||||||
|
@@ -48,22 +48,6 @@ static void paren_item(string& e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_field_defined(
|
|
||||||
falco_engine *engine, const string& source, string field)
|
|
||||||
{
|
|
||||||
auto factory = engine->get_filter_factory(source);
|
|
||||||
if(factory)
|
|
||||||
{
|
|
||||||
auto *chk = factory->new_filtercheck(field.c_str());
|
|
||||||
if (chk)
|
|
||||||
{
|
|
||||||
delete(chk);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool is_operator_defined(const string& op)
|
static inline bool is_operator_defined(const string& op)
|
||||||
{
|
{
|
||||||
auto ops = libsinsp::filter::parser::supported_operators();
|
auto ops = libsinsp::filter::parser::supported_operators();
|
||||||
@@ -76,13 +60,12 @@ static inline bool is_operator_for_list(const string& op)
|
|||||||
return find(ops.begin(), ops.end(), op) != ops.end();
|
return find(ops.begin(), ops.end(), op) != ops.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_format_valid(
|
static bool is_format_valid(const falco_source& source, string fmt, string& err)
|
||||||
falco_engine* e, const string& src, const string& fmt, string& err)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
shared_ptr<gen_event_formatter> formatter;
|
shared_ptr<gen_event_formatter> formatter;
|
||||||
formatter = e->create_formatter(src, fmt);
|
formatter = source.formatter_factory->create_formatter(fmt);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch(exception &e)
|
catch(exception &e)
|
||||||
@@ -118,9 +101,8 @@ static inline void append_info(T* prev, T& info, uint32_t id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void validate_exception_info(
|
static void validate_exception_info(
|
||||||
rule_loader::configuration& cfg,
|
const falco_source& source,
|
||||||
rule_loader::rule_exception_info &ex,
|
rule_loader::rule_exception_info &ex)
|
||||||
const string& source)
|
|
||||||
{
|
{
|
||||||
if (ex.fields.is_list)
|
if (ex.fields.is_list)
|
||||||
{
|
{
|
||||||
@@ -133,7 +115,7 @@ static void validate_exception_info(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
THROW(ex.fields.items.size() != ex.comps.items.size(),
|
THROW(ex.fields.items.size() != ex.comps.items.size(),
|
||||||
"Rule exception item " + ex.name
|
"Rule exception item " + ex.name
|
||||||
+ ": fields and comps lists must have equal length");
|
+ ": fields and comps lists must have equal length");
|
||||||
for (auto &v : ex.comps.items)
|
for (auto &v : ex.comps.items)
|
||||||
{
|
{
|
||||||
@@ -143,7 +125,7 @@ static void validate_exception_info(
|
|||||||
}
|
}
|
||||||
for (auto &v : ex.fields.items)
|
for (auto &v : ex.fields.items)
|
||||||
{
|
{
|
||||||
THROW(!is_field_defined(cfg.engine, source, v.item),
|
THROW(!source.is_field_defined(v.item),
|
||||||
"Rule exception item " + ex.name + ": field name "
|
"Rule exception item " + ex.name + ": field name "
|
||||||
+ v.item + " is not a supported filter field");
|
+ v.item + " is not a supported filter field");
|
||||||
}
|
}
|
||||||
@@ -160,7 +142,7 @@ static void validate_exception_info(
|
|||||||
THROW(!is_operator_defined(ex.comps.item),
|
THROW(!is_operator_defined(ex.comps.item),
|
||||||
"Rule exception item " + ex.name + ": comparison operator "
|
"Rule exception item " + ex.name + ": comparison operator "
|
||||||
+ ex.comps.item + " is not a supported comparison operator");
|
+ ex.comps.item + " is not a supported comparison operator");
|
||||||
THROW(!is_field_defined(cfg.engine, source, ex.fields.item),
|
THROW(!source.is_field_defined(ex.fields.item),
|
||||||
"Rule exception item " + ex.name + ": field name "
|
"Rule exception item " + ex.name + ": field name "
|
||||||
+ ex.fields.item + " is not a supported filter field");
|
+ ex.fields.item + " is not a supported filter field");
|
||||||
}
|
}
|
||||||
@@ -365,37 +347,11 @@ static shared_ptr<ast::expr> parse_condition(
|
|||||||
}
|
}
|
||||||
catch (const sinsp_exception& e)
|
catch (const sinsp_exception& e)
|
||||||
{
|
{
|
||||||
throw falco_exception("Compilation error when compiling \""
|
throw falco_exception("Compilation error when compiling \""
|
||||||
+ condition + "\": " + to_string(p.get_pos().col) + ": " + e.what());
|
+ condition + "\": " + to_string(p.get_pos().col) + ": " + e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static shared_ptr<gen_event_filter> compile_condition(
|
|
||||||
falco_engine* engine,
|
|
||||||
uint32_t id,
|
|
||||||
shared_ptr<ast::expr> cnd,
|
|
||||||
string src,
|
|
||||||
string& err)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto factory = engine->get_filter_factory(src);
|
|
||||||
sinsp_filter_compiler compiler(factory, cnd.get());
|
|
||||||
compiler.set_check_id(id);
|
|
||||||
shared_ptr<gen_event_filter> ret(compiler.compile());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
catch (const sinsp_exception& e)
|
|
||||||
{
|
|
||||||
err = e.what();
|
|
||||||
}
|
|
||||||
catch (const falco_exception& e)
|
|
||||||
{
|
|
||||||
err = e.what();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void apply_output_substitutions(
|
static void apply_output_substitutions(
|
||||||
rule_loader::configuration& cfg,
|
rule_loader::configuration& cfg,
|
||||||
string& out)
|
string& out)
|
||||||
@@ -457,7 +413,7 @@ void rule_loader::append(configuration& cfg, list_info& info)
|
|||||||
|
|
||||||
void rule_loader::define(configuration& cfg, macro_info& info)
|
void rule_loader::define(configuration& cfg, macro_info& info)
|
||||||
{
|
{
|
||||||
if (!cfg.engine->is_source_valid(info.source))
|
if (!cfg.sources.at(info.source))
|
||||||
{
|
{
|
||||||
cfg.warnings.push_back("Macro " + info.name
|
cfg.warnings.push_back("Macro " + info.name
|
||||||
+ ": warning (unknown-source): unknown source "
|
+ ": warning (unknown-source): unknown source "
|
||||||
@@ -484,7 +440,8 @@ void rule_loader::append(configuration& cfg, macro_info& info)
|
|||||||
|
|
||||||
void rule_loader::define(configuration& cfg, rule_info& info)
|
void rule_loader::define(configuration& cfg, rule_info& info)
|
||||||
{
|
{
|
||||||
if (!cfg.engine->is_source_valid(info.source))
|
auto source = cfg.sources.at(info.source);
|
||||||
|
if (!source)
|
||||||
{
|
{
|
||||||
cfg.warnings.push_back("Rule " + info.name
|
cfg.warnings.push_back("Rule " + info.name
|
||||||
+ ": warning (unknown-source): unknown source "
|
+ ": warning (unknown-source): unknown source "
|
||||||
@@ -500,7 +457,7 @@ void rule_loader::define(configuration& cfg, rule_info& info)
|
|||||||
{
|
{
|
||||||
THROW(!ex.fields.is_valid(), "Rule exception item "
|
THROW(!ex.fields.is_valid(), "Rule exception item "
|
||||||
+ ex.name + ": must have fields property with a list of fields");
|
+ ex.name + ": must have fields property with a list of fields");
|
||||||
validate_exception_info(cfg, ex, info.source);
|
validate_exception_info(*source, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
define_info(m_rule_infos, info, m_cur_index++);
|
define_info(m_rule_infos, info, m_cur_index++);
|
||||||
@@ -514,6 +471,11 @@ void rule_loader::append(configuration& cfg, rule_info& info)
|
|||||||
THROW(info.cond.empty() && info.exceptions.empty(),
|
THROW(info.cond.empty() && info.exceptions.empty(),
|
||||||
"Appended rule must have exceptions or condition property");
|
"Appended rule must have exceptions or condition property");
|
||||||
|
|
||||||
|
auto source = cfg.sources.at(prev->source);
|
||||||
|
// note: this is not supposed to happen
|
||||||
|
THROW(!source, "Rule " + prev->name
|
||||||
|
+ ": error (unknown-source): unknown source " + prev->source);
|
||||||
|
|
||||||
if (!info.cond.empty())
|
if (!info.cond.empty())
|
||||||
{
|
{
|
||||||
prev->cond += " ";
|
prev->cond += " ";
|
||||||
@@ -531,7 +493,7 @@ void rule_loader::append(configuration& cfg, rule_info& info)
|
|||||||
+ ex.name + ": must have fields property with a list of fields");
|
+ ex.name + ": must have fields property with a list of fields");
|
||||||
THROW(ex.values.empty(), "Rule exception new item "
|
THROW(ex.values.empty(), "Rule exception new item "
|
||||||
+ ex.name + ": must have fields property with a list of values");
|
+ ex.name + ": must have fields property with a list of values");
|
||||||
validate_exception_info(cfg, ex, prev->source);
|
validate_exception_info(*source, ex);
|
||||||
prev->exceptions.push_back(ex);
|
prev->exceptions.push_back(ex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -649,9 +611,15 @@ void rule_loader::compile_rule_infos(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto source = cfg.sources.at(r.source);
|
||||||
|
// note: this is not supposed to happen
|
||||||
|
THROW(!source, "Rule " + r.name
|
||||||
|
+ ": error (unknown-source): unknown source " + r.source);
|
||||||
|
|
||||||
// build filter AST by parsing the condition, building exceptions,
|
// build filter AST by parsing the condition, building exceptions,
|
||||||
// and resolving lists and macros
|
// and resolving lists and macros
|
||||||
falco_rule rule;
|
falco_rule rule;
|
||||||
|
|
||||||
condition = r.cond;
|
condition = r.cond;
|
||||||
if (!r.exceptions.empty())
|
if (!r.exceptions.empty())
|
||||||
{
|
{
|
||||||
@@ -679,7 +647,8 @@ void rule_loader::compile_rule_infos(
|
|||||||
{
|
{
|
||||||
apply_output_substitutions(cfg, rule.output);
|
apply_output_substitutions(cfg, rule.output);
|
||||||
}
|
}
|
||||||
THROW(!is_format_valid(cfg.engine, r.source, rule.output, err),
|
|
||||||
|
THROW(!is_format_valid(cfg.engine, r.source, rule.output, err),
|
||||||
"Invalid output format '" + rule.output + "': '" + err + "'");
|
"Invalid output format '" + rule.output + "': '" + err + "'");
|
||||||
|
|
||||||
// construct rule definition and compile it to a filter
|
// construct rule definition and compile it to a filter
|
||||||
@@ -688,13 +657,18 @@ void rule_loader::compile_rule_infos(
|
|||||||
rule.description = r.desc;
|
rule.description = r.desc;
|
||||||
rule.priority = r.priority;
|
rule.priority = r.priority;
|
||||||
rule.tags = r.tags;
|
rule.tags = r.tags;
|
||||||
// note: indexes are 0-based, but 0 is not an acceptable rule_id
|
try
|
||||||
auto id = out.insert(rule, rule.name) + 1;
|
|
||||||
auto filter = compile_condition(cfg.engine, id, ast, rule.source, err);
|
|
||||||
if (!filter)
|
|
||||||
{
|
{
|
||||||
if (r.skip_if_unknown_filter
|
auto rule_id = out.insert(rule, rule.name);
|
||||||
&& err.find("nonexistent field") != string::npos)
|
out.at(rule_id)->id = rule_id;
|
||||||
|
source->ruleset->add(*out.at(rule_id), ast);
|
||||||
|
source->ruleset->enable(rule.name, false, r.enabled);
|
||||||
|
}
|
||||||
|
catch (falco_exception& e)
|
||||||
|
{
|
||||||
|
string err = e.what();
|
||||||
|
if (err.find("nonexistent field") != string::npos
|
||||||
|
&& r.skip_if_unknown_filter)
|
||||||
{
|
{
|
||||||
cfg.warnings.push_back(
|
cfg.warnings.push_back(
|
||||||
"Rule " + rule.name + ": warning (unknown-field):");
|
"Rule " + rule.name + ": warning (unknown-field):");
|
||||||
@@ -705,7 +679,7 @@ void rule_loader::compile_rule_infos(
|
|||||||
throw falco_exception("Rule " + rule.name + ": error " + err);
|
throw falco_exception("Rule " + rule.name + ": error " + err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate set of event types and emit an special warning
|
// populate set of event types and emit an special warning
|
||||||
set<uint16_t> evttypes = { ppm_event_type::PPME_PLUGINEVENT_E };
|
set<uint16_t> evttypes = { ppm_event_type::PPME_PLUGINEVENT_E };
|
||||||
if(rule.source == falco_common::syscall_source)
|
if(rule.source == falco_common::syscall_source)
|
||||||
@@ -721,10 +695,6 @@ void rule_loader::compile_rule_infos(
|
|||||||
+ " This has a significant performance penalty.");
|
+ " This has a significant performance penalty.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add rule and its filter in the engine
|
|
||||||
cfg.engine->add_filter(filter, rule.name, rule.source, evttypes, rule.tags);
|
|
||||||
cfg.engine->enable_rule(rule.name, r.enabled);
|
|
||||||
}
|
}
|
||||||
catch (exception& e)
|
catch (exception& e)
|
||||||
{
|
{
|
||||||
@@ -769,4 +739,4 @@ bool rule_loader::compile(configuration& cfg, indexed_vector<falco_rule>& out) c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -21,11 +21,9 @@ limitations under the License.
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <yaml-cpp/yaml.h>
|
#include <yaml-cpp/yaml.h>
|
||||||
#include "falco_rule.h"
|
#include "falco_rule.h"
|
||||||
|
#include "falco_source.h"
|
||||||
#include "indexed_vector.h"
|
#include "indexed_vector.h"
|
||||||
|
|
||||||
// todo(jasondellaluce): remove this cyclic dependency
|
|
||||||
class falco_engine;
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Ruleset loader of the falco engine
|
\brief Ruleset loader of the falco engine
|
||||||
@@ -73,9 +71,9 @@ public:
|
|||||||
std::string output_extra;
|
std::string output_extra;
|
||||||
bool replace_output_container_info;
|
bool replace_output_container_info;
|
||||||
falco_common::priority_type min_priority;
|
falco_common::priority_type min_priority;
|
||||||
|
indexed_vector<falco_source> sources;
|
||||||
std::vector<std::string> warnings;
|
std::vector<std::string> warnings;
|
||||||
std::vector<std::string> errors;
|
std::vector<std::string> errors;
|
||||||
falco_engine* engine;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@@ -16,11 +16,11 @@ limitations under the License.
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "falco_rule.h"
|
||||||
|
#include <filter/ast.h>
|
||||||
#include <filter.h>
|
#include <filter.h>
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#include <gen_filter.h>
|
#include <gen_filter.h>
|
||||||
#include <filter/ast.h>
|
|
||||||
#include "falco_rule.h"
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Represents a manager for rulesets.A ruleset represents a set of
|
\brief Represents a manager for rulesets.A ruleset represents a set of
|
||||||
|
Reference in New Issue
Block a user