Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Container info in engine #151

Merged
merged 4 commits into from
Dec 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions test/falco_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ def setUp(self):
"""
self.falcodir = self.params.get('falcodir', '/', default=os.path.join(self.basedir, '../build'))

self.stderr_contains = self.params.get('stderr_contains', '*', default='')
self.exit_status = self.params.get('exit_status', '*', default=0)
self.should_detect = self.params.get('detect', '*', default=False)
self.trace_file = self.params.get('trace_file', '*')

Expand Down Expand Up @@ -197,9 +199,18 @@ def test(self):

res = self.falco_proc.run(timeout=180, sig=9)

if self.stderr_contains != '':
match = re.search(self.stderr_contains, res.stderr)
if match is None:
self.fail("Stderr of falco process did not contain content matching {}".format(self.stderr_contains))

if res.exit_status != self.exit_status:
self.error("Falco command \"{}\" exited with unexpected return value {} (!= {})".format(
cmd, res.exit_status, self.exit_status))

# No need to check any outputs if the falco process exited abnormally.
if res.exit_status != 0:
self.error("Falco command \"{}\" exited with non-zero return value {}".format(
cmd, res.exit_status))
return

self.check_rules_warnings(res)
if len(self.rules_events) > 0:
Expand Down
7 changes: 7 additions & 0 deletions test/falco_tests.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ trace_files: !mux
- rules/double_rule.yaml
trace_file: trace_files/cat_write.scap

invalid_rule_output:
exit_status: 1
stderr_contains: "Runtime error: Error loading rules:.* Invalid output format 'An open was seen %not_a_real_field': 'invalid formatting token not_a_real_field'. Exiting."
rules_file:
- rules/invalid_rule_output.yaml
trace_file: trace_files/cat_write.scap

disabled_rules:
detect: False
rules_file:
Expand Down
5 changes: 5 additions & 0 deletions test/rules/invalid_rule_output.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- rule: rule_with_invalid_output
desc: A rule with an invalid output field
condition: evt.type=open
output: "An open was seen %not_a_real_field"
priority: WARNING
2 changes: 1 addition & 1 deletion userspace/engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp")
include_directories("${PROJECT_BINARY_DIR}/userspace/engine")
include_directories("${LUAJIT_INCLUDE}")

add_library(falco_engine STATIC rules.cpp falco_common.cpp falco_engine.cpp)
add_library(falco_engine STATIC rules.cpp falco_common.cpp falco_engine.cpp formats.cpp)

target_include_directories(falco_engine PUBLIC
"${LUAJIT_INCLUDE}")
Expand Down
30 changes: 24 additions & 6 deletions userspace/engine/falco_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
#include "falco_engine.h"
#include "config_falco_engine.h"

#include "formats.h"

extern "C" {
#include "lpeg.h"
#include "lyaml.h"
Expand All @@ -38,7 +40,8 @@ string lua_print_stats = "print_stats";
using namespace std;

falco_engine::falco_engine(bool seed_rng)
: m_rules(NULL), m_sampling_ratio(1), m_sampling_multiplier(0)
: m_rules(NULL), m_sampling_ratio(1), m_sampling_multiplier(0),
m_replace_container_info(false)
{
luaopen_lpeg(m_ls);
luaopen_yaml(m_ls);
Expand Down Expand Up @@ -72,7 +75,16 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
{
m_rules = new falco_rules(m_inspector, this, m_ls);
}
m_rules->load_rules(rules_content, verbose, all_events);

// Note that falco_formats is added to both the lua state used
// by the falco engine as well as the separate lua state used
// by falco outputs. Within the engine, only
// formats.formatter is used, so we can unconditionally set
// json_output to false.
bool json_output = false;
falco_formats::init(m_inspector, m_ls, json_output);

m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info);
}

void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events)
Expand All @@ -98,20 +110,20 @@ void falco_engine::enable_rule(string &pattern, bool enabled)
m_evttype_filter.enable(pattern, enabled);
}

falco_engine::rule_result *falco_engine::process_event(sinsp_evt *ev)
unique_ptr<falco_engine::rule_result> falco_engine::process_event(sinsp_evt *ev)
{

if(should_drop_evt())
{
return NULL;
return unique_ptr<struct rule_result>();
}

if(!m_evttype_filter.run(ev))
{
return NULL;
return unique_ptr<struct rule_result>();
}

struct rule_result *res = new rule_result();
unique_ptr<struct rule_result> res(new rule_result());

lua_getglobal(m_ls, lua_on_event.c_str());

Expand Down Expand Up @@ -184,6 +196,12 @@ void falco_engine::set_sampling_multiplier(double sampling_multiplier)
m_sampling_multiplier = sampling_multiplier;
}

void falco_engine::set_extra(string &extra, bool replace_container_info)
{
m_extra = extra;
m_replace_container_info = replace_container_info;
}

inline bool falco_engine::should_drop_evt()
{
if(m_sampling_multiplier == 0)
Expand Down
15 changes: 14 additions & 1 deletion userspace/engine/falco_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class falco_engine : public falco_common
// the rule that matched. If no rule matched, returns NULL.
//
// the reutrned rule_result is allocated and must be delete()d.
rule_result *process_event(sinsp_evt *ev);
std::unique_ptr<rule_result> process_event(sinsp_evt *ev);

//
// Print details on the given rule. If rule is NULL, print
Expand Down Expand Up @@ -96,6 +96,16 @@ class falco_engine : public falco_common
//
void set_sampling_multiplier(double sampling_multiplier);

//
// You can optionally add "extra" formatting fields to the end
// 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
// available.
//
void set_extra(string &extra, bool replace_container_info);

private:

//
Expand Down Expand Up @@ -132,5 +142,8 @@ class falco_engine : public falco_common
double m_sampling_multiplier;

std::string m_lua_main_filename = "rule_loader.lua";

std::string m_extra;
bool m_replace_container_info;
};

8 changes: 4 additions & 4 deletions userspace/falco/formats.cpp → userspace/engine/formats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void falco_formats::init(sinsp* inspector, lua_State *ls, bool json_output)
s_inspector = inspector;
s_json_output = json_output;

luaL_openlib(ls, "falco", ll_falco, 0);
luaL_openlib(ls, "formats", ll_falco, 0);
}

int falco_formats::formatter(lua_State *ls)
Expand All @@ -52,7 +52,7 @@ int falco_formats::formatter(lua_State *ls)
}
catch(sinsp_exception& e)
{
throw falco_exception("Invalid output format '" + format + "'.\n");
luaL_error(ls, "Invalid output format '%s': '%s'", format.c_str(), e.what());
}

lua_pushlightuserdata(ls, formatter);
Expand All @@ -64,14 +64,14 @@ int falco_formats::free_formatter(lua_State *ls)
{
if (!lua_islightuserdata(ls, -1))
{
throw falco_exception("Invalid argument passed to free_formatter");
luaL_error(ls, "Invalid argument passed to free_formatter");
}

sinsp_evt_formatter *formatter = (sinsp_evt_formatter *) lua_topointer(ls, 1);

delete(formatter);

return 1;
return 0;
}

int falco_formats::format_event (lua_State *ls)
Expand Down
3 changes: 0 additions & 3 deletions userspace/falco/formats.h → userspace/engine/formats.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,4 @@ class falco_formats
static int format_event(lua_State *ls);

static sinsp* s_inspector;

private:
lua_State* m_ls;
};
32 changes: 31 additions & 1 deletion userspace/engine/lua/rule_loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ function table.tostring( tbl )
end


function load_rules(rules_content, rules_mgr, verbose, all_events)
function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replace_container_info)

compiler.set_verbose(verbose)
compiler.set_all_events(all_events)
Expand Down Expand Up @@ -257,6 +257,36 @@ function load_rules(rules_content, rules_mgr, verbose, all_events)
if (v['enabled'] == false) then
falco_rules.enable_rule(rules_mgr, v['rule'], 0)
end

-- If the format string contains %container.info, replace it
-- with extra. Otherwise, add extra onto the end of the format
-- string.
if string.find(v['output'], "%container.info", nil, true) ~= nil then

-- There may not be any extra, or we're not supposed
-- to replace it, in which case we use the generic
-- "%container.name (id=%container.id)"
if replace_container_info == false then
v['output'] = string.gsub(v['output'], "%%container.info", "%%container.name (id=%%container.id)")
if extra ~= "" then
v['output'] = v['output'].." "..extra
end
else
safe_extra = string.gsub(extra, "%%", "%%%%")
v['output'] = string.gsub(v['output'], "%%container.info", safe_extra)
end
else
-- Just add the extra to the end
if extra ~= "" then
v['output'] = v['output'].." "..extra
end
end

-- Ensure that the output field is properly formatted by
-- creating a formatter from it. Any error will be thrown
-- up to the top level.
formatter = formats.formatter(v['output'])
formats.free_formatter(formatter)
else
error ("Unexpected type in load_rule: "..filter_ast.type)
end
Expand Down
8 changes: 6 additions & 2 deletions userspace/engine/rules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ void falco_rules::enable_rule(string &rule, bool enabled)
m_engine->enable_rule(rule, enabled);
}

void falco_rules::load_rules(const string &rules_content, bool verbose, bool all_events)
void falco_rules::load_rules(const string &rules_content,
bool verbose, bool all_events,
string &extra, bool replace_container_info)
{
lua_getglobal(m_ls, m_lua_load_rules.c_str());
if(lua_isfunction(m_ls, -1))
Expand Down Expand Up @@ -182,7 +184,9 @@ void falco_rules::load_rules(const string &rules_content, bool verbose, bool all
lua_pushlightuserdata(m_ls, this);
lua_pushboolean(m_ls, (verbose ? 1 : 0));
lua_pushboolean(m_ls, (all_events ? 1 : 0));
if(lua_pcall(m_ls, 4, 0, 0) != 0)
lua_pushstring(m_ls, extra.c_str());
lua_pushboolean(m_ls, (replace_container_info ? 1 : 0));
if(lua_pcall(m_ls, 6, 0, 0) != 0)
{
const char* lerr = lua_tostring(m_ls, -1);
string err = "Error loading rules:" + string(lerr);
Expand Down
3 changes: 2 additions & 1 deletion userspace/engine/rules.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class falco_rules
public:
falco_rules(sinsp* inspector, falco_engine *engine, lua_State *ls);
~falco_rules();
void load_rules(const string &rules_content, bool verbose, bool all_events);
void load_rules(const string &rules_content, bool verbose, bool all_events,
std::string &extra, bool replace_container_info);
void describe_rule(string *rule);

static void init(lua_State *ls);
Expand Down
2 changes: 1 addition & 1 deletion userspace/falco/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ include_directories("${CURL_INCLUDE_DIR}")
include_directories("${YAMLCPP_INCLUDE_DIR}")
include_directories("${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include")

add_executable(falco configuration.cpp formats.cpp logger.cpp falco_outputs.cpp falco.cpp)
add_executable(falco configuration.cpp logger.cpp falco_outputs.cpp falco.cpp)

target_link_libraries(falco falco_engine sinsp)
target_link_libraries(falco
Expand Down
5 changes: 2 additions & 3 deletions userspace/falco/falco.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,10 @@ uint64_t do_inspect(falco_engine *engine,
// engine, which will match the event against the set
// of rules. If a match is found, pass the event to
// the outputs.
falco_engine::rule_result *res = engine->process_event(ev);
unique_ptr<falco_engine::rule_result> res = engine->process_event(ev);
if(res)
{
outputs->handle_event(res->evt, res->rule, res->priority, res->format);
delete(res);
}

num_evts++;
Expand Down Expand Up @@ -337,10 +336,10 @@ int falco_init(int argc, char **argv)
inspector = new sinsp();
engine = new falco_engine();
engine->set_inspector(inspector);
engine->set_extra(output_format, replace_container_info);

outputs = new falco_outputs();
outputs->set_inspector(inspector);
outputs->set_extra(output_format, replace_container_info);

// Some combinations of arguments are not allowed.
if (daemon && pidfilename == "") {
Expand Down
42 changes: 4 additions & 38 deletions userspace/falco/falco_outputs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
using namespace std;

falco_outputs::falco_outputs()
: m_replace_container_info(false)
{

}
Expand All @@ -47,17 +46,14 @@ void falco_outputs::init(bool json_output)

falco_common::init(m_lua_main_filename.c_str(), FALCO_SOURCE_LUA_DIR);

// Note that falco_formats is added to both the lua state used
// by the falco engine as well as the separate lua state used
// by falco outputs.
falco_formats::init(m_inspector, m_ls, json_output);

falco_logger::init(m_ls);
}

void falco_outputs::set_extra(string &extra, bool replace_container_info)
{
m_extra = extra;
m_replace_container_info = replace_container_info;
}

void falco_outputs::add_output(output_config oc)
{
uint8_t nargs = 1;
Expand Down Expand Up @@ -94,42 +90,12 @@ void falco_outputs::handle_event(sinsp_evt *ev, string &level, string &priority,
{
lua_getglobal(m_ls, m_lua_output_event.c_str());

// If the format string contains %container.info, replace it
// with extra. Otherwise, add extra onto the end of the format
// string.
string format_w_extra = format;
size_t pos;

if((pos = format_w_extra.find("%container.info")) != string::npos)
{
// There may not be any extra, or we're not supposed
// to replace it, in which case we use the generic
// "%container.name (id=%container.id)"
if(m_extra == "" || ! m_replace_container_info)
{
// 15 == strlen(%container.info)
format_w_extra.replace(pos, 15, "%container.name (id=%container.id)");
}
else
{
format_w_extra.replace(pos, 15, m_extra);
}
}
else
{
// Just add the extra to the end
if (m_extra != "")
{
format_w_extra += " " + m_extra;
}
}

if(lua_isfunction(m_ls, -1))
{
lua_pushlightuserdata(m_ls, ev);
lua_pushstring(m_ls, level.c_str());
lua_pushstring(m_ls, priority.c_str());
lua_pushstring(m_ls, format_w_extra.c_str());
lua_pushstring(m_ls, format.c_str());

if(lua_pcall(m_ls, 4, 0, 0) != 0)
{
Expand Down
Loading