From 1e205db8aaa8b9677c2b038ec546ca9cc5558bff Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 3 Feb 2017 17:19:40 -0800 Subject: [PATCH 1/5] Use right name for event-generator. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b3abef09..b2e74fc5 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ test/results*.json.* userspace/falco/lua/re.lua userspace/falco/lua/lpeg.so -docker/event-generator/event-generator +docker/event-generator/event_generator docker/event-generator/mysqld docker/event-generator/httpd docker/event-generator/sha1sum From a0a6914b6a63e67327943acf35dadc8624246c7d Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 3 Feb 2017 18:08:48 -0800 Subject: [PATCH 2/5] Add support for tagging rules. - in lua, look for a tags attribute to each rule. This is passed up in add_filter as a tags argument (as a lua table). If not present, an empty table is used. The tags table is iterated to populate a set of tags as strings, which is passed to add_filter(). - A new method falco_engine::enable_rule_by_tag is similar to enable_rule(), but is given a set of tag strings. Any rules containing one of the tags is enabled/disabled. - The list of event types has been changed to a set to more accurately reflect its purpose. - New argument to falco -T allows disabling all rules matching a given tag, via enable_rule_by_tag(). It can be provided multiple times. - New argument to falco -t allows running those rules matching a given tag. If provided all rules are first disabled. It can be provided multiple times, but can not be combined with -T or -D (disable rules by name) - falco_enging supports the notion of a ruleset. The idea is that you can choose a set of rules that are enabled/disabled by using enable_rule()/enable_rule_by_tag() in combination with a ruleset. Later, in process_event() you include that ruleset and the rules you had previously enabled will be run. - rulsets are provided as strings in enable_rule()/enable_rule_by_tag() and as numbers in process_event()--this avoids the overhead of string lookups per-event. Ruleset ids are created on the fly as needed. A utility method find_ruleset_id() looks up the ruleset id for a given name. The default ruleset is NULL string/0 numeric if not provided. - Although the ruleset is a useful falco engine feature, it isn't that important to the falco standalone program, so it's not documented. However, you can change the ruleset by providing FALCO_RULESET in the environment. --- userspace/engine/falco_engine.cpp | 47 ++++++++++++++--- userspace/engine/falco_engine.h | 38 +++++++++++--- userspace/engine/lua/rule_loader.lua | 6 ++- userspace/engine/rules.cpp | 31 ++++++++---- userspace/engine/rules.h | 4 +- userspace/falco/falco.cpp | 76 ++++++++++++++++++++++++++-- 6 files changed, 172 insertions(+), 30 deletions(-) diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index c735710c..b349f2e6 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -40,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_next_ruleset_id(0), + m_sampling_ratio(1), m_sampling_multiplier(0), m_replace_container_info(false) { luaopen_lpeg(m_ls); @@ -107,20 +108,51 @@ void falco_engine::load_rules_file(const string &rules_filename, bool verbose, b load_rules(rules_content, verbose, all_events); } -void falco_engine::enable_rule(string &pattern, bool enabled) +void falco_engine::enable_rule(string &pattern, bool enabled, string *ruleset) { - m_evttype_filter->enable(pattern, enabled); + uint16_t ruleset_id = 0; + + if(ruleset) + { + ruleset_id = find_ruleset_id(*ruleset); + } + + m_evttype_filter->enable(pattern, enabled, ruleset_id); } -unique_ptr falco_engine::process_event(sinsp_evt *ev) +void falco_engine::enable_rule_by_tag(set &tags, bool enabled, string *ruleset) { + uint16_t ruleset_id = 0; + if(ruleset) + { + ruleset_id = find_ruleset_id(*ruleset); + } + + m_evttype_filter->enable_tags(tags, enabled, ruleset_id); +} + +uint16_t falco_engine::find_ruleset_id(std::string &ruleset) +{ + auto it = m_known_rulesets.find(ruleset); + + if(it == m_known_rulesets.end()) + { + m_known_rulesets[ruleset] = ++m_next_ruleset_id; + it = m_known_rulesets.find(ruleset); + } + + return it->second; +} + +unique_ptr falco_engine::process_event(sinsp_evt *ev, uint16_t ruleset_id) +{ if(should_drop_evt()) { return unique_ptr(); } - if(!m_evttype_filter->run(ev)) + if(!m_evttype_filter->run(ev, ruleset_id)) { return unique_ptr(); } @@ -182,10 +214,11 @@ void falco_engine::print_stats() } void falco_engine::add_evttype_filter(string &rule, - list &evttypes, + set &evttypes, + set &tags, sinsp_filter* filter) { - m_evttype_filter->add(rule, evttypes, filter); + m_evttype_filter->add(rule, evttypes, tags, filter); } void falco_engine::clear_filters() diff --git a/userspace/engine/falco_engine.h b/userspace/engine/falco_engine.h index 2a423f10..7f8755c5 100644 --- a/userspace/engine/falco_engine.h +++ b/userspace/engine/falco_engine.h @@ -20,6 +20,7 @@ along with falco. If not, see . #include #include +#include #include "sinsp.h" #include "filter.h" @@ -47,9 +48,18 @@ public: void load_rules(const std::string &rules_content, bool verbose, bool all_events); // - // Enable/Disable any rules matching the provided pattern (regex). + // Enable/Disable any rules matching the provided pattern + // (regex). If ruleset is non-NULL, enable/disable these + // rules in the context of the provided ruleset. The ruleset + // can later be passed as an argument to process_event(). This + // allows for different sets of rules being active at once. // - void enable_rule(std::string &pattern, bool enabled); + void enable_rule(std::string &pattern, bool enabled, std::string *ruleset = NULL); + + // + // Enable/Disable any rules with any of the provided tags (set, exact matches only) + // + void enable_rule_by_tag(std::set &tags, bool enabled, std::string *ruleset = NULL); struct rule_result { sinsp_evt *evt; @@ -58,13 +68,26 @@ public: std::string format; }; + // + // Return the ruleset id corresponding to this ruleset name, + // creating a new one if necessary. If you provide any ruleset + // to enable_rule/enable_rule_by_tag(), you should look up the + // ruleset id and pass it to process_event(). + // + uint16_t find_ruleset_id(std::string &ruleset); + // // Given an event, check it against the set of rules in the // engine and if a matching rule is found, return details on // the rule that matched. If no rule matched, returns NULL. // - // the reutrned rule_result is allocated and must be delete()d. - std::unique_ptr process_event(sinsp_evt *ev); + // If ruleset is non-NULL, use the enabled/disabled status + // associated with the provided ruleset. This is only useful + // when you have previously called enable_rule/enable_rule_by_tag + // with a non-NULL ruleset. + // + // the returned rule_result is allocated and must be delete()d. + std::unique_ptr process_event(sinsp_evt *ev, uint16_t ruleset_id = 0); // // Print details on the given rule. If rule is NULL, print @@ -78,11 +101,12 @@ public: void print_stats(); // - // Add a filter, which is related to the specified list of + // Add a filter, which is related to the specified set of // event types, to the engine. // void add_evttype_filter(std::string &rule, - list &evttypes, + std::set &evttypes, + std::set &tags, sinsp_filter* filter); // Clear all existing filters. @@ -120,6 +144,8 @@ private: inline bool should_drop_evt(); falco_rules *m_rules; + uint16_t m_next_ruleset_id; + std::map m_known_rulesets; std::unique_ptr m_evttype_filter; // diff --git a/userspace/engine/lua/rule_loader.lua b/userspace/engine/lua/rule_loader.lua index 4e18ede8..99be9a4f 100644 --- a/userspace/engine/lua/rule_loader.lua +++ b/userspace/engine/lua/rule_loader.lua @@ -308,8 +308,12 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac install_filter(filter_ast.filter.value) + if (v['tags'] == nil) then + v['tags'] = {} + end + -- Pass the filter and event types back up - falco_rules.add_filter(rules_mgr, v['rule'], evttypes) + falco_rules.add_filter(rules_mgr, v['rule'], evttypes, v['tags']) -- Rule ASTs are merged together into one big AST, with "OR" between each -- rule. diff --git a/userspace/engine/rules.cpp b/userspace/engine/rules.cpp index e0a78d1e..63b9b416 100644 --- a/userspace/engine/rules.cpp +++ b/userspace/engine/rules.cpp @@ -65,42 +65,55 @@ void falco_rules::clear_filters() int falco_rules::add_filter(lua_State *ls) { - if (! lua_islightuserdata(ls, -3) || - ! lua_isstring(ls, -2) || + if (! lua_islightuserdata(ls, -4) || + ! lua_isstring(ls, -3) || + ! lua_istable(ls, -2) || ! lua_istable(ls, -1)) { throw falco_exception("Invalid arguments passed to add_filter()\n"); } - falco_rules *rules = (falco_rules *) lua_topointer(ls, -3); - const char *rulec = lua_tostring(ls, -2); + falco_rules *rules = (falco_rules *) lua_topointer(ls, -4); + const char *rulec = lua_tostring(ls, -3); - list evttypes; + set evttypes; + + lua_pushnil(ls); /* first key */ + while (lua_next(ls, -3) != 0) { + // key is at index -2, value is at index + // -1. We want the keys. + evttypes.insert(luaL_checknumber(ls, -2)); + + // Remove value, keep key for next iteration + lua_pop(ls, 1); + } + + set tags; lua_pushnil(ls); /* first key */ while (lua_next(ls, -2) != 0) { // key is at index -2, value is at index // -1. We want the keys. - evttypes.push_back(luaL_checknumber(ls, -2)); + tags.insert(lua_tostring(ls, -1)); // Remove value, keep key for next iteration lua_pop(ls, 1); } std::string rule = rulec; - rules->add_filter(rule, evttypes); + rules->add_filter(rule, evttypes, tags); return 0; } -void falco_rules::add_filter(string &rule, list &evttypes) +void falco_rules::add_filter(string &rule, set &evttypes, set &tags) { // While the current rule was being parsed, a sinsp_filter // object was being populated by lua_parser. Grab that filter // and pass it to the engine. sinsp_filter *filter = m_lua_parser->get_filter(true); - m_engine->add_evttype_filter(rule, evttypes, filter); + m_engine->add_evttype_filter(rule, evttypes, tags, filter); } int falco_rules::enable_rule(lua_State *ls) diff --git a/userspace/engine/rules.h b/userspace/engine/rules.h index 3cd06b08..1770aacc 100644 --- a/userspace/engine/rules.h +++ b/userspace/engine/rules.h @@ -18,7 +18,7 @@ along with falco. If not, see . #pragma once -#include +#include #include "sinsp.h" @@ -42,7 +42,7 @@ class falco_rules private: void clear_filters(); - void add_filter(string &rule, list &evttypes); + void add_filter(string &rule, std::set &evttypes, std::set &tags); void enable_rule(string &rule, bool enabled); lua_parser* m_lua_parser; diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index fb2fa6db..1a56bb4f 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -60,6 +60,7 @@ static void usage() " -A Monitor all events, including those with EF_DROP_FALCO flag.\n" " -d, --daemon Run as a daemon\n" " -D Disable any rules matching the regex . Can be specified multiple times.\n" + " Can not be specified with -t.\n" " -e Read the events from (in .scap format) instead of tapping into live.\n" " -k , --k8s-api=\n" " Enable Kubernetes support by connecting to the API server\n" @@ -100,6 +101,10 @@ static void usage() " Can be specified multiple times to read from multiple files.\n" " -s If specified, write statistics related to falco's reading/processing of events\n" " to this file. (Only useful in live mode).\n" + " -T Disable any rules with a tag=. Can be specified multiple times.\n" + " Can not be specified with -t.\n" + " -t Only run those rules with a tag=. Can be specified multiple times.\n" + " Can not be specified with -T/-D.\n" " -v Verbose output.\n" "\n" ); @@ -128,7 +133,8 @@ std::list cmdline_options; uint64_t do_inspect(falco_engine *engine, falco_outputs *outputs, sinsp* inspector, - string &stats_filename) + string &stats_filename, + uint16_t ruleset_id) { uint64_t num_evts = 0; int32_t res; @@ -188,7 +194,7 @@ 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. - unique_ptr res = engine->process_event(ev); + unique_ptr res = engine->process_event(ev, ruleset_id); if(res) { outputs->handle_event(res->evt, res->rule, res->priority, res->format); @@ -259,12 +265,15 @@ int falco_init(int argc, char **argv) { set disabled_rule_patterns; string pattern; + string all_rules = ".*"; + set disabled_rule_tags; + set enabled_rule_tags; // // Parse the args // while((op = getopt_long(argc, argv, - "hc:AdD:e:k:K:Ll:m:o:P:p:r:s:vw:", + "hc:AdD:e:k:K:Ll:m:o:P:p:r:s:T:t:vw:", long_options, &long_index)) != -1) { switch(op) @@ -339,6 +348,12 @@ int falco_init(int argc, char **argv) case 's': stats_filename = optarg; break; + case 'T': + disabled_rule_tags.insert(optarg); + break; + case 't': + enabled_rule_tags.insert(optarg); + break; case 'v': verbose = true; break; @@ -358,6 +373,18 @@ int falco_init(int argc, char **argv) engine = new falco_engine(); engine->set_inspector(inspector); engine->set_extra(output_format, replace_container_info); + string *ruleset = NULL; + string ruleset_env; + uint16_t ruleset_id = 0; + + // The ruleset feature is really falco + // engine-specific, so we don't advertise it. But it + // is possible to specify an alternate ruleset via the environment. + if (getenv("FALCO_RULESET") != NULL) + { + ruleset_env = getenv("FALCO_RULESET"); + ruleset = &ruleset_env; + } outputs = new falco_outputs(); outputs->set_inspector(inspector); @@ -421,10 +448,44 @@ int falco_init(int argc, char **argv) falco_logger::log(LOG_INFO, "Parsed rules from file " + filename + "\n"); } + // You can't both disable and enable rules + if((disabled_rule_patterns.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"); + } + + // If a ruleset was provided, we must first explicitly enable all rules. + if(ruleset) + { + engine->enable_rule(all_rules, true, ruleset); + } + for (auto pattern : disabled_rule_patterns) { falco_logger::log(LOG_INFO, "Disabling rules matching pattern: " + pattern + "\n"); - engine->enable_rule(pattern, false); + engine->enable_rule(pattern, false, ruleset); + } + + 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, ruleset); + } + + if(enabled_rule_tags.size() > 0) + { + + // Since we only want to enable specific + // rules, first disable all rules. + engine->enable_rule(all_rules, false, ruleset); + 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, ruleset); } outputs->init(config.m_json_output, config.m_notifications_rate, config.m_notifications_max_burst); @@ -607,10 +668,15 @@ int falco_init(int argc, char **argv) delete mesos_api; mesos_api = 0; + if(ruleset) + { + ruleset_id = engine->find_ruleset_id(*ruleset); + } num_evts = do_inspect(engine, outputs, inspector, - stats_filename); + stats_filename, + ruleset_id); duration = ((double)clock()) / CLOCKS_PER_SEC - duration; From 88faa7c1e7b233e96a11b40bbfe50140a4e7537d Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 3 Feb 2017 17:36:55 -0800 Subject: [PATCH 3/5] Add automated tests for tagged rules Add automated tests that verify the ability to tag sets of rules, disable them with -T, and run them with -t, works: - New test option disable_tags adds -T arguments to the falco command line, and run_tags adds -t arguments to the falco command line. - A new trace file open-multiple-files.scap opens 13 different files, and a new rules file has 13 different rules with all combinations of the tags a, b, c (both forward and backward), a rule with an empty list of tags, a rule with no tags field, and a rule with a completely different tag d. Using the above, add tests for: - Both disabling all combations of a, b, c using disable_tags as well as run all combinations of a, b, c, using run_tags. - Specifying both disabled (-T/-D) and enabled (-t) rules. Not allowed. - Specifying a ruleset while having tagged rules enabled, rules based on a name disabled, and no particular rules enabled or disabled. --- test/falco_test.py | 37 ++- test/falco_tests.yaml.in | 355 ++++++++++++++++++++++ test/rules/tagged_rules.yaml | 93 ++++++ test/trace_files/open-multiple-files.scap | Bin 0 -> 24051 bytes 4 files changed, 480 insertions(+), 5 deletions(-) create mode 100644 test/rules/tagged_rules.yaml create mode 100644 test/trace_files/open-multiple-files.scap diff --git a/test/falco_test.py b/test/falco_test.py index afb7c4f8..9a182fcc 100644 --- a/test/falco_test.py +++ b/test/falco_test.py @@ -23,6 +23,8 @@ class FalcoTest(Test): self.should_detect = self.params.get('detect', '*', default=False) self.trace_file = self.params.get('trace_file', '*') + self.env = {} + if not os.path.isabs(self.trace_file): self.trace_file = os.path.join(self.basedir, self.trace_file) @@ -113,6 +115,20 @@ class FalcoTest(Test): outputs.append(output) self.outputs = outputs + self.disable_tags = self.params.get('disable_tags', '*', default='') + + if self.disable_tags == '': + self.disable_tags=[] + + self.run_tags = self.params.get('run_tags', '*', default='') + + if self.run_tags == '': + self.run_tags=[] + + self.ruleset = self.params.get('ruleset', '*', default='') + if self.ruleset != '': + self.env["FALCO_RULESET"] = self.ruleset + def check_rules_warnings(self, res): found_warning = sets.Set() @@ -180,13 +196,18 @@ class FalcoTest(Test): triggered_rules = match.group(1) for rule, count in self.detect_counts.iteritems(): - expected_line = '{}: {}'.format(rule, count) - match = re.search(expected_line, triggered_rules) + expected = '{}: (\d+)'.format(rule) + match = re.search(expected, triggered_rules) if match is None: - self.fail("Could not find a line '{}' in triggered rule counts '{}'".format(expected_line, triggered_rules)) + actual_count = 0 else: - self.log.debug("Found expected count for {}: {}".format(rule, match.group())) + actual_count = int(match.group(1)) + + if actual_count != count: + self.fail("Different counts for rule {}: expected={}, actual={}".format(rule, count, actual_count)) + else: + self.log.debug("Found expected count for rule {}: {}".format(rule, count)) def check_outputs(self): for output in self.outputs: @@ -223,7 +244,13 @@ class FalcoTest(Test): cmd = '{}/userspace/falco/falco {} {} -c {} -e {} -o json_output={} -v'.format( self.falcodir, self.rules_args, self.disabled_args, self.conf_file, self.trace_file, self.json_output) - self.falco_proc = process.SubProcess(cmd) + for tag in self.disable_tags: + cmd += ' -T {}'.format(tag) + + for tag in self.run_tags: + cmd += ' -t {}'.format(tag) + + self.falco_proc = process.SubProcess(cmd, env=self.env) res = self.falco_proc.run(timeout=180, sig=9) diff --git a/test/falco_tests.yaml.in b/test/falco_tests.yaml.in index 977b7d4c..f61b3aa9 100644 --- a/test/falco_tests.yaml.in +++ b/test/falco_tests.yaml.in @@ -154,6 +154,25 @@ trace_files: !mux - rules/single_rule_enabled_flag.yaml trace_file: trace_files/cat_write.scap + disabled_and_enabled_rules_1: + exit_status: 1 + stderr_contains: "Runtime error: You can not specify both disabled .-D/-T. and enabled .-t. rules. Exiting." + disable_tags: [a] + run_tags: [a] + rules_file: + - rules/single_rule.yaml + trace_file: trace_files/cat_write.scap + + disabled_and_enabled_rules_2: + exit_status: 1 + stderr_contains: "Runtime error: You can not specify both disabled .-D/-T. and enabled .-t. rules. Exiting." + disabled_rules: + - "open.*" + run_tags: [a] + rules_file: + - rules/single_rule.yaml + trace_file: trace_files/cat_write.scap + null_output_field: detect: True detect_level: WARNING @@ -200,3 +219,339 @@ trace_files: !mux - "Create files below dev": 1 - "Modify binary dirs": 2 - "Change thread namespace": 2 + + disabled_tags_a: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + disable_tags: [a] + detect_counts: + - open_1: 0 + - open_2: 1 + - open_3: 1 + - open_4: 0 + - open_5: 0 + - open_6: 1 + - open_7: 0 + - open_8: 0 + - open_9: 0 + - open_10: 0 + - open_11: 1 + - open_12: 1 + - open_13: 1 + + disabled_tags_b: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + disable_tags: [b] + detect_counts: + - open_1: 1 + - open_2: 0 + - open_3: 1 + - open_4: 0 + - open_5: 1 + - open_6: 0 + - open_7: 0 + - open_8: 0 + - open_9: 1 + - open_10: 0 + - open_11: 1 + - open_12: 1 + - open_13: 1 + + disabled_tags_c: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + disable_tags: [c] + detect_counts: + - open_1: 1 + - open_2: 1 + - open_3: 0 + - open_4: 1 + - open_5: 0 + - open_6: 0 + - open_7: 0 + - open_8: 1 + - open_9: 0 + - open_10: 0 + - open_11: 1 + - open_12: 1 + - open_13: 1 + + disabled_tags_ab: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + disable_tags: [a, b] + detect_counts: + - open_1: 0 + - open_2: 0 + - open_3: 1 + - open_4: 0 + - open_5: 0 + - open_6: 0 + - open_7: 0 + - open_8: 0 + - open_9: 0 + - open_10: 0 + - open_11: 1 + - open_12: 1 + - open_13: 1 + + disabled_tags_abc: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + disable_tags: [a, b, c] + detect_counts: + - open_1: 0 + - open_2: 0 + - open_3: 0 + - open_4: 0 + - open_5: 0 + - open_6: 0 + - open_7: 0 + - open_8: 0 + - open_9: 0 + - open_10: 0 + - open_11: 1 + - open_12: 1 + - open_13: 1 + + run_tags_a: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + run_tags: [a] + detect_counts: + - open_1: 1 + - open_2: 0 + - open_3: 0 + - open_4: 1 + - open_5: 1 + - open_6: 0 + - open_7: 1 + - open_8: 1 + - open_9: 1 + - open_10: 1 + - open_11: 0 + - open_12: 0 + - open_13: 0 + + run_tags_b: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + run_tags: [b] + detect_counts: + - open_1: 0 + - open_2: 1 + - open_3: 0 + - open_4: 1 + - open_5: 0 + - open_6: 1 + - open_7: 1 + - open_8: 1 + - open_9: 0 + - open_10: 1 + - open_11: 0 + - open_12: 0 + - open_13: 0 + + run_tags_c: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + run_tags: [c] + detect_counts: + - open_1: 0 + - open_2: 0 + - open_3: 1 + - open_4: 0 + - open_5: 1 + - open_6: 1 + - open_7: 1 + - open_8: 0 + - open_9: 1 + - open_10: 1 + - open_11: 0 + - open_12: 0 + - open_13: 0 + + run_tags_ab: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + run_tags: [a, b] + detect_counts: + - open_1: 1 + - open_2: 1 + - open_3: 0 + - open_4: 1 + - open_5: 1 + - open_6: 1 + - open_7: 1 + - open_8: 1 + - open_9: 1 + - open_10: 1 + - open_11: 0 + - open_12: 0 + - open_13: 0 + + run_tags_bc: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + run_tags: [b, c] + detect_counts: + - open_1: 0 + - open_2: 1 + - open_3: 1 + - open_4: 1 + - open_5: 1 + - open_6: 1 + - open_7: 1 + - open_8: 1 + - open_9: 1 + - open_10: 1 + - open_11: 0 + - open_12: 0 + - open_13: 0 + + run_tags_abc: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + run_tags: [a, b, c] + detect_counts: + - open_1: 1 + - open_2: 1 + - open_3: 1 + - open_4: 1 + - open_5: 1 + - open_6: 1 + - open_7: 1 + - open_8: 1 + - open_9: 1 + - open_10: 1 + - open_11: 0 + - open_12: 0 + - open_13: 0 + + run_tags_d: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + run_tags: [d] + detect_counts: + - open_1: 0 + - open_2: 0 + - open_3: 0 + - open_4: 0 + - open_5: 0 + - open_6: 0 + - open_7: 0 + - open_8: 0 + - open_9: 0 + - open_10: 0 + - open_11: 1 + - open_12: 0 + - open_13: 0 + + # Trying one of the combinations with a ruleset specified. Should get same output and no errors. + run_tags_c_ruleset: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + run_tags: [c] + ruleset: my-ruleset + detect_counts: + - open_1: 0 + - open_2: 0 + - open_3: 1 + - open_4: 0 + - open_5: 1 + - open_6: 1 + - open_7: 1 + - open_8: 0 + - open_9: 1 + - open_10: 1 + - open_11: 0 + - open_12: 0 + - open_13: 0 + + # Disabling one rule with a ruleset specified. Should get that one rule missing and no errors. + disabled_with_ruleset: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + disabled_rules: + - "open_4" + ruleset: my-ruleset + detect_counts: + - open_1: 1 + - open_2: 1 + - open_3: 1 + - open_4: 0 + - open_5: 1 + - open_6: 1 + - open_7: 1 + - open_8: 1 + - open_9: 1 + - open_10: 1 + - open_11: 1 + - open_12: 1 + - open_13: 1 + + # Enabling all rules with a ruleset specified. Should get all rules matching. + default_with_ruleset: + detect: True + detect_level: WARNING + rules_file: + - rules/tagged_rules.yaml + trace_file: trace_files/open-multiple-files.scap + ruleset: my-ruleset + detect_counts: + - open_1: 1 + - open_2: 1 + - open_3: 1 + - open_4: 1 + - open_5: 1 + - open_6: 1 + - open_7: 1 + - open_8: 1 + - open_9: 1 + - open_10: 1 + - open_11: 1 + - open_12: 1 + - open_13: 1 diff --git a/test/rules/tagged_rules.yaml b/test/rules/tagged_rules.yaml new file mode 100644 index 00000000..09d08b74 --- /dev/null +++ b/test/rules/tagged_rules.yaml @@ -0,0 +1,93 @@ +- macro: open_read + condition: (evt.type=open or evt.type=openat) and evt.is_open_read=true and fd.typechar='f' + +- rule: open_1 + desc: open one + condition: open_read and fd.name=/tmp/file-1 + output: Open one (file=%fd.name) + priority: WARNING + tags: [a] + +- rule: open_2 + desc: open two + condition: open_read and fd.name=/tmp/file-2 + output: Open two (file=%fd.name) + priority: WARNING + tags: [b] + +- rule: open_3 + desc: open three + condition: open_read and fd.name=/tmp/file-3 + output: Open three (file=%fd.name) + priority: WARNING + tags: [c] + +- rule: open_4 + desc: open four + condition: open_read and fd.name=/tmp/file-4 + output: Open four (file=%fd.name) + priority: WARNING + tags: [a, b] + +- rule: open_5 + desc: open file + condition: open_read and fd.name=/tmp/file-5 + output: Open file (file=%fd.name) + priority: WARNING + tags: [a, c] + +- rule: open_6 + desc: open six + condition: open_read and fd.name=/tmp/file-6 + output: Open six (file=%fd.name) + priority: WARNING + tags: [b, c] + +- rule: open_7 + desc: open seven + condition: open_read and fd.name=/tmp/file-7 + output: Open seven (file=%fd.name) + priority: WARNING + tags: [a, b, c] + +- rule: open_8 + desc: open eight + condition: open_read and fd.name=/tmp/file-8 + output: Open eight (file=%fd.name) + priority: WARNING + tags: [b, a] + +- rule: open_9 + desc: open nine + condition: open_read and fd.name=/tmp/file-9 + output: Open nine (file=%fd.name) + priority: WARNING + tags: [c, a] + +- rule: open_10 + desc: open ten + condition: open_read and fd.name=/tmp/file-10 + output: Open ten (file=%fd.name) + priority: WARNING + tags: [b, c, a] + +- rule: open_11 + desc: open eleven + condition: open_read and fd.name=/tmp/file-11 + output: Open eleven (file=%fd.name) + priority: WARNING + tags: [d] + +- rule: open_12 + desc: open twelve + condition: open_read and fd.name=/tmp/file-12 + output: Open twelve (file=%fd.name) + priority: WARNING + tags: [] + +- rule: open_13 + desc: open thirteen + condition: open_read and fd.name=/tmp/file-13 + output: Open thirteen (file=%fd.name) + priority: WARNING + diff --git a/test/trace_files/open-multiple-files.scap b/test/trace_files/open-multiple-files.scap new file mode 100644 index 0000000000000000000000000000000000000000..61832b1787fded0b490e8d2f52a8585b975cb4d1 GIT binary patch literal 24051 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 literal 0 HcmV?d00001 From 0a69fc0c85fd46cbc921eed930b56a20dab17d23 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 3 Feb 2017 17:59:38 -0800 Subject: [PATCH 4/5] Tag existing falco ruleset. Tag the existing ruleset to group tags in a meaningful way. The added tags are: - filesystem: the rule relates to reading/writing files - sofware_mgmt: the rule relates to any software/package management tool like rpm, dpkg, etc. - process: the rule relates to starting a new process or changing the state of a current process. - database: the rule relates to databases - host: the rule *only* works outside of containers - shell: the rule specifically relates to starting shells - container: the rule *only* works inside containers - cis: the rule is related to the CIS Docker benchmark. - users: the rule relates to management of users or changing the identity of a running process. - network: the rule relates to network activity Rules can have multiple tags if they relate to multiple of the above. Rules do not have to have tags, although all the current rules do. --- rules/falco_rules.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/rules/falco_rules.yaml b/rules/falco_rules.yaml index cc57350e..47bc8bc9 100644 --- a/rules/falco_rules.yaml +++ b/rules/falco_rules.yaml @@ -244,6 +244,7 @@ condition: bin_dir and evt.dir = < and open_write and not package_mgmt_procs output: "File below a known binary directory opened for writing (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING + tags: [filesystem] - macro: write_etc_common condition: > @@ -263,6 +264,7 @@ condition: write_etc_common and not proc.sname=fbash output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING + tags: [filesystem] # Within a fbash session, the severity is lowered to INFO - rule: Write below etc in installer @@ -270,6 +272,7 @@ condition: write_etc_common and proc.sname=fbash output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline file=%fd.name) within pipe installer session" priority: INFO + tags: [filesystem] - macro: cmp_cp_by_passwd condition: proc.name in (cmp, cp) and proc.pname=passwd @@ -279,6 +282,7 @@ condition: sensitive_files and open_read and server_procs and not proc_is_new and proc.name!="sshd" output: "Sensitive file opened for reading by trusted program after startup (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING + tags: [filesystem] - list: read_sensitive_file_binaries items: [iptables, ps, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, sshd, vsftpd, systemd] @@ -293,6 +297,7 @@ and not proc.cmdline contains /usr/bin/mandb output: "Sensitive file opened for reading by non-trusted program (user=%user.name name=%proc.name command=%proc.cmdline file=%fd.name)" priority: WARNING + tags: [filesystem] # Only let rpm-related programs write to the rpm database - rule: Write below rpm database @@ -300,24 +305,28 @@ condition: fd.name startswith /var/lib/rpm and open_write and not proc.name in (dnf,rpm,rpmkey,yum) and not ansible_running_python output: "Rpm database opened for writing by a non-rpm program (command=%proc.cmdline file=%fd.name)" priority: WARNING + tags: [filesystem, software_mgmt] - rule: DB program spawned process desc: a database-server related program spawned a new process other than itself. This shouldn\'t occur and is a follow on from some SQL injection attacks. condition: proc.pname in (db_server_binaries) and spawned_process and not proc.name in (db_server_binaries) output: "Database-related program spawned process other than itself (user=%user.name program=%proc.cmdline parent=%proc.pname)" priority: WARNING + tags: [process, database] - rule: Modify binary dirs desc: an attempt to modify any file below a set of binary directories. condition: bin_dir_rename and modify and not package_mgmt_procs output: "File below known binary directory renamed/removed (user=%user.name command=%proc.cmdline operation=%evt.type file=%fd.name %evt.args)" priority: WARNING + tags: [filesystem] - rule: Mkdir binary dirs desc: an attempt to create a directory below a set of binary directories. condition: mkdir and bin_dir_mkdir and not package_mgmt_procs output: "Directory below known binary directory created (user=%user.name command=%proc.cmdline directory=%evt.arg.path)" priority: WARNING + tags: [filesystem] # Don't load shared objects coming from unexpected places # Commenting this out for now--there are lots of shared library @@ -343,6 +352,7 @@ and not proc.pname in (sysdigcloud_binaries) output: "Namespace change (setns) by unexpected program (user=%user.name command=%proc.cmdline parent=%proc.pname %container.info)" priority: WARNING + tags: [process] - list: known_shell_spawn_binaries items: [ @@ -369,6 +379,7 @@ and not parent_linux_image_upgrade_script output: "Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline pcmdline=%proc.pcmdline)" priority: WARNING + tags: [host, shell] - macro: trusted_containers condition: (container.image startswith sysdig/agent or @@ -383,6 +394,7 @@ condition: (open_read or open_write) and container and container.privileged=true and not trusted_containers output: File opened for read/write by privileged container (user=%user.name command=%proc.cmdline %container.info file=%fd.name) priority: WARNING + tags: [container, cis] - macro: sensitive_mount condition: (container.mount.dest[/proc*] != "N/A") @@ -392,6 +404,7 @@ condition: (open_read or open_write) and container and sensitive_mount and not trusted_containers output: File opened for read/write by container mounting sensitive directory (user=%user.name command=%proc.cmdline %container.info file=%fd.name) priority: WARNING + tags: [container, cis] # Anything run interactively by root # - condition: evt.type != switch and user.name = root and proc.name != sshd and interactive @@ -403,6 +416,7 @@ condition: spawned_process and system_users and interactive output: "System user ran an interactive command (user=%user.name command=%proc.cmdline)" priority: WARNING + tags: [users] - rule: Run shell in container desc: a shell was spawned by a non-shell program in a container. Container entrypoints are excluded. @@ -415,6 +429,7 @@ and not trusted_containers output: "Shell spawned in a container other than entrypoint (user=%user.name %container.info shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)" priority: WARNING + tags: [container, shell] # sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets - rule: System procs network activity @@ -422,6 +437,7 @@ condition: (fd.sockfamily = ip and system_procs) and (inbound or outbound) output: "Known system binary sent/received network traffic (user=%user.name command=%proc.cmdline connection=%fd.name)" priority: WARNING + tags: [network] # With the current restriction on system calls handled by falco # (e.g. excluding read/write/sendto/recvfrom/etc, this rule won't @@ -438,12 +454,14 @@ condition: evt.type=setuid and evt.dir=> and not user.name=root and not proc.name in (userexec_binaries, mail_binaries, sshd, dbus-daemon-lau, ping, ping6, critical-stack-) output: "Unexpected setuid call by non-sudo, non-root program (user=%user.name parent=%proc.pname command=%proc.cmdline uid=%evt.arg.uid)" priority: WARNING + tags: [users] - rule: User mgmt binaries desc: activity by any programs that can manage users, passwords, or permissions. sudo and su are excluded. Activity in containers is also excluded--some containers create custom users on top of a base linux distribution at startup. condition: spawned_process and proc.name in (user_mgmt_binaries) and not proc.name in (su, sudo) and not container and not proc.pname in (cron_binaries, systemd, run-parts) output: "User management binary command run outside of container (user=%user.name command=%proc.cmdline parent=%proc.pname)" priority: WARNING + tags: [host, users] - list: allowed_dev_files items: [/dev/null, /dev/stdin, /dev/stdout, /dev/stderr, /dev/tty, /dev/random, /dev/urandom, /dev/console] @@ -458,6 +476,7 @@ and not fd.name in (allowed_dev_files) output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING + tags: [filesystem] # fbash is a small shell script that runs bash, and is suitable for use in curl | fbash installers. - rule: Installer bash starts network server @@ -465,18 +484,21 @@ condition: evt.type=listen and proc.sname=fbash output: "Unexpected listen call by a process in a fbash session (command=%proc.cmdline)" priority: WARNING + tags: [network] - rule: Installer bash starts session desc: an attempt by a program in a pipe installer session to start a new session condition: evt.type=setsid and proc.sname=fbash output: "Unexpected setsid call by a process in fbash session (command=%proc.cmdline)" priority: WARNING + tags: [process] - rule: Installer bash non https connection desc: an attempt by a program in a pipe installer session to make an outgoing connection on a non-http(s) port condition: proc.sname=fbash and outbound and not fd.sport in (80, 443, 53) output: "Outbound connection on non-http(s) port by a process in a fbash session (command=%proc.cmdline connection=%fd.name)" priority: WARNING + tags: [network] # It'd be nice if we could warn when processes in a fbash session try # to download from any nonstandard location? This is probably blocked @@ -490,6 +512,7 @@ condition: evt.type=execve and proc.name in (chkconfig, systemctl) and proc.sname=fbash output: "Service management program run by process in a fbash session (command=%proc.cmdline)" priority: INFO + tags: [software_mgmt] # Notice when processes try to run any package management binary within a fbash session. # Note: this is not a WARNING, as you'd expect some package management @@ -499,6 +522,7 @@ condition: evt.type=execve and package_mgmt_procs and proc.sname=fbash output: "Package management program run by process in a fbash session (command=%proc.cmdline)" priority: INFO + tags: [software_mgmt] ########################### # Application-Related Rules From 185729d5d6f93006d3b2e08c9c2afb700a1f7c5a Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 10 Feb 2017 11:53:39 -0800 Subject: [PATCH 5/5] Address feedback from PR - Instead of having a possibly null string pointer as the argument to enable_* and process_event, have wrapper versions that assume a default falco ruleset. The default ruleset name is a static member of the falco_engine class, and the default ruleset id is created/found in the constructor. - This makes the whole mechanism simple enough that it doesn't require seprarate testing, so remove the capability within falco to read a ruleset from the environment and remove automated tests that specify a ruleset. - Make pattern/tags/ruleset arguments to enable_* functions const. (I'll squash this down before I commit) --- test/falco_test.py | 8 +--- test/falco_tests.yaml.in | 72 ------------------------------- userspace/engine/falco_engine.cpp | 44 +++++++++++-------- userspace/engine/falco_engine.h | 33 +++++++++----- userspace/falco/falco.cpp | 38 +++------------- 5 files changed, 57 insertions(+), 138 deletions(-) diff --git a/test/falco_test.py b/test/falco_test.py index 9a182fcc..a0a51bdc 100644 --- a/test/falco_test.py +++ b/test/falco_test.py @@ -23,8 +23,6 @@ class FalcoTest(Test): self.should_detect = self.params.get('detect', '*', default=False) self.trace_file = self.params.get('trace_file', '*') - self.env = {} - if not os.path.isabs(self.trace_file): self.trace_file = os.path.join(self.basedir, self.trace_file) @@ -125,10 +123,6 @@ class FalcoTest(Test): if self.run_tags == '': self.run_tags=[] - self.ruleset = self.params.get('ruleset', '*', default='') - if self.ruleset != '': - self.env["FALCO_RULESET"] = self.ruleset - def check_rules_warnings(self, res): found_warning = sets.Set() @@ -250,7 +244,7 @@ class FalcoTest(Test): for tag in self.run_tags: cmd += ' -t {}'.format(tag) - self.falco_proc = process.SubProcess(cmd, env=self.env) + self.falco_proc = process.SubProcess(cmd) res = self.falco_proc.run(timeout=180, sig=9) diff --git a/test/falco_tests.yaml.in b/test/falco_tests.yaml.in index f61b3aa9..1453dccb 100644 --- a/test/falco_tests.yaml.in +++ b/test/falco_tests.yaml.in @@ -483,75 +483,3 @@ trace_files: !mux - open_11: 1 - open_12: 0 - open_13: 0 - - # Trying one of the combinations with a ruleset specified. Should get same output and no errors. - run_tags_c_ruleset: - detect: True - detect_level: WARNING - rules_file: - - rules/tagged_rules.yaml - trace_file: trace_files/open-multiple-files.scap - run_tags: [c] - ruleset: my-ruleset - detect_counts: - - open_1: 0 - - open_2: 0 - - open_3: 1 - - open_4: 0 - - open_5: 1 - - open_6: 1 - - open_7: 1 - - open_8: 0 - - open_9: 1 - - open_10: 1 - - open_11: 0 - - open_12: 0 - - open_13: 0 - - # Disabling one rule with a ruleset specified. Should get that one rule missing and no errors. - disabled_with_ruleset: - detect: True - detect_level: WARNING - rules_file: - - rules/tagged_rules.yaml - trace_file: trace_files/open-multiple-files.scap - disabled_rules: - - "open_4" - ruleset: my-ruleset - detect_counts: - - open_1: 1 - - open_2: 1 - - open_3: 1 - - open_4: 0 - - open_5: 1 - - open_6: 1 - - open_7: 1 - - open_8: 1 - - open_9: 1 - - open_10: 1 - - open_11: 1 - - open_12: 1 - - open_13: 1 - - # Enabling all rules with a ruleset specified. Should get all rules matching. - default_with_ruleset: - detect: True - detect_level: WARNING - rules_file: - - rules/tagged_rules.yaml - trace_file: trace_files/open-multiple-files.scap - ruleset: my-ruleset - detect_counts: - - open_1: 1 - - open_2: 1 - - open_3: 1 - - open_4: 1 - - open_5: 1 - - open_6: 1 - - open_7: 1 - - open_8: 1 - - open_9: 1 - - open_10: 1 - - open_11: 1 - - open_12: 1 - - open_13: 1 diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index b349f2e6..ea00514b 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -56,6 +56,8 @@ falco_engine::falco_engine(bool seed_rng) { srandom((unsigned) getpid()); } + + m_default_ruleset_id = find_ruleset_id(m_default_ruleset); } falco_engine::~falco_engine() @@ -108,38 +110,39 @@ void falco_engine::load_rules_file(const string &rules_filename, bool verbose, b load_rules(rules_content, verbose, all_events); } -void falco_engine::enable_rule(string &pattern, bool enabled, string *ruleset) +void falco_engine::enable_rule(const string &pattern, bool enabled, const string &ruleset) { - uint16_t ruleset_id = 0; - - if(ruleset) - { - ruleset_id = find_ruleset_id(*ruleset); - } + uint16_t ruleset_id = find_ruleset_id(ruleset); m_evttype_filter->enable(pattern, enabled, ruleset_id); } -void falco_engine::enable_rule_by_tag(set &tags, bool enabled, string *ruleset) +void falco_engine::enable_rule(const string &pattern, bool enabled) { - uint16_t ruleset_id = 0; + enable_rule(pattern, enabled, m_default_ruleset); +} - if(ruleset) - { - ruleset_id = find_ruleset_id(*ruleset); - } +void falco_engine::enable_rule_by_tag(const set &tags, bool enabled, const string &ruleset) +{ + uint16_t ruleset_id = find_ruleset_id(ruleset); m_evttype_filter->enable_tags(tags, enabled, ruleset_id); } -uint16_t falco_engine::find_ruleset_id(std::string &ruleset) +void falco_engine::enable_rule_by_tag(const set &tags, bool enabled) { - auto it = m_known_rulesets.find(ruleset); + enable_rule_by_tag(tags, enabled, m_default_ruleset); +} - if(it == m_known_rulesets.end()) +uint16_t falco_engine::find_ruleset_id(const std::string &ruleset) +{ + auto it = m_known_rulesets.lower_bound(ruleset); + + if(it == m_known_rulesets.end() || + it->first != ruleset) { - m_known_rulesets[ruleset] = ++m_next_ruleset_id; - it = m_known_rulesets.find(ruleset); + it = m_known_rulesets.emplace_hint(it, + std::make_pair(ruleset, m_next_ruleset_id++)); } return it->second; @@ -187,6 +190,11 @@ unique_ptr falco_engine::process_event(sinsp_evt *ev, return res; } +unique_ptr falco_engine::process_event(sinsp_evt *ev) +{ + return process_event(ev, m_default_ruleset_id); +} + void falco_engine::describe_rule(string *rule) { return m_rules->describe_rule(rule); diff --git a/userspace/engine/falco_engine.h b/userspace/engine/falco_engine.h index 7f8755c5..d06c45e7 100644 --- a/userspace/engine/falco_engine.h +++ b/userspace/engine/falco_engine.h @@ -49,17 +49,23 @@ public: // // Enable/Disable any rules matching the provided pattern - // (regex). If ruleset is non-NULL, enable/disable these - // rules in the context of the provided ruleset. The ruleset - // can later be passed as an argument to process_event(). This - // allows for different sets of rules being active at once. + // (regex). When provided, enable/disable these rules in the + // context of the provided ruleset. The ruleset (id) can later + // be passed as an argument to process_event(). This allows + // for different sets of rules being active at once. // - void enable_rule(std::string &pattern, bool enabled, std::string *ruleset = NULL); + void enable_rule(const std::string &pattern, bool enabled, const std::string &ruleset); + + // Wrapper that assumes the default ruleset + void enable_rule(const std::string &pattern, bool enabled); // // Enable/Disable any rules with any of the provided tags (set, exact matches only) // - void enable_rule_by_tag(std::set &tags, bool enabled, std::string *ruleset = NULL); + void enable_rule_by_tag(const std::set &tags, bool enabled, const std::string &ruleset); + + // Wrapper that assumes the default ruleset + void enable_rule_by_tag(const std::set &tags, bool enabled); struct rule_result { sinsp_evt *evt; @@ -74,20 +80,25 @@ public: // to enable_rule/enable_rule_by_tag(), you should look up the // ruleset id and pass it to process_event(). // - uint16_t find_ruleset_id(std::string &ruleset); + uint16_t find_ruleset_id(const std::string &ruleset); // // Given an event, check it against the set of rules in the // engine and if a matching rule is found, return details on // the rule that matched. If no rule matched, returns NULL. // - // If ruleset is non-NULL, use the enabled/disabled status + // When ruleset_id is provided, use the enabled/disabled status // associated with the provided ruleset. This is only useful // when you have previously called enable_rule/enable_rule_by_tag - // with a non-NULL ruleset. + // with a ruleset string. // // the returned rule_result is allocated and must be delete()d. - std::unique_ptr process_event(sinsp_evt *ev, uint16_t ruleset_id = 0); + std::unique_ptr process_event(sinsp_evt *ev, uint16_t ruleset_id); + + // + // Wrapper assuming the default ruleset + // + std::unique_ptr process_event(sinsp_evt *ev); // // Print details on the given rule. If rule is NULL, print @@ -172,6 +183,8 @@ private: double m_sampling_multiplier; std::string m_lua_main_filename = "rule_loader.lua"; + std::string m_default_ruleset = "falco-default-ruleset"; + uint32_t m_default_ruleset_id; std::string m_extra; bool m_replace_container_info; diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index 1a56bb4f..455ab3a1 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -133,8 +133,7 @@ std::list cmdline_options; uint64_t do_inspect(falco_engine *engine, falco_outputs *outputs, sinsp* inspector, - string &stats_filename, - uint16_t ruleset_id) + string &stats_filename) { uint64_t num_evts = 0; int32_t res; @@ -194,7 +193,7 @@ 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. - unique_ptr res = engine->process_event(ev, ruleset_id); + unique_ptr res = engine->process_event(ev); if(res) { outputs->handle_event(res->evt, res->rule, res->priority, res->format); @@ -373,18 +372,6 @@ int falco_init(int argc, char **argv) engine = new falco_engine(); engine->set_inspector(inspector); engine->set_extra(output_format, replace_container_info); - string *ruleset = NULL; - string ruleset_env; - uint16_t ruleset_id = 0; - - // The ruleset feature is really falco - // engine-specific, so we don't advertise it. But it - // is possible to specify an alternate ruleset via the environment. - if (getenv("FALCO_RULESET") != NULL) - { - ruleset_env = getenv("FALCO_RULESET"); - ruleset = &ruleset_env; - } outputs = new falco_outputs(); outputs->set_inspector(inspector); @@ -454,16 +441,10 @@ int falco_init(int argc, char **argv) throw std::invalid_argument("You can not specify both disabled (-D/-T) and enabled (-t) rules"); } - // If a ruleset was provided, we must first explicitly enable all rules. - if(ruleset) - { - engine->enable_rule(all_rules, true, ruleset); - } - for (auto pattern : disabled_rule_patterns) { falco_logger::log(LOG_INFO, "Disabling rules matching pattern: " + pattern + "\n"); - engine->enable_rule(pattern, false, ruleset); + engine->enable_rule(pattern, false); } if(disabled_rule_tags.size() > 0) @@ -472,7 +453,7 @@ int falco_init(int argc, char **argv) { falco_logger::log(LOG_INFO, "Disabling rules with tag: " + tag + "\n"); } - engine->enable_rule_by_tag(disabled_rule_tags, false, ruleset); + engine->enable_rule_by_tag(disabled_rule_tags, false); } if(enabled_rule_tags.size() > 0) @@ -480,12 +461,12 @@ int falco_init(int argc, char **argv) // Since we only want to enable specific // rules, first disable all rules. - engine->enable_rule(all_rules, false, ruleset); + 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, ruleset); + engine->enable_rule_by_tag(enabled_rule_tags, true); } outputs->init(config.m_json_output, config.m_notifications_rate, config.m_notifications_max_burst); @@ -668,15 +649,10 @@ int falco_init(int argc, char **argv) delete mesos_api; mesos_api = 0; - if(ruleset) - { - ruleset_id = engine->find_ruleset_id(*ruleset); - } num_evts = do_inspect(engine, outputs, inspector, - stats_filename, - ruleset_id); + stats_filename); duration = ((double)clock()) / CLOCKS_PER_SEC - duration;