Skip to content
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
8 changes: 6 additions & 2 deletions test/falco_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ trace_files: !mux
detect: True
detect_level: WARNING
rules_file:
- rules/single_rule.yaml
- rules/single_rule_with_tags.yaml
conf_file: confs/stdout_output.yaml
trace_file: trace_files/cat_write.scap
time_iso_8601: true
Expand Down Expand Up @@ -721,7 +721,7 @@ trace_files: !mux
detect: True
detect_level: WARNING
rules_file:
- rules/single_rule.yaml
- rules/single_rule_with_tags.yaml
conf_file: confs/grpc_unix_socket.yaml
trace_file: trace_files/cat_write.scap
run_duration: 5
Expand All @@ -745,6 +745,10 @@ trace_files: !mux
# For the hostname, since we don't know that beforehand,
# only check the field presence
- "hostname: "
#tags
- "tags: \"filesystem\""
- "tags: \"process\""
- "tags: \"testing\""

detect_counts:
detect: True
Expand Down
16 changes: 8 additions & 8 deletions test/output_files/single_rule_with_cat_write.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{"output":"2016-08-04T16:17:57.881781397+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881781397Z", "output_fields": {"evt.time.iso8601":1470327477881781397,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.881785348+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881785348Z", "output_fields": {"evt.time.iso8601":1470327477881785348,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.881796705+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881796705Z", "output_fields": {"evt.time.iso8601":1470327477881796705,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.881799840+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881799840Z", "output_fields": {"evt.time.iso8601":1470327477881799840,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.882003104+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882003104Z", "output_fields": {"evt.time.iso8601":1470327477882003104,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.882008208+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882008208Z", "output_fields": {"evt.time.iso8601":1470327477882008208,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.882045694+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882045694Z", "output_fields": {"evt.time.iso8601":1470327477882045694,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.882054739+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882054739Z", "output_fields": {"evt.time.iso8601":1470327477882054739,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.881781397+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.881781397Z", "output_fields": {"evt.time.iso8601":1470327477881781397,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.881785348+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.881785348Z", "output_fields": {"evt.time.iso8601":1470327477881785348,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.881796705+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.881796705Z", "output_fields": {"evt.time.iso8601":1470327477881796705,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.881799840+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.881799840Z", "output_fields": {"evt.time.iso8601":1470327477881799840,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.882003104+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.882003104Z", "output_fields": {"evt.time.iso8601":1470327477882003104,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.882008208+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.882008208Z", "output_fields": {"evt.time.iso8601":1470327477882008208,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.882045694+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.882045694Z", "output_fields": {"evt.time.iso8601":1470327477882045694,"proc.cmdline":"cat /dev/null"}}
{"output":"2016-08-04T16:17:57.882054739+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.882054739Z", "output_fields": {"evt.time.iso8601":1470327477882054739,"proc.cmdline":"cat /dev/null"}}
34 changes: 34 additions & 0 deletions test/rules/single_rule_with_tags.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#
# Copyright (C) 2021 The Falco Authors.
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

- required_engine_version: 2

- list: cat_binaries
items: [cat]

- list: cat_capable_binaries
items: [cat_binaries]

- macro: is_cat
condition: proc.name in (cat_capable_binaries)

- rule: open_from_cat
desc: A process named cat does an open
condition: evt.type=open and is_cat
output: "An open was seen (command=%proc.cmdline)"
priority: WARNING
tags: [filesystem, process, testing]
21 changes: 16 additions & 5 deletions userspace/engine/falco_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,18 +342,29 @@ void falco_engine::populate_rule_result(unique_ptr<struct rule_result> &res, gen
if(lua_isfunction(m_ls, -1))
{
lua_pushnumber(m_ls, ev->get_check_id());

if(lua_pcall(m_ls, 1, 4, 0) != 0)
if(lua_pcall(m_ls, 1, 5, 0) != 0)
{
const char* lerr = lua_tostring(m_ls, -1);
string err = "Error invoking function output: " + string(lerr);
throw falco_exception(err);
}
const char *p = lua_tostring(m_ls, -4);
const char *p = lua_tostring(m_ls, -5);
res->rule = p;
res->evt = ev;
res->priority_num = (falco_common::priority_type) lua_tonumber(m_ls, -3);
res->format = lua_tostring(m_ls, -2);
res->priority_num = (falco_common::priority_type) lua_tonumber(m_ls, -4);
res->format = lua_tostring(m_ls, -3);

// Tags are passed back as a table, and is on the top of the stack
lua_pushnil(m_ls); /* first key */
while (lua_next(m_ls, -2) != 0) {
// key is at index -2, value is at index
// -1. We want the value.
res->tags.insert(luaL_checkstring(m_ls, -1));

// Remove value, keep key for next iteration
lua_pop(m_ls, 1);
}
lua_pop(m_ls, 1); // Clean table leftover

// Exception fields are passed back as a table
lua_pushnil(m_ls); /* first key */
Expand Down
1 change: 1 addition & 0 deletions userspace/engine/falco_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class falco_engine : public falco_common
falco_common::priority_type priority_num;
std::string format;
std::set<std::string> exception_fields;
std::set<std::string> tags;
};

//
Expand Down
11 changes: 10 additions & 1 deletion userspace/engine/formats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ int falco_formats::lua_free_formatter(lua_State *ls)
}

string falco_formats::format_event(const gen_event *evt, const std::string &rule, const std::string &source,
const std::string &level, const std::string &format)
const std::string &level, const std::string &format, std::set<std::string> &tags)
{

string line;
Expand Down Expand Up @@ -181,8 +181,10 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
if(s_json_output)
{
Json::Value event;
Json::Value rule_tags;
Json::FastWriter writer;
string full_line;
unsigned int rule_tags_idx = 0;

// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
time_t evttime = evt->get_ts() / 1000000000;
Expand All @@ -197,12 +199,19 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
event["time"] = iso8601evttime;
event["rule"] = rule;
event["priority"] = level;
event["source"] = source;

if(s_json_include_output_property)
{
// This is the filled-in output line.
event["output"] = line;
}

for (auto &tag : tags)
{
rule_tags[rule_tags_idx++] = tag;
}
event["tags"] = rule_tags;

full_line = writer.write(event);

Expand Down
2 changes: 1 addition & 1 deletion userspace/engine/formats.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class falco_formats
static int lua_free_formatter(lua_State *ls);

static string format_event(const gen_event *evt, const std::string &rule, const std::string &source,
const std::string &level, const std::string &format);
const std::string &level, const std::string &format, std::set<std::string> &tags);

static map<string, string> resolve_tokens(const gen_event *evt, const std::string &source,
const std::string &format);
Expand Down
2 changes: 1 addition & 1 deletion userspace/engine/lua/rule_loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ function on_event(rule_id)
error ("rule_loader.on_event(): could not find rule by name: ", rule.rule)
end

return rule.rule, rule.priority_num, output, combined_rule.exception_fields
return rule.rule, rule.priority_num, output, combined_rule.exception_fields, rule.tags
end

function print_stats()
Expand Down
2 changes: 1 addition & 1 deletion userspace/falco/falco.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ uint64_t do_inspect(falco_engine *engine,
unique_ptr<falco_engine::rule_result> res = engine->process_sinsp_event(ev);
if(res)
{
outputs->handle_event(res->evt, res->rule, res->source, res->priority_num, res->format);
outputs->handle_event(res->evt, res->rule, res->source, res->priority_num, res->format, res->tags);
}

num_evts++;
Expand Down
5 changes: 3 additions & 2 deletions userspace/falco/falco_outputs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ void falco_outputs::add_output(falco::outputs::config oc)
}

void falco_outputs::handle_event(gen_event *evt, string &rule, string &source,
falco_common::priority_type priority, string &format)
falco_common::priority_type priority, string &format, std::set<std::string> &tags)
{
if(!m_notifications_tb.claim())
{
Expand Down Expand Up @@ -190,8 +190,9 @@ void falco_outputs::handle_event(gen_event *evt, string &rule, string &source,
sformat += " " + format;
}

cmsg.msg = falco_formats::format_event(evt, rule, source, falco_common::priority_names[priority], sformat);
cmsg.msg = falco_formats::format_event(evt, rule, source, falco_common::priority_names[priority], sformat, tags);
cmsg.fields = falco_formats::resolve_tokens(evt, source, sformat);
cmsg.tags.insert(tags.begin(), tags.end());

cmsg.type = ctrl_msg_type::CTRL_MSG_OUTPUT;
m_queue.push(cmsg);
Expand Down
2 changes: 1 addition & 1 deletion userspace/falco/falco_outputs.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class falco_outputs

// Format then send the event to all configured outputs (`evt` is an event that has matched some rule).
void handle_event(gen_event *evt, std::string &rule, std::string &source,
falco_common::priority_type priority, std::string &format);
falco_common::priority_type priority, std::string &format, std::set<std::string> &tags);

// Format then send a generic message to all outputs. Not necessarily associated with any event.
void handle_msg(uint64_t now,
Expand Down
1 change: 1 addition & 0 deletions userspace/falco/outputs.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct message
std::string rule;
std::string source;
map<std::string, std::string> fields;
std::set<std::string> tags;
};

//
Expand Down
3 changes: 1 addition & 2 deletions userspace/falco/outputs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,5 @@ message response {
string output = 5;
map<string, string> output_fields = 6;
string hostname = 7;
// TODO(leodido,fntlnz): tags not supported yet, keeping it for reference.
// repeated string tags = 8;
repeated string tags = 8;
}
4 changes: 4 additions & 0 deletions userspace/falco/outputs_grpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,9 @@ void falco::outputs::output_grpc::output(const message *msg)
auto host = grpc_res.mutable_hostname();
*host = m_hostname;

// tags
auto tags = grpc_res.mutable_tags();
*tags = {msg->tags.begin(), msg->tags.end()};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's check what we end up with when a Falco rule does not have tags defined.

Do we obtain ...,"tags":[],... or not? I'd prefer a clean JSON, but that's my personal preference only :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any preferences. Anyway, I agree with @leodido that a test covering such a scenario (especially for the JSON output format) would be really helpful to clarify the expected result.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review! I opened a PR to address these concerns, so we can eventually move this conversation there: #1733


falco::grpc::queue::get().push(grpc_res);
}
2 changes: 1 addition & 1 deletion userspace/falco/webserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ bool k8s_audit_handler::accept_data(falco_engine *engine,
{
outputs->handle_event(res->evt, res->rule,
res->source, res->priority_num,
res->format);
res->format, res->tags);
}
catch(falco_exception &e)
{
Expand Down