mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-18 18:58:41 +00:00
chore: restore the classic flags for a future refactor for the new
functionalities Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com> Signed-off-by: Lorenzo Fontana <lo@linux.com>
This commit is contained in:
@@ -69,7 +69,7 @@ if(MUSL_OPTIMIZED_BUILD)
|
||||
set(MUSL_FLAGS "-static -Os")
|
||||
endif()
|
||||
|
||||
set(CMAKE_COMMON_FLAGS "-Wall -pg -ggdb ${DRAIOS_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}")
|
||||
set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${DRAIOS_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}")
|
||||
|
||||
if(BUILD_WARNINGS_AS_ERRORS)
|
||||
set(CMAKE_SUPPRESSED_WARNINGS
|
||||
|
||||
@@ -38,8 +38,7 @@ if(MINIMAL_BUILD)
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libscap"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/libhawk")
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
else()
|
||||
target_include_directories(
|
||||
falco_engine
|
||||
@@ -52,17 +51,11 @@ else()
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libscap"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/libhawk")
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
endif()
|
||||
|
||||
target_link_libraries(falco_engine "${FALCO_SINSP_LIBRARY}" "${LPEG_LIB}" "${LYAML_LIB}" "${LIBYAML_LIB}")
|
||||
|
||||
if(DEFINED LIBHAWK_LIBRARIES)
|
||||
message(STATUS "Using externally provided libhawk implementations: ${LIBHAWK_LIBRARIES}")
|
||||
target_link_libraries(falco_engine ${LIBHAWK_LIBRARIES})
|
||||
endif()
|
||||
|
||||
configure_file(config_falco_engine.h.in config_falco_engine.h)
|
||||
|
||||
if(DEFINED FALCO_COMPONENT)
|
||||
|
||||
@@ -26,8 +26,7 @@ limitations under the License.
|
||||
|
||||
#include "formats.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#include "lpeg.h"
|
||||
#include "lyaml.h"
|
||||
}
|
||||
@@ -35,6 +34,7 @@ extern "C"
|
||||
#include "utils.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
|
||||
string lua_on_event = "on_event";
|
||||
string lua_print_stats = "print_stats";
|
||||
|
||||
@@ -42,24 +42,25 @@ using namespace std;
|
||||
|
||||
nlohmann::json::json_pointer falco_engine::k8s_audit_time = "/stageTimestamp"_json_pointer;
|
||||
|
||||
falco_engine::falco_engine(bool seed_rng, const std::string &alternate_lua_dir):
|
||||
m_rules(NULL), m_next_ruleset_id(0),
|
||||
m_min_priority(falco_common::PRIORITY_DEBUG),
|
||||
m_sampling_ratio(1), m_sampling_multiplier(0),
|
||||
m_replace_container_info(false)
|
||||
falco_engine::falco_engine(bool seed_rng, const std::string& alternate_lua_dir)
|
||||
: m_rules(NULL), m_next_ruleset_id(0),
|
||||
m_min_priority(falco_common::PRIORITY_DEBUG),
|
||||
m_sampling_ratio(1), m_sampling_multiplier(0),
|
||||
m_replace_container_info(false)
|
||||
{
|
||||
luaopen_lpeg(m_ls);
|
||||
luaopen_yaml(m_ls);
|
||||
|
||||
m_alternate_lua_dir = alternate_lua_dir;
|
||||
|
||||
falco_common::init(m_lua_main_filename.c_str(), alternate_lua_dir.c_str());
|
||||
falco_rules::init(m_ls);
|
||||
|
||||
clear_filters();
|
||||
m_sinsp_rules.reset(new falco_sinsp_ruleset());
|
||||
m_k8s_audit_rules.reset(new falco_ruleset());
|
||||
|
||||
if(seed_rng)
|
||||
{
|
||||
srandom((unsigned)getpid());
|
||||
srandom((unsigned) getpid());
|
||||
}
|
||||
|
||||
m_default_ruleset_id = find_ruleset_id(m_default_ruleset);
|
||||
@@ -70,7 +71,7 @@ falco_engine::falco_engine(bool seed_rng, const std::string &alternate_lua_dir):
|
||||
|
||||
falco_engine::~falco_engine()
|
||||
{
|
||||
if(m_rules)
|
||||
if (m_rules)
|
||||
{
|
||||
delete m_rules;
|
||||
}
|
||||
@@ -87,7 +88,7 @@ falco_engine *falco_engine::clone()
|
||||
|
||||
uint32_t falco_engine::engine_version()
|
||||
{
|
||||
return (uint32_t)FALCO_ENGINE_VERSION;
|
||||
return (uint32_t) FALCO_ENGINE_VERSION;
|
||||
}
|
||||
|
||||
#define DESCRIPTION_TEXT_START 16
|
||||
@@ -153,28 +154,17 @@ void falco_engine::list_fields(bool names_only)
|
||||
}
|
||||
}
|
||||
|
||||
void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events)
|
||||
{
|
||||
ifstream is;
|
||||
|
||||
is.open(rules_filename);
|
||||
if(!is.is_open())
|
||||
{
|
||||
throw falco_exception("Could not open rules filename " +
|
||||
rules_filename + " " +
|
||||
"for reading");
|
||||
}
|
||||
|
||||
string rules_content((istreambuf_iterator<char>(is)),
|
||||
istreambuf_iterator<char>());
|
||||
|
||||
load_rules(rules_content, verbose, all_events);
|
||||
}
|
||||
|
||||
void falco_engine::load_rules(const string &rules_content, bool verbose, bool all_events)
|
||||
{
|
||||
uint64_t dummy;
|
||||
|
||||
return load_rules(rules_content, verbose, all_events, dummy);
|
||||
}
|
||||
|
||||
void falco_engine::load_rules(const string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version)
|
||||
{
|
||||
// The engine must have been given an inspector by now.
|
||||
if(!m_inspector)
|
||||
if(! m_inspector)
|
||||
{
|
||||
throw falco_exception("No inspector provided");
|
||||
}
|
||||
@@ -186,52 +176,45 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
|
||||
|
||||
if(!m_rules)
|
||||
{
|
||||
// Note that falco_formats is added to the lua state used by the falco engine only.
|
||||
// Within the engine, only formats.
|
||||
// Formatter is used, so we can unconditionally set json_output to false.
|
||||
bool json_output = false;
|
||||
bool json_include_output_property = false;
|
||||
falco_formats::init(m_inspector, this, m_ls, json_output, json_include_output_property);
|
||||
m_rules = new falco_rules(m_inspector, this, m_ls);
|
||||
m_rules = new falco_rules(m_inspector,
|
||||
this,
|
||||
m_ls);
|
||||
}
|
||||
|
||||
uint64_t dummy;
|
||||
// m_sinsp_rules.reset(new falco_sinsp_ruleset());
|
||||
// m_k8s_audit_rules.reset(new falco_ruleset());
|
||||
m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, dummy);
|
||||
// Note that falco_formats is added to the lua state used
|
||||
// by the falco engine only. Within the engine, only
|
||||
// formats.formatter is used, so we can unconditionally set
|
||||
// json_output to false.
|
||||
bool json_output = false;
|
||||
bool json_include_output_property = false;
|
||||
falco_formats::init(m_inspector, this, m_ls, json_output, json_include_output_property);
|
||||
|
||||
m_is_ready = true;
|
||||
|
||||
return;
|
||||
|
||||
//
|
||||
// auto local_rules = new falco_rules(m_inspector, this, m_ls);
|
||||
// try
|
||||
// {
|
||||
// uint64_t dummy;
|
||||
// local_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, dummy);
|
||||
|
||||
// // m_rules = local_rules
|
||||
// // std::atomic<falco_rules *> lore(m_rules);
|
||||
// // std::atomic_exchange(&lore, local_rules);
|
||||
// // SCHEDULE LOCAL_RULES AS NEXT RULESET
|
||||
// }
|
||||
// catch(const falco_exception &e)
|
||||
// {
|
||||
// // todo
|
||||
// printf("IGNORE BECAUSE OF ERROR LOADING RULESET!\n");
|
||||
// }
|
||||
m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, required_engine_version);
|
||||
}
|
||||
|
||||
// // todo(fntlnz): not sure we want this in falco_engine
|
||||
// void falco_engine::watch_rules(bool verbose, bool all_events)
|
||||
// {
|
||||
// hawk_watch_rules((hawk_watch_rules_cb)rules_cb, reinterpret_cast<hawk_engine *>(this));
|
||||
// }
|
||||
|
||||
bool falco_engine::is_ready()
|
||||
void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events)
|
||||
{
|
||||
return m_is_ready;
|
||||
uint64_t dummy;
|
||||
|
||||
return load_rules_file(rules_filename, verbose, all_events, dummy);
|
||||
}
|
||||
|
||||
void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events, uint64_t &required_engine_version)
|
||||
{
|
||||
ifstream is;
|
||||
|
||||
is.open(rules_filename);
|
||||
if (!is.is_open())
|
||||
{
|
||||
throw falco_exception("Could not open rules filename " +
|
||||
rules_filename + " " +
|
||||
"for reading");
|
||||
}
|
||||
|
||||
string rules_content((istreambuf_iterator<char>(is)),
|
||||
istreambuf_iterator<char>());
|
||||
|
||||
load_rules(rules_content, verbose, all_events, required_engine_version);
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule(const string &substring, bool enabled, const string &ruleset)
|
||||
@@ -299,7 +282,7 @@ uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset)
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
|
||||
return m_sinsp_rules->num_rules_for_ruleset(ruleset_id) +
|
||||
m_k8s_audit_rules->num_rules_for_ruleset(ruleset_id);
|
||||
m_k8s_audit_rules->num_rules_for_ruleset(ruleset_id);
|
||||
}
|
||||
|
||||
void falco_engine::evttypes_for_ruleset(std::vector<bool> &evttypes, const std::string &ruleset)
|
||||
@@ -338,7 +321,6 @@ unique_ptr<falco_engine::rule_result> falco_engine::process_sinsp_event(sinsp_ev
|
||||
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_sinsp_event(sinsp_evt *ev)
|
||||
{
|
||||
// todo(leodido, fntlnz) > pass the last ruleset id
|
||||
return process_sinsp_event(ev, m_default_ruleset_id);
|
||||
}
|
||||
|
||||
@@ -350,7 +332,7 @@ unique_ptr<falco_engine::rule_result> falco_engine::process_k8s_audit_event(json
|
||||
}
|
||||
|
||||
// All k8s audit events have the single tag "1".
|
||||
if(!m_k8s_audit_rules->run((gen_event *)ev, 1, ruleset_id))
|
||||
if(!m_k8s_audit_rules->run((gen_event *) ev, 1, ruleset_id))
|
||||
{
|
||||
return unique_ptr<struct rule_result>();
|
||||
}
|
||||
@@ -373,7 +355,7 @@ void falco_engine::populate_rule_result(unique_ptr<struct rule_result> &res, gen
|
||||
|
||||
if(lua_pcall(m_ls, 1, 4, 0) != 0)
|
||||
{
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
string err = "Error invoking function output: " + string(lerr);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
@@ -416,7 +398,7 @@ bool falco_engine::parse_k8s_audit_json(nlohmann::json &j, std::list<json_event>
|
||||
{
|
||||
// Note we only handle a single top level array, to
|
||||
// avoid excessive recursion.
|
||||
if(!parse_k8s_audit_json(item, evts, false))
|
||||
if(! parse_k8s_audit_json(item, evts, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -494,7 +476,7 @@ void falco_engine::print_stats()
|
||||
{
|
||||
if(lua_pcall(m_ls, 0, 0, 0) != 0)
|
||||
{
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
string err = "Error invoking function print_stats: " + string(lerr);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
@@ -503,20 +485,21 @@ void falco_engine::print_stats()
|
||||
{
|
||||
throw falco_exception("No function " + lua_print_stats + " found in lua rule loader module");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void falco_engine::add_sinsp_filter(string &rule,
|
||||
set<uint32_t> &evttypes,
|
||||
set<uint32_t> &syscalls,
|
||||
set<string> &tags,
|
||||
sinsp_filter *filter)
|
||||
sinsp_filter* filter)
|
||||
{
|
||||
m_sinsp_rules->add(rule, evttypes, syscalls, tags, filter);
|
||||
}
|
||||
|
||||
void falco_engine::add_k8s_audit_filter(string &rule,
|
||||
set<string> &tags,
|
||||
json_event_filter *filter)
|
||||
json_event_filter* filter)
|
||||
{
|
||||
// All k8s audit events have a single tag "1".
|
||||
std::set<uint32_t> event_tags = {1};
|
||||
@@ -558,8 +541,8 @@ inline bool falco_engine::should_drop_evt()
|
||||
return false;
|
||||
}
|
||||
|
||||
double coin = (random() * (1.0 / RAND_MAX));
|
||||
return (coin >= (1.0 / (m_sampling_multiplier * m_sampling_ratio)));
|
||||
double coin = (random() * (1.0/RAND_MAX));
|
||||
return (coin >= (1.0/(m_sampling_multiplier * m_sampling_ratio)));
|
||||
}
|
||||
|
||||
sinsp_filter_factory &falco_engine::sinsp_factory()
|
||||
|
||||
@@ -38,11 +38,6 @@ limitations under the License.
|
||||
#include "config_falco_engine.h"
|
||||
#include "falco_common.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "hawk.h"
|
||||
}
|
||||
|
||||
//
|
||||
// This class acts as the primary interface between a program and the
|
||||
// falco rules engine. Falco outputs (writing to files/syslog/etc) are
|
||||
@@ -52,10 +47,9 @@ extern "C"
|
||||
class falco_engine : public falco_common
|
||||
{
|
||||
public:
|
||||
falco_engine(bool seed_rng = true, const std::string &alternate_lua_dir = FALCO_ENGINE_SOURCE_LUA_DIR);
|
||||
falco_engine(bool seed_rng=true, const std::string& alternate_lua_dir=FALCO_ENGINE_SOURCE_LUA_DIR);
|
||||
virtual ~falco_engine();
|
||||
|
||||
falco_engine(const falco_engine &rhs);
|
||||
falco_engine *clone();
|
||||
|
||||
// A given engine has a version which identifies the fields
|
||||
@@ -65,7 +59,7 @@ public:
|
||||
static uint32_t engine_version();
|
||||
|
||||
// Print to stdout (using printf) a description of each field supported by this engine.
|
||||
void list_fields(bool names_only = false);
|
||||
void list_fields(bool names_only=false);
|
||||
|
||||
//
|
||||
// Load rules either directly or from a filename.
|
||||
@@ -73,8 +67,12 @@ public:
|
||||
void load_rules_file(const std::string &rules_filename, bool verbose, bool all_events);
|
||||
void load_rules(const std::string &rules_content, bool verbose, bool all_events);
|
||||
|
||||
// Watch and live-reload rules using an external ABI interface provided by libhawk
|
||||
void watch_rules(bool verbose, bool all_events);
|
||||
//
|
||||
// Identical to above, but also returns the required engine version for the file/content.
|
||||
// (If no required engine version is specified, returns 0).
|
||||
//
|
||||
void load_rules_file(const std::string &rules_filename, bool verbose, bool all_events, uint64_t &required_engine_version);
|
||||
void load_rules(const std::string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version);
|
||||
|
||||
//
|
||||
// Enable/Disable any rules matching the provided substring.
|
||||
@@ -89,6 +87,7 @@ public:
|
||||
// Wrapper that assumes the default ruleset
|
||||
void enable_rule(const std::string &substring, bool enabled);
|
||||
|
||||
|
||||
// Like enable_rule, but the rule name must be an exact match.
|
||||
void enable_rule_exact(const std::string &rule_name, bool enabled, const std::string &ruleset);
|
||||
|
||||
@@ -157,8 +156,7 @@ public:
|
||||
|
||||
// **Methods Related to k8s audit log events, which are
|
||||
// **represented as json objects.
|
||||
struct rule_result
|
||||
{
|
||||
struct rule_result {
|
||||
gen_event *evt;
|
||||
std::string rule;
|
||||
std::string source;
|
||||
@@ -175,7 +173,7 @@ public:
|
||||
// Returns true if the json object was recognized as a k8s
|
||||
// audit event(s), false otherwise.
|
||||
//
|
||||
bool parse_k8s_audit_json(nlohmann::json &j, std::list<json_event> &evts, bool top = true);
|
||||
bool parse_k8s_audit_json(nlohmann::json &j, std::list<json_event> &evts, bool top=true);
|
||||
|
||||
//
|
||||
// Given an event, check it against the set of rules in the
|
||||
@@ -200,7 +198,7 @@ public:
|
||||
//
|
||||
void add_k8s_audit_filter(std::string &rule,
|
||||
std::set<std::string> &tags,
|
||||
json_event_filter *filter);
|
||||
json_event_filter* filter);
|
||||
|
||||
// **Methods Related to Sinsp Events e.g system calls
|
||||
//
|
||||
@@ -241,14 +239,13 @@ public:
|
||||
std::set<uint32_t> &evttypes,
|
||||
std::set<uint32_t> &syscalls,
|
||||
std::set<std::string> &tags,
|
||||
sinsp_filter *filter);
|
||||
sinsp_filter* filter);
|
||||
|
||||
sinsp_filter_factory &sinsp_factory();
|
||||
json_event_filter_factory &json_factory();
|
||||
|
||||
bool is_ready();
|
||||
|
||||
private:
|
||||
|
||||
static nlohmann::json::json_pointer k8s_audit_time;
|
||||
|
||||
//
|
||||
@@ -300,6 +297,5 @@ private:
|
||||
|
||||
std::string m_extra;
|
||||
bool m_replace_container_info;
|
||||
|
||||
bool m_is_ready = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ if(USE_BUNDLED_DEPS)
|
||||
list(APPEND FALCO_DEPENDENCIES yamlcpp)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
list(
|
||||
APPEND FALCO_SOURCES
|
||||
@@ -110,6 +112,18 @@ add_executable(
|
||||
${FALCO_SOURCES}
|
||||
)
|
||||
|
||||
if(DEFINED LIBHAWK_LIBRARIES)
|
||||
message(STATUS "Using externally provided libhawk implementations: ${LIBHAWK_LIBRARIES}")
|
||||
list(
|
||||
APPEND FALCO_LIBRARIES
|
||||
"${LIBHAWK_LIBRARIES}"
|
||||
)
|
||||
list(
|
||||
APPEND FALCO_INCLUDE_DIRECTORIES
|
||||
"${PROJECT_SOURCE_DIR}/userspace/libhawk"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_dependencies(falco ${FALCO_DEPENDENCIES})
|
||||
|
||||
target_link_libraries(
|
||||
|
||||
@@ -58,6 +58,16 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
|
||||
m_config->get_sequence<list<string>>(rules_files, string("rules_file"));
|
||||
|
||||
for(auto &file : rules_files)
|
||||
{
|
||||
// Here, we only include files that exist
|
||||
struct stat buffer;
|
||||
if(stat(file.c_str(), &buffer) == 0)
|
||||
{
|
||||
read_rules_file_directory(file, m_rules_filenames);
|
||||
}
|
||||
}
|
||||
|
||||
m_json_output = m_config->get_scalar<bool>("json_output", false);
|
||||
m_json_include_output_property = m_config->get_scalar<bool>("json_include_output_property", true);
|
||||
|
||||
@@ -224,6 +234,69 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_syscall_evt_simulate_drops = m_config->get_scalar<bool>("syscall_event_drops", "simulate_drops", false);
|
||||
}
|
||||
|
||||
void falco_configuration::read_rules_file_directory(const string &path, list<string> &rules_filenames)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
int rc = stat(path.c_str(), &st);
|
||||
|
||||
if(rc != 0)
|
||||
{
|
||||
std::cerr << "Could not get info on rules file " << path << ": " << strerror(errno) << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if(st.st_mode & S_IFDIR)
|
||||
{
|
||||
// It's a directory. Read the contents, sort
|
||||
// alphabetically, and add every path to
|
||||
// rules_filenames
|
||||
vector<string> dir_filenames;
|
||||
|
||||
DIR *dir = opendir(path.c_str());
|
||||
|
||||
if(!dir)
|
||||
{
|
||||
std::cerr << "Could not get read contents of directory " << path << ": " << strerror(errno) << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
for(struct dirent *ent = readdir(dir); ent; ent = readdir(dir))
|
||||
{
|
||||
string efile = path + "/" + ent->d_name;
|
||||
|
||||
rc = stat(efile.c_str(), &st);
|
||||
|
||||
if(rc != 0)
|
||||
{
|
||||
std::cerr << "Could not get info on rules file " << efile << ": " << strerror(errno) << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if(st.st_mode & S_IFREG)
|
||||
{
|
||||
dir_filenames.push_back(efile);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
std::sort(dir_filenames.begin(),
|
||||
dir_filenames.end());
|
||||
|
||||
for(string &ent : dir_filenames)
|
||||
{
|
||||
rules_filenames.push_back(ent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume it's a file and just add to
|
||||
// rules_filenames. If it can't be opened/etc that
|
||||
// will be reported later..
|
||||
rules_filenames.push_back(path);
|
||||
}
|
||||
}
|
||||
|
||||
static bool split(const string &str, char delim, pair<string, string> &parts)
|
||||
{
|
||||
@@ -265,4 +338,4 @@ void falco_configuration::set_cmdline_option(const string &opt)
|
||||
{
|
||||
m_config->set_scalar(keyval.first, keyval.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,6 +190,9 @@ public:
|
||||
void init(std::string conf_filename, std::list<std::string>& cmdline_options);
|
||||
void init(std::list<std::string>& cmdline_options);
|
||||
|
||||
static void read_rules_file_directory(const string& path, list<string>& rules_filenames);
|
||||
|
||||
std::list<std::string> m_rules_filenames;
|
||||
bool m_json_output;
|
||||
bool m_json_include_output_property;
|
||||
std::string m_log_level;
|
||||
|
||||
@@ -31,7 +31,6 @@ limitations under the License.
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <condition_variable>
|
||||
#include <tuple>
|
||||
|
||||
#include <sinsp.h>
|
||||
|
||||
@@ -49,18 +48,22 @@ limitations under the License.
|
||||
#include "webserver.h"
|
||||
#include "grpc_server.h"
|
||||
#endif
|
||||
extern "C"
|
||||
{
|
||||
#include "hawk.h"
|
||||
}
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
typedef function<void(sinsp *inspector)> open_t;
|
||||
typedef function<void(sinsp* inspector)> open_t;
|
||||
|
||||
bool g_terminate = false;
|
||||
bool g_reopen_outputs = false;
|
||||
bool g_restart = false;
|
||||
bool g_daemonized = false;
|
||||
|
||||
std::mutex engine_ready;
|
||||
std::condition_variable engine_cv;
|
||||
bool is_engine_ready = false;
|
||||
std::mutex g_engine_ready;
|
||||
std::condition_variable g_engine_cv;
|
||||
bool g_is_engine_ready = false;
|
||||
|
||||
//
|
||||
// Helper functions
|
||||
@@ -85,97 +88,100 @@ static void restart_falco(int signal)
|
||||
//
|
||||
static void usage()
|
||||
{
|
||||
printf(
|
||||
"Falco version: " FALCO_VERSION "\n"
|
||||
"Usage: falco [options]\n\n"
|
||||
"Options:\n"
|
||||
" -h, --help Print this page\n"
|
||||
" -c Configuration file (default " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ")\n"
|
||||
" -A Monitor all events, including those with EF_DROP_SIMPLE_CONS flag.\n"
|
||||
" --alternate-lua-dir <path> Specify an alternate path for loading Falco lua files\n"
|
||||
" -b, --print-base64 Print data buffers in base64.\n"
|
||||
" This is useful for encoding binary data that needs to be used over media designed to.\n"
|
||||
" --cri <path> Path to CRI socket for container metadata.\n"
|
||||
" Use the specified socket to fetch data from a CRI-compatible runtime.\n"
|
||||
" -d, --daemon Run as a daemon.\n"
|
||||
" --disable-cri-async Disable asynchronous CRI metadata fetching.\n"
|
||||
" This is useful to let the input event wait for the container metadata fetch\n"
|
||||
" to finish before moving forward. Async fetching, in some environments leads\n"
|
||||
" to empty fields for container metadata when the fetch is not fast enough to be\n"
|
||||
" completed asynchronously. This can have a performance penalty on your environment\n"
|
||||
" depending on the number of containers and the frequency at which they are created/started/stopped\n"
|
||||
" --disable-source <event_source>\n"
|
||||
" Disable a specific event source.\n"
|
||||
" Available event sources are: syscall, k8s_audit.\n"
|
||||
" It can be passed multiple times.\n"
|
||||
" Can not disable both the event sources.\n"
|
||||
" -D <substring> Disable any rules with names having the substring <substring>. Can be specified multiple times.\n"
|
||||
" Can not be specified with -t.\n"
|
||||
" -e <events_file> Read the events from <events_file> (in .scap format for sinsp events, or jsonl for\n"
|
||||
" k8s audit events) instead of tapping into live.\n"
|
||||
printf(
|
||||
"Falco version: " FALCO_VERSION "\n"
|
||||
"Usage: falco [options]\n\n"
|
||||
"Options:\n"
|
||||
" -h, --help Print this page\n"
|
||||
" -c Configuration file (default " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ")\n"
|
||||
" -A Monitor all events, including those with EF_DROP_SIMPLE_CONS flag.\n"
|
||||
" --alternate-lua-dir <path> Specify an alternate path for loading Falco lua files\n"
|
||||
" -b, --print-base64 Print data buffers in base64.\n"
|
||||
" This is useful for encoding binary data that needs to be used over media designed to.\n"
|
||||
" --cri <path> Path to CRI socket for container metadata.\n"
|
||||
" Use the specified socket to fetch data from a CRI-compatible runtime.\n"
|
||||
" -d, --daemon Run as a daemon.\n"
|
||||
" --disable-cri-async Disable asynchronous CRI metadata fetching.\n"
|
||||
" This is useful to let the input event wait for the container metadata fetch\n"
|
||||
" to finish before moving forward. Async fetching, in some environments leads\n"
|
||||
" to empty fields for container metadata when the fetch is not fast enough to be\n"
|
||||
" completed asynchronously. This can have a performance penalty on your environment\n"
|
||||
" depending on the number of containers and the frequency at which they are created/started/stopped\n"
|
||||
" --disable-source <event_source>\n"
|
||||
" Disable a specific event source.\n"
|
||||
" Available event sources are: syscall, k8s_audit.\n"
|
||||
" It can be passed multiple times.\n"
|
||||
" Can not disable both the event sources.\n"
|
||||
" -D <substring> Disable any rules with names having the substring <substring>. Can be specified multiple times.\n"
|
||||
" Can not be specified with -t.\n"
|
||||
" -e <events_file> Read the events from <events_file> (in .scap format for sinsp events, or jsonl for\n"
|
||||
" k8s audit events) instead of tapping into live.\n"
|
||||
#ifndef MINIMAL_BUILD
|
||||
" -k <url>, --k8s-api <url>\n"
|
||||
" Enable Kubernetes support by connecting to the API server specified as argument.\n"
|
||||
" E.g. \"http://admin:password@127.0.0.1:8080\".\n"
|
||||
" The API server can also be specified via the environment variable FALCO_K8S_API.\n"
|
||||
" -K <bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>], --k8s-api-cert <bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>]\n"
|
||||
" Use the provided files names to authenticate user and (optionally) verify the K8S API server identity.\n"
|
||||
" Each entry must specify full (absolute, or relative to the current directory) path to the respective file.\n"
|
||||
" Private key password is optional (needed only if key is password protected).\n"
|
||||
" CA certificate is optional. For all files, only PEM file format is supported. \n"
|
||||
" Specifying CA certificate only is obsoleted - when single entry is provided \n"
|
||||
" for this option, it will be interpreted as the name of a file containing bearer token.\n"
|
||||
" Note that the format of this command-line option prohibits use of files whose names contain\n"
|
||||
" ':' or '#' characters in the file name.\n"
|
||||
" -k <url>, --k8s-api <url>\n"
|
||||
" Enable Kubernetes support by connecting to the API server specified as argument.\n"
|
||||
" E.g. \"http://admin:password@127.0.0.1:8080\".\n"
|
||||
" The API server can also be specified via the environment variable FALCO_K8S_API.\n"
|
||||
" -K <bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>], --k8s-api-cert <bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>]\n"
|
||||
" Use the provided files names to authenticate user and (optionally) verify the K8S API server identity.\n"
|
||||
" Each entry must specify full (absolute, or relative to the current directory) path to the respective file.\n"
|
||||
" Private key password is optional (needed only if key is password protected).\n"
|
||||
" CA certificate is optional. For all files, only PEM file format is supported. \n"
|
||||
" Specifying CA certificate only is obsoleted - when single entry is provided \n"
|
||||
" for this option, it will be interpreted as the name of a file containing bearer token.\n"
|
||||
" Note that the format of this command-line option prohibits use of files whose names contain\n"
|
||||
" ':' or '#' characters in the file name.\n"
|
||||
#endif
|
||||
" -L Show the name and description of all rules and exit.\n"
|
||||
" -l <rule> Show the name and description of the rule with name <rule> and exit.\n"
|
||||
" --list [<source>] List all defined fields. If <source> is provided, only list those fields for\n"
|
||||
" the source <source>. Current values for <source> are \"syscall\", \"k8s_audit\"\n"
|
||||
" -L Show the name and description of all rules and exit.\n"
|
||||
" -l <rule> Show the name and description of the rule with name <rule> and exit.\n"
|
||||
" --list [<source>] List all defined fields. If <source> is provided, only list those fields for\n"
|
||||
" the source <source>. Current values for <source> are \"syscall\", \"k8s_audit\"\n"
|
||||
#ifndef MINIMAL_BUILD
|
||||
" -m <url[,marathon_url]>, --mesos-api <url[,marathon_url]>\n"
|
||||
" Enable Mesos support by connecting to the API server\n"
|
||||
" specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\".\n"
|
||||
" Marathon url is optional and defaults to Mesos address, port 8080.\n"
|
||||
" The API servers can also be specified via the environment variable FALCO_MESOS_API.\n"
|
||||
" -m <url[,marathon_url]>, --mesos-api <url[,marathon_url]>\n"
|
||||
" Enable Mesos support by connecting to the API server\n"
|
||||
" specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\".\n"
|
||||
" Marathon url is optional and defaults to Mesos address, port 8080.\n"
|
||||
" The API servers can also be specified via the environment variable FALCO_MESOS_API.\n"
|
||||
#endif
|
||||
" -M <num_seconds> Stop collecting after <num_seconds> reached.\n"
|
||||
" -N When used with --list, only print field names.\n"
|
||||
" -o, --option <key>=<val> Set the value of option <key> to <val>. Overrides values in configuration file.\n"
|
||||
" <key> can be a two-part <key>.<subkey>\n"
|
||||
" -p <output_format>, --print <output_format>\n"
|
||||
" Add additional information to each falco notification's output.\n"
|
||||
" With -pc or -pcontainer will use a container-friendly format.\n"
|
||||
" With -pk or -pkubernetes will use a kubernetes-friendly format.\n"
|
||||
" With -pm or -pmesos will use a mesos-friendly format.\n"
|
||||
" Additionally, specifying -pc/-pk/-pm will change the interpretation\n"
|
||||
" of %%container.info in rule output fields.\n"
|
||||
" -P, --pidfile <pid_file> When run as a daemon, write pid to specified file\n"
|
||||
" -s <stats_file> If specified, append statistics related to Falco's reading/processing of events\n"
|
||||
" to this file (only useful in live mode).\n"
|
||||
" --stats-interval <msec> When using -s <stats_file>, write statistics every <msec> ms.\n"
|
||||
" This uses signals, so don't recommend intervals below 200 ms.\n"
|
||||
" Defaults to 5000 (5 seconds).\n"
|
||||
" -S <len>, --snaplen <len>\n"
|
||||
" Capture the first <len> bytes of each I/O buffer.\n"
|
||||
" By default, the first 80 bytes are captured. Use this\n"
|
||||
" option with caution, it can generate huge trace files.\n"
|
||||
" --support Print support information including version, etc. and exit.\n"
|
||||
" -T <tag> Disable any rules with a tag=<tag>. Can be specified multiple times.\n"
|
||||
" Can not be specified with -t.\n"
|
||||
" -t <tag> Only run those rules with a tag=<tag>. Can be specified multiple times.\n"
|
||||
" Can not be specified with -T/-D.\n"
|
||||
" -U,--unbuffered Turn off output buffering to configured outputs.\n"
|
||||
" This causes every single line emitted by falco to be flushed,\n"
|
||||
" which generates higher CPU usage but is useful when piping those outputs\n"
|
||||
" into another process or into a script.\n"
|
||||
" -u, --userspace Parse events from userspace.\n"
|
||||
" To be used in conjunction with the ptrace(2) based driver (pdig).\n"
|
||||
" -V, --validate <rules_file> Read the contents of the specified rules(s) file and exit.\n"
|
||||
" Can be specified multiple times to validate multiple files.\n"
|
||||
" -v Verbose output.\n"
|
||||
" --version Print version number.\n"
|
||||
"\n");
|
||||
" -M <num_seconds> Stop collecting after <num_seconds> reached.\n"
|
||||
" -N When used with --list, only print field names.\n"
|
||||
" -o, --option <key>=<val> Set the value of option <key> to <val>. Overrides values in configuration file.\n"
|
||||
" <key> can be a two-part <key>.<subkey>\n"
|
||||
" -p <output_format>, --print <output_format>\n"
|
||||
" Add additional information to each falco notification's output.\n"
|
||||
" With -pc or -pcontainer will use a container-friendly format.\n"
|
||||
" With -pk or -pkubernetes will use a kubernetes-friendly format.\n"
|
||||
" With -pm or -pmesos will use a mesos-friendly format.\n"
|
||||
" Additionally, specifying -pc/-pk/-pm will change the interpretation\n"
|
||||
" of %%container.info in rule output fields.\n"
|
||||
" -P, --pidfile <pid_file> When run as a daemon, write pid to specified file\n"
|
||||
" -r <rules_file> Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml).\n"
|
||||
" Can be specified multiple times to read from multiple files/directories.\n"
|
||||
" -s <stats_file> If specified, append statistics related to Falco's reading/processing of events\n"
|
||||
" to this file (only useful in live mode).\n"
|
||||
" --stats-interval <msec> When using -s <stats_file>, write statistics every <msec> ms.\n"
|
||||
" This uses signals, so don't recommend intervals below 200 ms.\n"
|
||||
" Defaults to 5000 (5 seconds).\n"
|
||||
" -S <len>, --snaplen <len>\n"
|
||||
" Capture the first <len> bytes of each I/O buffer.\n"
|
||||
" By default, the first 80 bytes are captured. Use this\n"
|
||||
" option with caution, it can generate huge trace files.\n"
|
||||
" --support Print support information including version, rules files used, etc. and exit.\n"
|
||||
" -T <tag> Disable any rules with a tag=<tag>. Can be specified multiple times.\n"
|
||||
" Can not be specified with -t.\n"
|
||||
" -t <tag> Only run those rules with a tag=<tag>. Can be specified multiple times.\n"
|
||||
" Can not be specified with -T/-D.\n"
|
||||
" -U,--unbuffered Turn off output buffering to configured outputs.\n"
|
||||
" This causes every single line emitted by falco to be flushed,\n"
|
||||
" which generates higher CPU usage but is useful when piping those outputs\n"
|
||||
" into another process or into a script.\n"
|
||||
" -u, --userspace Parse events from userspace.\n"
|
||||
" To be used in conjunction with the ptrace(2) based driver (pdig).\n"
|
||||
" -V, --validate <rules_file> Read the contents of the specified rules(s) file and exit.\n"
|
||||
" Can be specified multiple times to validate multiple files.\n"
|
||||
" -v Verbose output.\n"
|
||||
" --version Print version number.\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void display_fatal_err(const string &msg)
|
||||
@@ -186,7 +192,7 @@ static void display_fatal_err(const string &msg)
|
||||
* If stderr logging is not enabled, also log to stderr. When
|
||||
* daemonized this will simply write to /dev/null.
|
||||
*/
|
||||
if(!falco_logger::log_stderr)
|
||||
if (! falco_logger::log_stderr)
|
||||
{
|
||||
std::cerr << msg;
|
||||
}
|
||||
@@ -238,20 +244,20 @@ static std::string read_file(std::string filename)
|
||||
//
|
||||
// Event processing loop
|
||||
//
|
||||
uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs,
|
||||
sinsp *inspector,
|
||||
falco_configuration &config,
|
||||
syscall_evt_drop_mgr &sdropmgr,
|
||||
uint64_t duration_to_tot_ns,
|
||||
string &stats_filename,
|
||||
uint64_t stats_interval,
|
||||
bool all_events,
|
||||
int &result)
|
||||
uint64_t do_inspect(falco_engine **engine,
|
||||
falco_outputs *outputs,
|
||||
sinsp* inspector,
|
||||
falco_configuration &config,
|
||||
syscall_evt_drop_mgr &sdropmgr,
|
||||
uint64_t duration_to_tot_ns,
|
||||
string &stats_filename,
|
||||
uint64_t stats_interval,
|
||||
bool all_events,
|
||||
int &result)
|
||||
{
|
||||
|
||||
uint64_t num_evts = 0;
|
||||
int32_t rc;
|
||||
sinsp_evt *ev;
|
||||
sinsp_evt* ev;
|
||||
StatsFileWriter writer;
|
||||
uint64_t duration_start = 0;
|
||||
|
||||
@@ -262,11 +268,11 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs,
|
||||
config.m_syscall_evt_drop_max_burst,
|
||||
config.m_syscall_evt_simulate_drops);
|
||||
|
||||
if(stats_filename != "")
|
||||
if (stats_filename != "")
|
||||
{
|
||||
string errstr;
|
||||
|
||||
if(!writer.init(inspector, stats_filename, stats_interval, errstr))
|
||||
if (!writer.init(inspector, stats_filename, stats_interval, errstr))
|
||||
{
|
||||
throw falco_exception(errstr);
|
||||
}
|
||||
@@ -274,8 +280,8 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs,
|
||||
|
||||
{
|
||||
// wait for the first engine to be ready
|
||||
std::unique_lock<std::mutex> lk(engine_ready);
|
||||
engine_cv.wait(lk, [] { return is_engine_ready; });
|
||||
std::unique_lock<std::mutex> lk(g_engine_ready);
|
||||
g_engine_cv.wait(lk, [] { return g_is_engine_ready; });
|
||||
}
|
||||
|
||||
//
|
||||
@@ -287,6 +293,7 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs,
|
||||
e.compare_exchange_strong(engine_to_use, *engine);
|
||||
while(1)
|
||||
{
|
||||
|
||||
rc = inspector->next(&ev);
|
||||
|
||||
writer.handle();
|
||||
@@ -302,7 +309,7 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs,
|
||||
falco_logger::log(LOG_INFO, "SIGINT received, exiting...\n");
|
||||
break;
|
||||
}
|
||||
else if(g_restart)
|
||||
else if (g_restart)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "SIGHUP received, restarting...\n");
|
||||
break;
|
||||
@@ -325,11 +332,10 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs,
|
||||
throw sinsp_exception(inspector->getlasterr().c_str());
|
||||
}
|
||||
|
||||
if(duration_start == 0)
|
||||
if (duration_start == 0)
|
||||
{
|
||||
duration_start = ev->get_ts();
|
||||
}
|
||||
else if(duration_to_tot_ns > 0)
|
||||
} else if(duration_to_tot_ns > 0)
|
||||
{
|
||||
if(ev->get_ts() - duration_start >= duration_to_tot_ns)
|
||||
{
|
||||
@@ -372,9 +378,9 @@ uint64_t do_inspect(falco_engine **engine, falco_outputs *outputs,
|
||||
|
||||
static void print_all_ignored_events(sinsp *inspector)
|
||||
{
|
||||
sinsp_evttables *einfo = inspector->get_event_info_tables();
|
||||
const struct ppm_event_info *etable = einfo->m_event_info;
|
||||
const struct ppm_syscall_desc *stable = einfo->m_syscall_info_table;
|
||||
sinsp_evttables* einfo = inspector->get_event_info_tables();
|
||||
const struct ppm_event_info* etable = einfo->m_event_info;
|
||||
const struct ppm_syscall_desc* stable = einfo->m_syscall_info_table;
|
||||
|
||||
std::set<string> ignored_event_names;
|
||||
for(uint32_t j = 0; j < PPM_EVENT_MAX; j++)
|
||||
@@ -438,11 +444,11 @@ static void rules_cb(char *rules_content, hawk_engine *engine)
|
||||
// This mutex is only needed for the first synchronization
|
||||
// it can be discarded the second time rules_cb is needed
|
||||
// since the main engine loop is already started.
|
||||
if(!is_engine_ready)
|
||||
if(!g_is_engine_ready)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(engine_ready);
|
||||
is_engine_ready = true;
|
||||
engine_cv.notify_all();
|
||||
std::lock_guard<std::mutex> lk(g_engine_ready);
|
||||
g_is_engine_ready = true;
|
||||
g_engine_cv.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +458,7 @@ static void rules_cb(char *rules_content, hawk_engine *engine)
|
||||
int falco_init(int argc, char **argv)
|
||||
{
|
||||
int result = EXIT_SUCCESS;
|
||||
sinsp *inspector = NULL;
|
||||
sinsp* inspector = NULL;
|
||||
sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL;
|
||||
falco_engine *engine_blueprint;
|
||||
std::thread watchrules_thread;
|
||||
@@ -476,9 +482,9 @@ int falco_init(int argc, char **argv)
|
||||
bool names_only = false;
|
||||
bool all_events = false;
|
||||
#ifndef MINIMAL_BUILD
|
||||
string *k8s_api = 0;
|
||||
string *k8s_api_cert = 0;
|
||||
string *mesos_api = 0;
|
||||
string* k8s_api = 0;
|
||||
string* k8s_api_cert = 0;
|
||||
string* mesos_api = 0;
|
||||
#endif
|
||||
string output_format = "";
|
||||
uint32_t snaplen = 0;
|
||||
@@ -503,7 +509,7 @@ int falco_init(int argc, char **argv)
|
||||
bool compress = false;
|
||||
bool buffered_outputs = true;
|
||||
bool buffered_cmdline = false;
|
||||
std::map<string, uint64_t> required_engine_versions;
|
||||
std::map<string,uint64_t> required_engine_versions;
|
||||
|
||||
// Used for stats
|
||||
double duration;
|
||||
@@ -555,8 +561,8 @@ int falco_init(int argc, char **argv)
|
||||
// Parse the args
|
||||
//
|
||||
while((op = getopt_long(argc, argv,
|
||||
"hc:AbdD:e:F:ik:K:Ll:m:M:No:P:p:S:s:T:t:UuvV:w:",
|
||||
long_options, &long_index)) != -1)
|
||||
"hc:AbdD:e:F:ik:K:Ll:m:M:No:P:p:r:S:s:T:t:UuvV:w:",
|
||||
long_options, &long_index)) != -1)
|
||||
{
|
||||
switch(op)
|
||||
{
|
||||
@@ -649,6 +655,9 @@ int falco_init(int argc, char **argv)
|
||||
replace_container_info = false;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
falco_configuration::read_rules_file_directory(string(optarg), rules_filenames);
|
||||
break;
|
||||
case 'S':
|
||||
snaplen = atoi(optarg);
|
||||
break;
|
||||
@@ -688,18 +697,18 @@ int falco_init(int argc, char **argv)
|
||||
printf("Driver version: %s\n", DRIVER_VERSION);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
else if(string(long_options[long_index].name) == "cri")
|
||||
else if (string(long_options[long_index].name) == "cri")
|
||||
{
|
||||
if(optarg != NULL)
|
||||
{
|
||||
cri_socket_path = optarg;
|
||||
}
|
||||
}
|
||||
else if(string(long_options[long_index].name) == "disable-cri-async")
|
||||
else if (string(long_options[long_index].name) == "disable-cri-async")
|
||||
{
|
||||
cri_async = false;
|
||||
cri_async = false;
|
||||
}
|
||||
else if(string(long_options[long_index].name) == "list")
|
||||
else if (string(long_options[long_index].name) == "list")
|
||||
{
|
||||
list_flds = true;
|
||||
if(optarg != NULL)
|
||||
@@ -707,28 +716,27 @@ int falco_init(int argc, char **argv)
|
||||
list_flds_source = optarg;
|
||||
}
|
||||
}
|
||||
else if(string(long_options[long_index].name) == "stats-interval")
|
||||
else if (string(long_options[long_index].name) == "stats-interval")
|
||||
{
|
||||
stats_interval = atoi(optarg);
|
||||
}
|
||||
else if(string(long_options[long_index].name) == "support")
|
||||
else if (string(long_options[long_index].name) == "support")
|
||||
{
|
||||
print_support = true;
|
||||
}
|
||||
else if(string(long_options[long_index].name) == "disable-source")
|
||||
else if (string(long_options[long_index].name) == "disable-source")
|
||||
{
|
||||
if(optarg != NULL)
|
||||
{
|
||||
disable_sources.insert(optarg);
|
||||
}
|
||||
}
|
||||
else if(string(long_options[long_index].name) == "alternate-lua-dir")
|
||||
else if (string(long_options[long_index].name)== "alternate-lua-dir")
|
||||
{
|
||||
if(optarg != NULL)
|
||||
{
|
||||
alternate_lua_dir = optarg;
|
||||
if(alternate_lua_dir.back() != '/')
|
||||
{
|
||||
if (alternate_lua_dir.back() != '/') {
|
||||
alternate_lua_dir += '/';
|
||||
}
|
||||
}
|
||||
@@ -738,6 +746,7 @@ int falco_init(int argc, char **argv)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inspector = new sinsp();
|
||||
@@ -771,11 +780,11 @@ int falco_init(int argc, char **argv)
|
||||
engine_blueprint->set_inspector(inspector);
|
||||
engine_blueprint->set_extra(output_format, replace_container_info);
|
||||
|
||||
// if(list_flds)
|
||||
// {
|
||||
// list_source_fields(engine, verbose, names_only, list_flds_source);
|
||||
// return EXIT_SUCCESS;
|
||||
// }
|
||||
if(list_flds)
|
||||
{
|
||||
// list_source_fields(engine, verbose, names_only, list_flds_source);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if(disable_sources.size() > 0)
|
||||
{
|
||||
@@ -791,23 +800,21 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
disable_syscall = disable_sources.count("syscall") > 0;
|
||||
disable_k8s_audit = disable_sources.count("k8s_audit") > 0;
|
||||
if(disable_syscall && disable_k8s_audit)
|
||||
{
|
||||
if (disable_syscall && disable_k8s_audit) {
|
||||
throw std::invalid_argument("The event source \"syscall\" and \"k8s_audit\" can not be disabled together");
|
||||
}
|
||||
}
|
||||
|
||||
// Some combinations of arguments are not allowed.
|
||||
if(daemon && pidfilename == "")
|
||||
{
|
||||
if (daemon && pidfilename == "") {
|
||||
throw std::invalid_argument("If -d is provided, a pid file must also be provided");
|
||||
}
|
||||
|
||||
ifstream conf_stream;
|
||||
if(conf_filename.size())
|
||||
if (conf_filename.size())
|
||||
{
|
||||
conf_stream.open(conf_filename);
|
||||
if(!conf_stream.is_open())
|
||||
if (!conf_stream.is_open())
|
||||
{
|
||||
throw std::runtime_error("Could not find configuration file at " + conf_filename);
|
||||
}
|
||||
@@ -815,14 +822,14 @@ int falco_init(int argc, char **argv)
|
||||
else
|
||||
{
|
||||
conf_stream.open(FALCO_SOURCE_CONF_FILE);
|
||||
if(conf_stream.is_open())
|
||||
if (conf_stream.is_open())
|
||||
{
|
||||
conf_filename = FALCO_SOURCE_CONF_FILE;
|
||||
}
|
||||
else
|
||||
{
|
||||
conf_stream.open(FALCO_INSTALL_CONF_FILE);
|
||||
if(conf_stream.is_open())
|
||||
if (conf_stream.is_open())
|
||||
{
|
||||
conf_filename = FALCO_INSTALL_CONF_FILE;
|
||||
}
|
||||
@@ -861,7 +868,7 @@ int falco_init(int argc, char **argv)
|
||||
// }
|
||||
|
||||
falco_configuration config;
|
||||
if(conf_filename.size())
|
||||
if (conf_filename.size())
|
||||
{
|
||||
config.init(conf_filename, cmdline_options);
|
||||
falco_logger::set_time_format_iso_8601(config.m_time_format_iso_8601);
|
||||
@@ -875,6 +882,11 @@ int falco_init(int argc, char **argv)
|
||||
throw std::runtime_error("Could not find configuration file at " + conf_filename);
|
||||
}
|
||||
|
||||
if (rules_filenames.size())
|
||||
{
|
||||
config.m_rules_filenames = rules_filenames;
|
||||
}
|
||||
|
||||
engine_blueprint->set_min_priority(config.m_min_priority);
|
||||
|
||||
if(buffered_cmdline)
|
||||
@@ -882,6 +894,60 @@ int falco_init(int argc, char **argv)
|
||||
config.m_buffered_outputs = buffered_outputs;
|
||||
}
|
||||
|
||||
if(config.m_rules_filenames.size() == 0)
|
||||
{
|
||||
// throw std::invalid_argument("You must specify at least one rules file/directory via -r or a rules_file entry in falco.yaml");
|
||||
}
|
||||
|
||||
falco_logger::log(LOG_DEBUG, "Configured rules filenames:\n");
|
||||
for (auto filename : config.m_rules_filenames)
|
||||
{
|
||||
falco_logger::log(LOG_DEBUG, string(" ") + filename + "\n");
|
||||
}
|
||||
|
||||
for (auto filename : config.m_rules_filenames)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Loading rules from file " + filename + ":\n");
|
||||
uint64_t required_engine_version;
|
||||
|
||||
// engine->load_rules_file(filename, verbose, all_events, required_engine_version);
|
||||
required_engine_versions[filename] = required_engine_version;
|
||||
}
|
||||
|
||||
// You can't both disable and enable rules
|
||||
if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) &&
|
||||
enabled_rule_tags.size() > 0) {
|
||||
throw std::invalid_argument("You can not specify both disabled (-D/-T) and enabled (-t) rules");
|
||||
}
|
||||
|
||||
for (auto substring : disabled_rule_substrings)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Disabling rules matching substring: " + substring + "\n");
|
||||
// engine->enable_rule(substring, false);
|
||||
}
|
||||
|
||||
if(disabled_rule_tags.size() > 0)
|
||||
{
|
||||
for(auto tag : disabled_rule_tags)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Disabling rules with tag: " + tag + "\n");
|
||||
}
|
||||
// engine->enable_rule_by_tag(disabled_rule_tags, false);
|
||||
}
|
||||
|
||||
if(enabled_rule_tags.size() > 0)
|
||||
{
|
||||
|
||||
// Since we only want to enable specific
|
||||
// rules, first disable all rules.
|
||||
// engine->enable_rule(all_rules, false);
|
||||
for(auto tag : enabled_rule_tags)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Enabling rules with tag: " + tag + "\n");
|
||||
}
|
||||
// engine->enable_rule_by_tag(enabled_rule_tags, true);
|
||||
}
|
||||
|
||||
hawk_init();
|
||||
watchrules_thread = std::thread([&] {
|
||||
// todo: pass verbose, and all_events
|
||||
@@ -980,14 +1046,24 @@ int falco_init(int argc, char **argv)
|
||||
support["system_info"]["machine"] = sysinfo.machine;
|
||||
support["cmdline"] = cmdline;
|
||||
support["config"] = read_file(conf_filename);
|
||||
support["rules_source"] = "external"; // todo(fntlnz): do we want to let libhawk pass an identifier and maybe more dump info for this?
|
||||
support["rules_files"] = nlohmann::json::array();
|
||||
for(auto filename : config.m_rules_filenames)
|
||||
{
|
||||
nlohmann::json finfo;
|
||||
finfo["name"] = filename;
|
||||
nlohmann::json variant;
|
||||
variant["required_engine_version"] = required_engine_versions[filename];
|
||||
variant["content"] = read_file(filename);
|
||||
finfo["variants"].push_back(variant);
|
||||
support["rules_files"].push_back(finfo);
|
||||
}
|
||||
printf("%s\n", support.dump().c_str());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// read hostname
|
||||
string hostname;
|
||||
if(char *env_hostname = getenv("FALCO_GRPC_HOSTNAME"))
|
||||
if(char* env_hostname = getenv("FALCO_GRPC_HOSTNAME"))
|
||||
{
|
||||
hostname = env_hostname;
|
||||
}
|
||||
@@ -1007,13 +1083,13 @@ int falco_init(int argc, char **argv)
|
||||
inspector->set_drop_event_flags(EF_DROP_SIMPLE_CONS);
|
||||
}
|
||||
|
||||
if(describe_all_rules)
|
||||
if (describe_all_rules)
|
||||
{
|
||||
// engine->describe_rule(NULL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if(describe_rule != "")
|
||||
if (describe_rule != "")
|
||||
{
|
||||
// engine->describe_rule(&describe_rule);
|
||||
goto exit;
|
||||
@@ -1051,25 +1127,21 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
// If daemonizing, do it here so any init errors will
|
||||
// be returned in the foreground process.
|
||||
if(daemon && !g_daemonized)
|
||||
{
|
||||
if (daemon && !g_daemonized) {
|
||||
pid_t pid, sid;
|
||||
|
||||
pid = fork();
|
||||
if(pid < 0)
|
||||
{
|
||||
if (pid < 0) {
|
||||
// error
|
||||
falco_logger::log(LOG_ERR, "Could not fork. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
else if(pid > 0)
|
||||
{
|
||||
} else if (pid > 0) {
|
||||
// parent. Write child pid to pidfile and exit
|
||||
std::ofstream pidfile;
|
||||
pidfile.open(pidfilename);
|
||||
|
||||
if(!pidfile.good())
|
||||
if (!pidfile.good())
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "Could not write pid to pid file " + pidfilename + ". Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
@@ -1083,8 +1155,7 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
// Become own process group.
|
||||
sid = setsid();
|
||||
if(sid < 0)
|
||||
{
|
||||
if (sid < 0) {
|
||||
falco_logger::log(LOG_ERR, "Could not set session id. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
@@ -1094,8 +1165,7 @@ int falco_init(int argc, char **argv)
|
||||
umask(027);
|
||||
|
||||
// Change working directory to '/'
|
||||
if((chdir("/")) < 0)
|
||||
{
|
||||
if ((chdir("/")) < 0) {
|
||||
falco_logger::log(LOG_ERR, "Could not change working directory to '/'. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
@@ -1131,15 +1201,14 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
// Try to open the trace file as a sysdig
|
||||
// capture file first.
|
||||
try
|
||||
{
|
||||
try {
|
||||
inspector->open(trace_filename);
|
||||
falco_logger::log(LOG_INFO, "Reading system call events from file: " + trace_filename + "\n");
|
||||
}
|
||||
catch(sinsp_exception &e)
|
||||
{
|
||||
falco_logger::log(LOG_DEBUG, "Could not read trace file \"" + trace_filename + "\": " + string(e.what()));
|
||||
trace_is_scap = false;
|
||||
trace_is_scap=false;
|
||||
}
|
||||
|
||||
if(!trace_is_scap)
|
||||
@@ -1150,8 +1219,7 @@ int falco_init(int argc, char **argv)
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
#else
|
||||
try
|
||||
{
|
||||
try {
|
||||
string line;
|
||||
nlohmann::json j;
|
||||
|
||||
@@ -1163,13 +1231,13 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
falco_logger::log(LOG_INFO, "Reading k8s audit events from file: " + trace_filename + "\n");
|
||||
}
|
||||
catch(nlohmann::json::parse_error &e)
|
||||
catch (nlohmann::json::parse_error& e)
|
||||
{
|
||||
fprintf(stderr, "Trace filename %s not recognized as system call events or k8s audit events\n", trace_filename.c_str());
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
catch(exception &e)
|
||||
catch (exception &e)
|
||||
{
|
||||
fprintf(stderr, "Could not open trace filename %s for reading: %s\n", trace_filename.c_str(), e.what());
|
||||
result = EXIT_FAILURE;
|
||||
@@ -1180,7 +1248,8 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
open_t open_cb = [&userspace](sinsp *inspector) {
|
||||
open_t open_cb = [&userspace](sinsp* inspector)
|
||||
{
|
||||
if(userspace)
|
||||
{
|
||||
// open_udig() is the underlying method used in the capture code to parse userspace events from the kernel.
|
||||
@@ -1192,22 +1261,19 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
inspector->open();
|
||||
};
|
||||
open_t open_nodriver_cb = [](sinsp *inspector) {
|
||||
open_t open_nodriver_cb = [](sinsp* inspector) {
|
||||
inspector->open_nodriver();
|
||||
};
|
||||
open_t open_f;
|
||||
|
||||
// Default mode: both event sources enabled
|
||||
if(!disable_syscall && !disable_k8s_audit)
|
||||
{
|
||||
if (!disable_syscall && !disable_k8s_audit) {
|
||||
open_f = open_cb;
|
||||
}
|
||||
if(disable_syscall)
|
||||
{
|
||||
if (disable_syscall) {
|
||||
open_f = open_nodriver_cb;
|
||||
}
|
||||
if(disable_k8s_audit)
|
||||
{
|
||||
if (disable_k8s_audit) {
|
||||
open_f = open_cb;
|
||||
}
|
||||
|
||||
@@ -1218,7 +1284,7 @@ int falco_init(int argc, char **argv)
|
||||
catch(sinsp_exception &e)
|
||||
{
|
||||
// If syscall input source is enabled and not through userspace instrumentation
|
||||
if(!disable_syscall && !userspace)
|
||||
if (!disable_syscall && !userspace)
|
||||
{
|
||||
// Try to insert the Falco kernel module
|
||||
if(system("modprobe " PROBE_NAME " > /dev/null 2> /dev/null"))
|
||||
@@ -1226,8 +1292,8 @@ int falco_init(int argc, char **argv)
|
||||
falco_logger::log(LOG_ERR, "Unable to load the driver.\n");
|
||||
}
|
||||
open_f(inspector);
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
rethrow_exception(current_exception());
|
||||
}
|
||||
@@ -1256,7 +1322,7 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
if(!k8s_api_cert)
|
||||
{
|
||||
if(char *k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
|
||||
if(char* k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
|
||||
{
|
||||
k8s_api_cert = new string(k8s_cert_env);
|
||||
}
|
||||
@@ -1265,13 +1331,13 @@ int falco_init(int argc, char **argv)
|
||||
k8s_api = 0;
|
||||
k8s_api_cert = 0;
|
||||
}
|
||||
else if(char *k8s_api_env = getenv("FALCO_K8S_API"))
|
||||
else if(char* k8s_api_env = getenv("FALCO_K8S_API"))
|
||||
{
|
||||
if(k8s_api_env != NULL)
|
||||
{
|
||||
if(!k8s_api_cert)
|
||||
{
|
||||
if(char *k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
|
||||
if(char* k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
|
||||
{
|
||||
k8s_api_cert = new string(k8s_cert_env);
|
||||
}
|
||||
@@ -1295,7 +1361,7 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
inspector->init_mesos_client(mesos_api, verbose);
|
||||
}
|
||||
else if(char *mesos_api_env = getenv("FALCO_MESOS_API"))
|
||||
else if(char* mesos_api_env = getenv("FALCO_MESOS_API"))
|
||||
{
|
||||
if(mesos_api_env != NULL)
|
||||
{
|
||||
@@ -1310,7 +1376,7 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
// std::string ssl_option = (config.m_webserver_ssl_enabled ? " (SSL)" : "");
|
||||
// falco_logger::log(LOG_INFO, "Starting internal webserver, listening on port " + to_string(config.m_webserver_listen_port) + ssl_option + "\n");
|
||||
// webserver.init(&config, engine_future.get().get(), outputs);
|
||||
// webserver.init(&config, engine, outputs);
|
||||
// webserver.start();
|
||||
}
|
||||
|
||||
@@ -1326,17 +1392,19 @@ int falco_init(int argc, char **argv)
|
||||
config.m_grpc_private_key,
|
||||
config.m_grpc_cert_chain,
|
||||
config.m_grpc_root_certs,
|
||||
config.m_log_level);
|
||||
config.m_log_level
|
||||
);
|
||||
grpc_server_thread = std::thread([&grpc_server] {
|
||||
grpc_server.run();
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if(!trace_filename.empty() && !trace_is_scap)
|
||||
{
|
||||
#ifndef MINIMAL_BUILD
|
||||
// read_k8s_audit_trace_file(engine.get(),
|
||||
#ifndef MINIMAL_BUILD
|
||||
// read_k8s_audit_trace_file(engine,
|
||||
// outputs,
|
||||
// trace_filename);
|
||||
#endif
|
||||
@@ -1345,11 +1413,12 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
uint64_t num_evts;
|
||||
|
||||
num_evts = do_inspect(&engine_blueprint, outputs,
|
||||
num_evts = do_inspect(&engine_blueprint,
|
||||
outputs,
|
||||
inspector,
|
||||
config,
|
||||
sdropmgr,
|
||||
uint64_t(duration_to_tot * ONE_SECOND_IN_NS),
|
||||
uint64_t(duration_to_tot*ONE_SECOND_IN_NS),
|
||||
stats_filename,
|
||||
stats_interval,
|
||||
all_events,
|
||||
@@ -1370,12 +1439,13 @@ int falco_init(int argc, char **argv)
|
||||
num_evts,
|
||||
num_evts / duration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Honor -M also when using a trace file.
|
||||
// Since inspection stops as soon as all events have been consumed
|
||||
// just await the given duration is reached, if needed.
|
||||
if(!trace_filename.empty() && duration_to_tot > 0)
|
||||
if(!trace_filename.empty() && duration_to_tot>0)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::seconds(duration_to_tot));
|
||||
}
|
||||
@@ -1400,14 +1470,13 @@ int falco_init(int argc, char **argv)
|
||||
catch(exception &e)
|
||||
{
|
||||
display_fatal_err("Runtime error: " + string(e.what()) + ". Exiting.\n");
|
||||
|
||||
result = EXIT_FAILURE;
|
||||
|
||||
if(watchrules_thread.joinable())
|
||||
{
|
||||
hawk_destroy();
|
||||
watchrules_thread.join();
|
||||
}
|
||||
result = EXIT_FAILURE;
|
||||
|
||||
#ifndef MINIMAL_BUILD
|
||||
webserver.stop();
|
||||
if(grpc_server_thread.joinable())
|
||||
|
||||
Reference in New Issue
Block a user