Compare commits

..

5 Commits

Author SHA1 Message Date
Leonardo Grasso
359bd41b2e chore(userspace/falco): correct comment
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-08-09 13:15:43 +02:00
Leonardo Grasso
27fb674406 chore: cleanup Mesos references
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-08-09 11:18:36 +02:00
Leonardo Grasso
4b35d71c99 chore(userspace/falco): remove unused mesos_api var
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-08-09 11:15:35 +02:00
Leonardo Grasso
710d15a2fd chore(userspace/falco/app_actions): remove Mesos support
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-08-09 11:13:27 +02:00
Leonardo Grasso
3a445c6457 update!: remove --mesos-api and -pm command-line flags
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-08-09 11:12:30 +02:00
18 changed files with 145 additions and 376 deletions

View File

@@ -22,8 +22,6 @@
> /kind feature
> /kind release
> If contributing rules or changes to rules, please make sure to also uncomment one of the following line:
> /kind rule-update
@@ -48,8 +46,6 @@ Please remove the leading whitespace before the `/kind <>` you uncommented.
> /area proposals
> /area CI
<!--
Please remove the leading whitespace before the `/area <>` you uncommented.
-->

View File

@@ -1,17 +1,5 @@
# Change Log
## v0.32.2
Released on 2022-08-09
### Major Changes
### Bug Fixes
* fix: Added ARCH to bpf download URL [[#2142](https://github.com/falcosecurity/falco/pull/2142)] - [@eric-engberg](https://github.com/eric-engberg)
## v0.32.1
Released on 2022-07-11

View File

@@ -26,8 +26,8 @@ else()
# In case you want to test against another driver version (or branch, or commit) just pass the variable -
# ie., `cmake -DDRIVER_VERSION=dev ..`
if(NOT DRIVER_VERSION)
set(DRIVER_VERSION "d673b2722e8a730013bfe525eaa417945ef8b723")
set(DRIVER_CHECKSUM "SHA256=de7a2fb42da781d5b867f25a009cfdf8b03a1c12dc9a5d2abba08c7afb5a14d4")
set(DRIVER_VERSION "b4c198773bf05486e122f6d3f7f63be125242413")
set(DRIVER_CHECKSUM "SHA256=e85fa42a0b58ba21ca7efb38c20ce25207f4816245bdf154e6b9a037a1cce930")
endif()
# cd /path/to/build && cmake /path/to/source
@@ -45,4 +45,4 @@ set(DRIVER_NAME "falco")
set(DRIVER_PACKAGE_NAME "falco")
set(DRIVER_COMPONENT_NAME "falco-driver")
add_subdirectory(${DRIVER_SOURCE_DIR} ${PROJECT_BINARY_DIR}/driver)
add_subdirectory(${DRIVER_SOURCE_DIR} ${PROJECT_BINARY_DIR}/driver)

View File

@@ -27,8 +27,8 @@ else()
# In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable -
# ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "d673b2722e8a730013bfe525eaa417945ef8b723")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=de7a2fb42da781d5b867f25a009cfdf8b03a1c12dc9a5d2abba08c7afb5a14d4")
set(FALCOSECURITY_LIBS_VERSION "b4c198773bf05486e122f6d3f7f63be125242413")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=e85fa42a0b58ba21ca7efb38c20ce25207f4816245bdf154e6b9a037a1cce930")
endif()
# cd /path/to/build && cmake /path/to/source
@@ -84,4 +84,4 @@ endif()
include(driver)
include(libscap)
include(libsinsp)
include(libsinsp)

View File

@@ -511,7 +511,7 @@
# %container.info, without any leading term (file=%fd.name
# %container.info user=%user.name user_loginuid=%user.loginuid, and not file=%fd.name
# container=%container.info user=%user.name user_loginuid=%user.loginuid). The output will change
# based on the context and whether or not -pk/-pm/-pc was specified on
# based on the context and whether or not -pk/-pc was specified on
# the command line.
- macro: container
condition: (container.id != host)
@@ -2152,13 +2152,20 @@
# In some environments, any attempt by a interpreted program (perl,
# python, ruby, etc) to listen for incoming connections or perform
# outgoing connections might be suspicious. These rules are not
# enabled by default.
# enabled by default, but you can modify the following macros to
# enable them.
- macro: consider_interpreted_inbound
condition: (never_true)
- macro: consider_interpreted_outbound
condition: (never_true)
- rule: Interpreted procs inbound network activity
desc: Any inbound network activity performed by any interpreted program (perl, python, ruby, etc.)
condition: >
(inbound and interpreted_procs)
enabled: false
(inbound and consider_interpreted_inbound
and interpreted_procs)
output: >
Interpreted program received/listened for network traffic
(user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
@@ -2168,8 +2175,8 @@
- rule: Interpreted procs outbound network activity
desc: Any outbound network activity performed by any interpreted program (perl, python, ruby, etc.)
condition: >
(outbound and interpreted_procs)
enabled: false
(outbound and consider_interpreted_outbound
and interpreted_procs)
output: >
Interpreted program performed outgoing network connection
(user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
@@ -2355,7 +2362,10 @@
# This rule is not enabled by default, since this rule is for cloud environment(GCP, AWS and Azure) only.
# You can filter the container that you want to allow access to metadata by overwriting user_known_metadata_access macro.
# If you want to enable this rule, overwrite the first macro,
# And you can filter the container that you want to allow access to metadata by overwriting the second macro.
- macro: consider_metadata_access
condition: (never_true)
- macro: user_known_metadata_access
condition: (k8s.ns.name = "kube-system")
@@ -2364,8 +2374,7 @@
# metadata about the instance. The metadata could be used to get credentials by attackers.
- rule: Contact cloud metadata service from container
desc: Detect attempts to contact the Cloud Instance Metadata Service from a container
condition: outbound and fd.sip="169.254.169.254" and container and not user_known_metadata_access
enabled: false
condition: outbound and fd.sip="169.254.169.254" and container and consider_metadata_access and not user_known_metadata_access
output: Outbound connection to cloud instance metadata service (command=%proc.cmdline connection=%fd.name %container.info image=%container.image.repository:%container.image.tag)
priority: NOTICE
tags: [network, container, mitre_discovery]

View File

@@ -18,7 +18,6 @@ limitations under the License.
#include <unistd.h>
#include <string>
#include <fstream>
#include <functional>
#include <utility>
#include <sinsp.h>
@@ -172,7 +171,20 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
std::unique_ptr<load_result> res = load_rules(rules_content, no_name);
interpret_load_result(res, no_name, rules_content, verbose);
if(verbose)
{
// Here, verbose controls whether to additionally
// "log" e.g. print to stderr. What's logged is always
// non-verbose so it fits on a single line.
// todo(jasondellaluce): introduce a logging callback in Falco
fprintf(stderr, "%s\n", res->as_string(false).c_str());
}
if(!res->successful())
{
// The output here is always the full e.g. "verbose" output.
throw falco_exception(res->as_string(true).c_str());
}
}
std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_content, const std::string &name)
@@ -199,33 +211,44 @@ std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_c
void falco_engine::load_rules_file(const std::string &rules_filename, bool verbose, bool all_events)
{
std::string rules_content;
std::unique_ptr<load_result> res = load_rules_file(rules_filename);
read_file(rules_filename, rules_content);
if(verbose)
{
// Here, verbose controls whether to additionally
// "log" e.g. print to stderr. What's logged is always
// non-verbose so it fits on a single line.
// todo(jasondellaluce): introduce a logging callback in Falco
fprintf(stderr, "%s\n", res->as_string(false).c_str());
}
std::unique_ptr<load_result> res = load_rules(rules_content, rules_filename);
interpret_load_result(res, rules_filename, rules_content, verbose);
if(!res->successful())
{
// The output here is always the full e.g. "verbose" output.
throw falco_exception(res->as_string(true).c_str());
}
}
std::unique_ptr<load_result> falco_engine::load_rules_file(const string &rules_filename)
{
std::string rules_content;
ifstream is;
try {
read_file(rules_filename, rules_content);
}
catch (falco_exception &e)
is.open(rules_filename);
if (!is.is_open())
{
rule_loader::context ctx(rules_filename);
std::string empty;
std::unique_ptr<rule_loader::result> res(new rule_loader::result(rules_filename));
res->add_error(load_result::LOAD_ERR_FILE_READ, e.what(), ctx);
res->add_error(load_result::LOAD_ERR_FILE_READ, "Could not open for reading.", ctx, empty);
return std::move(res);
}
string rules_content((istreambuf_iterator<char>(is)),
istreambuf_iterator<char>());
return load_rules(rules_content, rules_filename);
}
@@ -403,44 +426,6 @@ bool falco_engine::is_source_valid(const std::string &source)
return m_sources.at(source) != nullptr;
}
void falco_engine::read_file(const std::string& filename, std::string& contents)
{
ifstream is;
is.open(filename);
if (!is.is_open())
{
throw falco_exception("Could not open " + filename + " for reading.");
}
contents.assign(istreambuf_iterator<char>(is),
istreambuf_iterator<char>());
}
void falco_engine::interpret_load_result(std::unique_ptr<load_result>& res,
const std::string& rules_filename,
const std::string& rules_content,
bool verbose)
{
falco::load_result::rules_contents_t rc = {{rules_filename, rules_content}};
if(!res->successful())
{
// The output here is always the full e.g. "verbose" output.
throw falco_exception(res->as_string(true, rc).c_str());
}
if(verbose && res->has_warnings())
{
// Here, verbose controls whether to additionally
// "log" e.g. print to stderr. What's logged is always
// non-verbose so it fits on a single line.
// todo(jasondellaluce): introduce a logging callback in Falco
fprintf(stderr, "%s\n", res->as_string(false, rc).c_str());
}
}
bool falco_engine::check_plugin_requirements(
const std::vector<plugin_version_requirement>& plugins,
std::string& err)

View File

@@ -145,7 +145,7 @@ public:
// of all output expressions. You can also choose to replace
// %container.info with the extra information or add it to the
// end of the expression. This is used in open source falco to
// add k8s/mesos/container information to outputs when
// add k8s/container information to outputs when
// available.
//
void set_extra(string &extra, bool replace_container_info);
@@ -233,17 +233,6 @@ public:
std::string& err);
private:
// Throws falco_exception if the file can not be read
void read_file(const std::string& filename, std::string& contents);
// For load_rules methods that throw exceptions on error,
// interpret a load_result and throw an exception if needed.
void interpret_load_result(std::unique_ptr<falco::load_result>& res,
const std::string& rules_filename,
const std::string& rules_content,
bool verbose);
indexed_vector<falco_source> m_sources;
falco_source* find_source(std::size_t index);

View File

@@ -16,7 +16,6 @@ limitations under the License.
#pragma once
#include <functional>
#include <string>
#include <nlohmann/json.hpp>
@@ -76,35 +75,20 @@ public:
// has_warnings() can both be true if there were only warnings.
virtual bool has_warnings() = 0;
// This represents a set of rules contents as a mapping from
// rules content name (usually filename) to rules content. The
// rules content is actually a reference to the actual string
// to avoid copies. Using reference_wrapper allows the
// reference to be held in the stl map (bare references can't
// be copied/assigned, but reference_wrappers can).
//
// It's used in the as_string/as_json() methods below.
typedef std::map<std::string, std::reference_wrapper<const std::string>> rules_contents_t;
// This contains a human-readable version of the result,
// suitable for display to end users.
//
// The provided rules_contents_t should map from content name
// to rules content (reference) for each rules_content that has
// been passed to rule_loader::compile() or
// rule_reader::load().
//
// When verbose is true, the returned value has full details
// on the result including document locations/context.
//
// When verbose is false, the returned value is a short string
// with the success value and a list of
// errors/warnings. Suitable for simple one-line display.
virtual const std::string& as_string(bool verbose, const rules_contents_t& contents) = 0;
virtual const std::string& as_string(bool verbose) = 0;
// This contains the full result structure as json, suitable
// for automated parsing/interpretation downstream.
virtual const nlohmann::json& as_json(const rules_contents_t& contents) = 0;
virtual const nlohmann::json& as_json() = 0;
};
} // namespace falco

View File

@@ -135,76 +135,46 @@ nlohmann::json rule_loader::context::as_json()
return ret;
}
std::string rule_loader::context::snippet(const falco::load_result::rules_contents_t& rules_contents,
size_t snippet_width) const
std::string rule_loader::context::snippet(const std::string& content) const
{
std::string ret;
if(m_locs.empty())
if(m_locs.empty() || content.size() == 0)
{
return "<No context available>\n";
}
rule_loader::context::location loc = m_locs.back();
auto it = rules_contents.find(name);
if(it == rules_contents.end())
{
return "<No context available>\n";
}
const std::string& snip_content = it->second;
size_t from = loc.mark.pos;
// In some cases like this, where the content ends with a
// dangling property value:
// tags:
// The YAML::Mark position can be past the end of the file.
for(; from > 0 && from >= snip_content.size(); from--);
for(; from > 0 && from >= content.size(); from--);
// The snippet is generally the line that contains the
// position. So walk backwards from pos to the preceding
// newline, and walk forwards from pos to the following
// newline.
//
// However, some lines can be very very long, so the walk
// forwards/walk backwards is capped at a maximum of
// snippet_width/2 characters in either direction.
for(; from > 0 && snip_content.at(from) != '\n' && (loc.mark.pos - from) < (snippet_width/2); from--);
// Add the line that includes the mark and a marker
// at the column number.
size_t to = from;
size_t to = loc.mark.pos;
for(; to < snip_content.size()-1 && snip_content.at(to) != '\n' && (to - loc.mark.pos) < (snippet_width/2); to++);
for(; from > 0 && content.at(from) != '\n'; from--);
for(; to < content.size()-1 && content.at(to) != '\n'; to++);
// Don't include the newlines
if(snip_content.at(from) == '\n')
if(content.at(from) == '\n')
{
from++;
}
if(snip_content.at(to) == '\n')
if(content.at(to) == '\n')
{
to--;
}
ret = snip_content.substr(from, to-from+1);
ret = content.substr(from, to-from+1) + "\n";
// Replace the initial/end characters with '...' if the walk
// forwards/backwards was incomplete
if(loc.mark.pos - from >= (snippet_width/2))
{
ret.replace(0, 2, "...");
}
if(to - loc.mark.pos >= (snippet_width/2))
{
ret.replace(ret.size()-2, ret.size(), "...");
}
ret += "\n";
// Add a blank line with a marker at the position within the snippet
ret += std::string(loc.mark.pos-from, ' ') + '^' + "\n";
// Add a blank line with a marker at the column number
ret += std::string(loc.mark.column, ' ') + '^' + "\n";
return ret;
}
@@ -225,26 +195,26 @@ bool rule_loader::result::has_warnings()
return (warnings.size() > 0);
}
void rule_loader::result::add_error(load_result::error_code ec, const std::string& msg, const context& ctx)
void rule_loader::result::add_error(load_result::error_code ec, const std::string& msg, const context& ctx, const std::string& rules_content)
{
error err = {ec, msg, ctx};
error err = {ec, msg, ctx, ctx.snippet(rules_content)};
success = false;
errors.push_back(err);
}
void rule_loader::result::add_warning(load_result::warning_code wc, const std::string& msg, const context& ctx)
void rule_loader::result::add_warning(load_result::warning_code wc, const std::string& msg, const context& ctx, const std::string& rules_content)
{
warning warn = {wc, msg, ctx};
warning warn = {wc, msg, ctx, ctx.snippet(rules_content)};
warnings.push_back(warn);
}
const std::string& rule_loader::result::as_string(bool verbose, const rules_contents_t& contents)
const std::string& rule_loader::result::as_string(bool verbose)
{
if(verbose)
{
return as_verbose_string(contents);
return as_verbose_string();
}
else
{
@@ -266,19 +236,7 @@ const std::string& rule_loader::result::as_summary_string()
os << name << ": ";
}
if(success)
{
os << "Ok";
if (!warnings.empty())
{
os << ", with warnings";
}
}
else
{
os << "Invalid";
}
os << (success ? "Ok" : "Invalid");
if(!errors.empty())
{
@@ -324,7 +282,7 @@ const std::string& rule_loader::result::as_summary_string()
return res_summary_string;
}
const std::string& rule_loader::result::as_verbose_string(const rules_contents_t& contents)
const std::string& rule_loader::result::as_verbose_string()
{
std::ostringstream os;
@@ -338,19 +296,7 @@ const std::string& rule_loader::result::as_verbose_string(const rules_contents_t
os << name << ": ";
}
if(success)
{
os << "Ok";
if (!warnings.empty())
{
os << ", with warnings";
}
}
else
{
os << "Invalid";
}
os << (success ? "Ok" : "Invalid");
if (!errors.empty())
{
@@ -364,7 +310,7 @@ const std::string& rule_loader::result::as_verbose_string(const rules_contents_t
os << err.ctx.as_string();
os << "------" << std::endl;
os << err.ctx.snippet(contents);
os << err.snippet;
os << "------" << std::endl;
os << load_result::error_code_str(err.ec)
@@ -385,7 +331,7 @@ const std::string& rule_loader::result::as_verbose_string(const rules_contents_t
os << warn.ctx.as_string();
os << "------" << std::endl;
os << warn.ctx.snippet(contents);
os << warn.snippet;
os << "------" << std::endl;
os << load_result::warning_code_str(warn.wc)
@@ -399,7 +345,7 @@ const std::string& rule_loader::result::as_verbose_string(const rules_contents_t
return res_verbose_string;
}
const nlohmann::json& rule_loader::result::as_json(const rules_contents_t& contents)
const nlohmann::json& rule_loader::result::as_json()
{
nlohmann::json j;
@@ -418,7 +364,7 @@ const nlohmann::json& rule_loader::result::as_json(const rules_contents_t& conte
nlohmann::json jerr;
jerr["context"] = err.ctx.as_json();
jerr["context"]["snippet"] = err.ctx.snippet(contents);
jerr["context"]["snippet"] = err.snippet;
jerr["code"] = load_result::error_code_str(err.ec);
jerr["codedesc"] = load_result::error_desc(err.ec);
@@ -434,7 +380,7 @@ const nlohmann::json& rule_loader::result::as_json(const rules_contents_t& conte
nlohmann::json jwarn;
jwarn["context"] = warn.ctx.as_json();
jwarn["context"]["snippet"] = warn.ctx.snippet(contents);
jwarn["context"]["snippet"] = warn.snippet;
jwarn["code"] = load_result::warning_code_str(warn.wc);
jwarn["codedesc"] = load_result::warning_desc(warn.wc);
@@ -896,7 +842,8 @@ void rule_loader::define(configuration& cfg, rule_info& info)
{
cfg.res->add_warning(load_result::LOAD_UNKNOWN_SOURCE,
"Unknown source " + info.source + ", skipping",
info.ctx);
info.ctx,
cfg.content);
return;
}
@@ -1097,7 +1044,7 @@ void rule_loader::compile_rule_infos(
{
for (auto &w : warn_codes)
{
cfg.res->add_warning(w, "", r.ctx);
cfg.res->add_warning(w, "", r.ctx, cfg.content);
}
}
@@ -1144,7 +1091,8 @@ void rule_loader::compile_rule_infos(
cfg.res->add_warning(
load_result::LOAD_UNKNOWN_FIELD,
e.what(),
r.cond_ctx);
r.cond_ctx,
cfg.content);
}
else
{
@@ -1177,7 +1125,8 @@ void rule_loader::compile_rule_infos(
cfg.res->add_warning(
load_result::LOAD_NO_EVTTYPE,
"Rule matches too many evt.type values. This has a significant performance penalty.",
r.ctx);
r.ctx,
cfg.content);
}
}
}
@@ -1197,7 +1146,7 @@ void rule_loader::compile(configuration& cfg, indexed_vector<falco_rule>& out) c
}
catch(rule_load_exception &e)
{
cfg.res->add_error(e.ec, e.msg, e.ctx);
cfg.res->add_error(e.ec, e.msg, e.ctx, cfg.content);
}
// print info on any dangling lists or macros that were not used anywhere
@@ -1208,7 +1157,8 @@ void rule_loader::compile(configuration& cfg, indexed_vector<falco_rule>& out) c
cfg.res->add_warning(
load_result::LOAD_UNUSED_MACRO,
"Macro not referred to by any other rule/macro",
m.ctx);
m.ctx,
cfg.content);
}
}
for (auto &l : lists)
@@ -1218,7 +1168,8 @@ void rule_loader::compile(configuration& cfg, indexed_vector<falco_rule>& out) c
cfg.res->add_warning(
load_result::LOAD_UNUSED_LIST,
"List not referred to by any other rule/macro",
l.ctx);
l.ctx,
cfg.content);
}
}
}

View File

@@ -36,8 +36,6 @@ public:
class context
{
public:
static const size_t default_snippet_width = 160;
struct location
{
// The original location in the document
@@ -53,7 +51,7 @@ public:
};
context(const std::string& name);
context(const YAML::Node& item,
context(const YAML::Node& mark,
const std::string item_type,
const std::string item_name,
const context& parent);
@@ -61,9 +59,7 @@ public:
// Return a snippet of the provided rules content
// corresponding to this context.
// Uses the provided rules_contents to look up the original
// rules content for a given location name.
std::string snippet(const falco::load_result::rules_contents_t& rules_contents, size_t snippet_width = default_snippet_width) const;
std::string snippet(const std::string& content) const;
std::string as_string();
nlohmann::json as_json();
@@ -81,6 +77,7 @@ public:
falco::load_result::warning_code wc;
std::string msg;
context ctx;
std::string snippet;
};
struct error
@@ -88,6 +85,7 @@ public:
falco::load_result::error_code ec;
std::string msg;
context ctx;
std::string snippet;
};
class rule_load_exception : public std::exception
@@ -115,21 +113,22 @@ public:
virtual bool successful() override;
virtual bool has_warnings() override;
virtual const std::string& as_string(bool verbose, const falco::load_result::rules_contents_t& contents) override;
virtual const nlohmann::json& as_json(const falco::load_result::rules_contents_t& contents) override;
virtual const std::string& as_string(bool verbose) override;
virtual const nlohmann::json& as_json() override;
void add_error(falco::load_result::error_code ec,
const std::string& msg,
const context& ctx);
const context& ctx,
const std::string& rules_content);
void add_warning(falco::load_result::warning_code ec,
const std::string& msg,
const context& ctx);
const context& ctx,
const std::string& rules_content);
protected:
const std::string& as_summary_string();
const std::string& as_verbose_string(const falco::load_result::rules_contents_t& contents);
const std::string& as_verbose_string();
std::string name;
bool success;

View File

@@ -411,7 +411,7 @@ static void read_item(
else
{
rule_loader::context ctx(item, "unknown", "", 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, cfg.content);
}
}
@@ -425,7 +425,7 @@ bool rule_reader::load(rule_loader::configuration& cfg, rule_loader& loader)
catch(const exception& e)
{
rule_loader::context ctx(cfg.name);
cfg.res->add_error(load_result::LOAD_ERR_YAML_PARSE, e.what(), ctx);
cfg.res->add_error(load_result::LOAD_ERR_YAML_PARSE, e.what(), ctx, cfg.content);
return false;
}
@@ -454,7 +454,7 @@ bool rule_reader::load(rule_loader::configuration& cfg, rule_loader& loader)
}
catch (rule_loader::rule_load_exception &e)
{
cfg.res->add_error(e.ec, e.msg, e.ctx);
cfg.res->add_error(e.ec, e.msg, e.ctx, cfg.content);
// Although we *could* continue on to the next doc,
// as it's effectively a new rules file, for

View File

@@ -21,7 +21,7 @@ using namespace falco::app;
application::run_result application::init_clients()
{
#ifndef MINIMAL_BUILD
// k8s and mesos clients are useful only if syscall source is enabled
// k8s client is useful only if the syscall source is enabled
if (!is_syscall_source_enabled())
{
return run_result::ok();
@@ -55,23 +55,6 @@ application::run_result application::init_clients()
}
m_state->inspector->init_k8s_client(k8s_api_ptr, k8s_api_cert_ptr, k8s_node_name_ptr, m_options.verbose);
}
//
// Run mesos, if required
//
if(!m_options.mesos_api.empty())
{
// Differs from init_k8s_client in that it
// passes a pointer but the inspector does
// *not* own it and does not use it after
// init_mesos_client() returns.
m_state->inspector->init_mesos_client(&(m_options.mesos_api), m_options.verbose);
}
else if(char* mesos_api_env = getenv("FALCO_MESOS_API"))
{
std::string mesos_api_copy = mesos_api_env;
m_state->inspector->init_mesos_client(&mesos_api_copy, m_options.verbose);
}
#endif
return run_result::ok();

View File

@@ -35,11 +35,6 @@ void application::configure_output_format()
output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id";
replace_container_info = true;
}
else if(m_options.print_additional == "m" || m_options.print_additional == "mesos")
{
output_format = "task=%mesos.task.name container=%container.id";
replace_container_info = true;
}
else if(!m_options.print_additional.empty())
{
output_format = m_options.print_additional;

View File

@@ -93,37 +93,27 @@ application::run_result application::load_rules_files()
falco_configuration::read_rules_file_directory(path, m_state->config->m_loaded_rules_filenames, m_state->config->m_loaded_rules_folders);
}
std::vector<std::string> rules_contents;
falco::load_result::rules_contents_t rc;
try {
read_files(m_state->config->m_loaded_rules_filenames.begin(),
m_state->config->m_loaded_rules_filenames.end(),
rules_contents,
rc);
}
catch(falco_exception& e)
{
return run_result::fatal(e.what());
}
for(auto &filename : m_state->config->m_loaded_rules_filenames)
for (const auto& filename : m_state->config->m_loaded_rules_filenames)
{
falco_logger::log(LOG_INFO, "Loading rules from file " + filename + "\n");
std::unique_ptr<falco::load_result> res;
res = m_state->engine->load_rules(rc.at(filename), filename);
res = m_state->engine->load_rules_file(filename);
// Print the full output if verbose is true
if(m_options.verbose &&
(!res->successful() || res->has_warnings()))
{
printf("%s\n",
(m_state->config->m_json_output ?
res->as_json().dump().c_str() :
res->as_string(true).c_str()));
}
if(!res->successful())
{
// Return the summary version as the error
return run_result::fatal(res->as_string(true, rc));
}
// If verbose is true, also print any warnings
if(m_options.verbose && res->has_warnings())
{
fprintf(stderr, "%s\n", res->as_string(true, rc).c_str());
return run_result::fatal(res->as_string(false));
}
}

View File

@@ -23,43 +23,7 @@ application::run_result application::validate_rules_files()
{
if(m_options.validate_rules_filenames.size() > 0)
{
std::vector<std::string> rules_contents;
falco::load_result::rules_contents_t rc;
try {
read_files(m_options.validate_rules_filenames.begin(),
m_options.validate_rules_filenames.end(),
rules_contents,
rc);
}
catch(falco_exception& e)
{
return run_result::fatal(e.what());
}
bool successful = true;
// The validation result is *always* printed to
// stdout. When json_output is true, the output is in
// json format and contains all errors/warnings for
// all files.
//
// When json_output is false, it contains a summary of
// each file and whether it was valid or not, along
// with any errors. To match older falco behavior,
// this *only* contains errors.
//
// So for each file stdout will contain:
//
// <filename>: Ok
// or
// <filename>: Invalid
// [All Validation Errors]
//
// Warnings are only printed to stderr, and only
// printed when verbose is true.
std::string summary;
falco_logger::log(LOG_INFO, "Validating rules file(s):\n");
@@ -72,45 +36,31 @@ application::run_result application::validate_rules_files()
// validation result is a single json object.
nlohmann::json results = nlohmann::json::array();
for(auto &filename : m_options.validate_rules_filenames)
for(auto file : m_options.validate_rules_filenames)
{
std::unique_ptr<falco::load_result> res;
res = m_state->engine->load_rules(rc.at(filename), filename);
res = m_state->engine->load_rules_file(file);
successful &= res->successful();
if(summary != "")
{
summary += "\n";
}
summary += file + ": " + (res->successful() ? "Ok" : "Invalid");
if(m_state->config->m_json_output)
{
results.push_back(res->as_json(rc));
results.push_back(res->as_json());
}
else
{
if(summary != "")
// Print the full output when verbose is true
if(m_options.verbose &&
(!res->successful() || res->has_warnings()))
{
summary += "\n";
}
// Add to the summary if not successful, or successful
// with no warnings.
if(!res->successful() ||
(res->successful() && !res->has_warnings()))
{
summary += res->as_string(true, rc);
}
else
{
// If here, there must be only warnings.
// Add a line to the summary noting that the
// file was ok with warnings, without actually
// printing the warnings.
summary += filename + ": Ok, with warnings";
// If verbose is true, print the warnings now.
if(m_options.verbose)
{
fprintf(stderr, "%s\n", res->as_string(true, rc).c_str());
}
printf("%s\n", res->as_string(true).c_str());
}
}
}
@@ -121,13 +71,10 @@ application::run_result application::validate_rules_files()
res["falco_load_results"] = results;
printf("%s\n", res.dump().c_str());
}
else
{
printf("%s\n", summary.c_str());
}
if(successful)
{
printf("%s\n", summary.c_str());
return run_result::exit();
}
else

View File

@@ -180,16 +180,13 @@ void cmdline_options::define()
("list-syscall-events", "List all defined system call events.", cxxopts::value<bool>(list_syscall_events))
#ifndef MUSL_OPTIMIZED
("list-plugins", "Print info on all loaded plugins and exit.", cxxopts::value(list_plugins)->default_value("false"))
#endif
#ifndef MINIMAL_BUILD
("m,mesos-api", "Enable Mesos support by connecting to the API server specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\". Marathon url is optional and defaults to Mesos address, port 8080. The API servers can also be specified via the environment variable FALCO_MESOS_API.", cxxopts::value(mesos_api), "<url[,marathon_url]>")
#endif
("M", "Stop collecting after <num_seconds> reached.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>")
("markdown", "When used with --list/--list-syscall-events, print the content in Markdown format", cxxopts::value<bool>(markdown))
("N", "When used with --list, only print field names.", cxxopts::value(names_only)->default_value("false"))
("o,option", "Set the value of option <opt> to <val>. Overrides values in configuration file. <opt> can be identified using its location in configuration file using dot notation. Elements which are entries of lists can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "<opt>=<val>")
("plugin-info", "Print info for a single plugin and exit.\nThis includes all descriptivo info like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n<plugin_name> can be the name of the plugin or its configured library_path.", cxxopts::value(print_plugin_info), "<plugin_name>")
("p,print", "Add additional information to each falco notification's output.\nWith -pc or -pcontainer will use a container-friendly format.\nWith -pk or -pkubernetes will use a kubernetes-friendly format.\nWith -pm or -pmesos will use a mesos-friendly format.\nAdditionally, specifying -pc/-pk/-pm will change the interpretation of %container.info in rule output fields.", cxxopts::value(print_additional), "<output_format>")
("p,print", "Add additional information to each falco notification's output.\nWith -pc or -pcontainer will use a container-friendly format.\nWith -pk or -pkubernetes will use a kubernetes-friendly format.\nAdditionally, specifying -pc/-pk will change the interpretation of %container.info in rule output fields.", cxxopts::value(print_additional), "<output_format>")
("P,pidfile", "When run as a daemon, write pid to specified file", cxxopts::value(pidfilename)->default_value("/var/run/falco.pid"), "<pid_file>")
("r", "Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml). Can be specified multiple times to read from multiple files/directories.", cxxopts::value<std::vector<std::string>>(), "<rules_file>")
("s", "If specified, append statistics related to Falco's reading/processing of events to this file (only useful in live mode).", cxxopts::value(stats_filename), "<stats_file>")

View File

@@ -58,7 +58,6 @@ public:
std::string print_plugin_info;
bool list_syscall_events;
bool markdown;
std::string mesos_api;
int duration_to_tot;
bool names_only;
std::vector<std::string> cmdline_config_options;

View File

@@ -134,49 +134,6 @@ private:
bool proceed;
};
// Convenience method. Read a sequence of filenames and fill
// in a vector of rules contents.
// Also fill in the provided rules_contents_t with a mapping from
// filename (reference) to content (reference).
// falco_exception if any file could not be read.
template<class InputIterator>
void read_files(InputIterator begin, InputIterator end,
std::vector<std::string>& rules_contents,
falco::load_result::rules_contents_t& rc)
{
// Read the contents in a first pass
for(auto it = begin; it != end; it++)
{
std::string &filename = *it;
std::ifstream is;
is.open(filename);
if (!is.is_open())
{
throw falco_exception("Could not open file " + filename + " for reading");
}
std::string rules_content((istreambuf_iterator<char>(is)),
istreambuf_iterator<char>());
rules_contents.emplace_back(std::move(rules_content));
}
// Populate the map in a second pass to avoid
// references becoming invalid.
auto it = begin;
auto rit = rules_contents.begin();
for(; it != end && rit != rules_contents.end(); it++, rit++)
{
rc.emplace(*it, *rit);
}
// Both it and rit must be at the end, otherwise
// there's a bug in the above
if(it != end || rit != rules_contents.end())
{
throw falco_exception("Unexpected mismatch in rules content name/rules content sets?");
}
}
// These methods comprise the code the application "runs". The
// order in which the methods run is in application.cpp.
run_result create_signal_handlers();