From f1748060c57cbb90180cbc4d179f2fec7b8201c0 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Thu, 4 Aug 2016 12:01:54 -0700 Subject: [PATCH] Add tests for multiple files, disabled rules. Add test that cover reading from multiple sets of rule files and disabling rules. Specific changes: - Modify falco to allow multiple -r arguments to read from multiple files. - In the test multiplex file, add a disabled_rules attribute, containing a sequence of rules to disable. Result in -D arguments when running falco. - In the test multiplex file, 'rules_file' can be a sequence. It results in multiple -r arguments when running falco. - In the test multiplex file, 'detect_level' can be a squence of multiple severity levels. All levels will be checked for in the output. - Move all test rules files to a rules subdirectory and all trace files to a traces subdirectory. - Add a small trace file for a simple cat of /dev/null. Used by the new tests. - Add the following new tests: - Reading from multiple files, with the first file being empty. Ensure that the rules from the second file are properly loaded. - Reading from multiple files with the last being empty. Ensures that the empty file doesn't overwrite anything from the first file. - Reading from multiple files with varying severity levels for each rule. Ensures that both files are properly read. - Disabling rules from a rules file, both with full rule names and regexes. Will result in not detecting anything. --- test/falco_test.py | 46 ++++++++++++++----- test/falco_tests.yaml.in | 51 +++++++++++++++++++-- test/rules/double_rule.yaml | 13 ++++++ test/rules/empty_rules.yaml | 0 test/{ => rules}/falco_rules_warnings.yaml | 0 test/rules/single_rule.yaml | 8 ++++ test/trace_files/cat_write.scap | Bin 0 -> 12532 bytes test/{ => trace_files}/empty.scap | Bin userspace/falco/configuration.cpp | 2 +- userspace/falco/configuration.h | 2 +- userspace/falco/falco.cpp | 20 +++++--- 11 files changed, 119 insertions(+), 23 deletions(-) create mode 100644 test/rules/double_rule.yaml create mode 100644 test/rules/empty_rules.yaml rename test/{ => rules}/falco_rules_warnings.yaml (100%) create mode 100644 test/rules/single_rule.yaml create mode 100644 test/trace_files/cat_write.scap rename test/{ => trace_files}/empty.scap (100%) diff --git a/test/falco_test.py b/test/falco_test.py index 7b72d5ee..66eff585 100644 --- a/test/falco_test.py +++ b/test/falco_test.py @@ -26,8 +26,28 @@ class FalcoTest(Test): self.json_output = self.params.get('json_output', '*', default=False) self.rules_file = self.params.get('rules_file', '*', default=os.path.join(self.basedir, '../rules/falco_rules.yaml')) - if not os.path.isabs(self.rules_file): - self.rules_file = os.path.join(self.basedir, self.rules_file) + if not isinstance(self.rules_file, list): + self.rules_file = [self.rules_file] + + self.rules_args = "" + + for file in self.rules_file: + if not os.path.isabs(file): + file = os.path.join(self.basedir, file) + self.rules_args = self.rules_args + "-r " + file + " " + + self.disabled_rules = self.params.get('disabled_rules', '*', default='') + + if self.disabled_rules == '': + self.disabled_rules = [] + + if not isinstance(self.disabled_rules, list): + self.disabled_rules = [self.disabled_rules] + + self.disabled_args = "" + + for rule in self.disabled_rules: + self.disabled_args = self.disabled_args + "-D " + rule + " " self.rules_warning = self.params.get('rules_warning', '*', default=False) if self.rules_warning == False: @@ -49,6 +69,9 @@ class FalcoTest(Test): if self.should_detect: self.detect_level = self.params.get('detect_level', '*') + if not isinstance(self.detect_level, list): + self.detect_level = [self.detect_level] + # Doing this in 2 steps instead of simply using # module_is_loaded to avoid logging lsmod output to the log. lsmod_output = process.system_output("lsmod", verbose=False) @@ -105,16 +128,17 @@ class FalcoTest(Test): if events_detected == 0: self.fail("Detected {} events when should have detected > 0".format(events_detected)) - level_line = '(?i){}: (\d+)'.format(self.detect_level) - match = re.search(level_line, res.stdout) + for level in self.detect_level: + level_line = '(?i){}: (\d+)'.format(level) + match = re.search(level_line, res.stdout) - if match is None: - self.fail("Could not find a line '{}: ' in falco output".format(self.detect_level)) + if match is None: + self.fail("Could not find a line '{}: ' in falco output".format(level)) - events_detected = int(match.group(1)) + events_detected = int(match.group(1)) - if not events_detected > 0: - self.fail("Detected {} events at level {} when should have detected > 0".format(events_detected, self.detect_level)) + if not events_detected > 0: + self.fail("Detected {} events at level {} when should have detected > 0".format(events_detected, level)) def check_json_output(self, res): if self.json_output: @@ -131,8 +155,8 @@ class FalcoTest(Test): self.log.info("Trace file %s", self.trace_file) # Run the provided trace file though falco - cmd = '{}/userspace/falco/falco -r {} -c {}/../falco.yaml -e {} -o json_output={} -v'.format( - self.falcodir, self.rules_file, self.falcodir, self.trace_file, self.json_output) + cmd = '{}/userspace/falco/falco {} {} -c {}/../falco.yaml -e {} -o json_output={} -v'.format( + self.falcodir, self.rules_args, self.disabled_args, self.falcodir, self.trace_file, self.json_output) self.falco_proc = process.SubProcess(cmd) diff --git a/test/falco_tests.yaml.in b/test/falco_tests.yaml.in index bb1eb511..17e61f24 100644 --- a/test/falco_tests.yaml.in +++ b/test/falco_tests.yaml.in @@ -1,13 +1,13 @@ trace_files: !mux builtin_rules_no_warnings: detect: False - trace_file: empty.scap + trace_file: trace_files/empty.scap rules_warning: False test_warnings: detect: False - trace_file: empty.scap - rules_file: falco_rules_warnings.yaml + trace_file: trace_files/empty.scap + rules_file: rules/falco_rules_warnings.yaml rules_warning: - no_evttype - evttype_not_equals @@ -60,3 +60,48 @@ trace_files: !mux - repeated_evttypes_with_in: [open] - repeated_evttypes_with_separate_in: [open] - repeated_evttypes_with_mix: [open] + + multiple_rules_first_empty: + detect: True + detect_level: WARNING + rules_file: + - rules/empty_rules.yaml + - rules/single_rule.yaml + trace_file: trace_files/cat_write.scap + + multiple_rules_last_empty: + detect: True + detect_level: WARNING + rules_file: + - rules/single_rule.yaml + - rules/empty_rules.yaml + trace_file: trace_files/cat_write.scap + + multiple_rules: + detect: True + detect_level: + - WARNING + - INFO + - ERROR + rules_file: + - rules/single_rule.yaml + - rules/double_rule.yaml + trace_file: trace_files/cat_write.scap + + disabled_rules: + detect: False + rules_file: + - rules/empty_rules.yaml + - rules/single_rule.yaml + disabled_rules: + - open_from_cat + trace_file: trace_files/cat_write.scap + + disabled_rules_using_regex: + detect: False + rules_file: + - rules/empty_rules.yaml + - rules/single_rule.yaml + disabled_rules: + - "open.*" + trace_file: trace_files/cat_write.scap diff --git a/test/rules/double_rule.yaml b/test/rules/double_rule.yaml new file mode 100644 index 00000000..4633a55b --- /dev/null +++ b/test/rules/double_rule.yaml @@ -0,0 +1,13 @@ +# This ruleset depends on the is_cat macro defined in single_rule.yaml + +- rule: exec_from_cat + desc: A process named cat does execve + condition: evt.type=execve and is_cat + output: "An exec was seen (command=%proc.cmdline)" + priority: ERROR + +- rule: access_from_cat + desc: A process named cat does an access + condition: evt.type=access and is_cat + output: "An access was seen (command=%proc.cmdline)" + priority: INFO \ No newline at end of file diff --git a/test/rules/empty_rules.yaml b/test/rules/empty_rules.yaml new file mode 100644 index 00000000..e69de29b diff --git a/test/falco_rules_warnings.yaml b/test/rules/falco_rules_warnings.yaml similarity index 100% rename from test/falco_rules_warnings.yaml rename to test/rules/falco_rules_warnings.yaml diff --git a/test/rules/single_rule.yaml b/test/rules/single_rule.yaml new file mode 100644 index 00000000..3044c6b8 --- /dev/null +++ b/test/rules/single_rule.yaml @@ -0,0 +1,8 @@ +- macro: is_cat + condition: proc.name=cat + +- 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 \ No newline at end of file diff --git a/test/trace_files/cat_write.scap b/test/trace_files/cat_write.scap new file mode 100644 index 0000000000000000000000000000000000000000..c4cf36b9cfa11aa1cd8ce229fc29b7ac1263d86b GIT binary patch literal 12532 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 &cmdline_optio init_cmdline_options(cmdline_options); - m_rules_filename = m_config->get_scalar("rules_file", "/etc/falco_rules.yaml"); + m_rules_filenames.push_back(m_config->get_scalar("rules_file", "/etc/falco_rules.yaml")); m_json_output = m_config->get_scalar("json_output", false); falco_outputs::output_config file_output; diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 8e13fd94..2076b5aa 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -123,7 +123,7 @@ class falco_configuration void init(std::string conf_filename, std::list &cmdline_options); void init(std::list &cmdline_options); - std::string m_rules_filename; + std::list m_rules_filenames; bool m_json_output; std::vector m_outputs; private: diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index e7ebc1b2..7e986487 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -2,6 +2,9 @@ #include #include +#include +#include +#include #include #include #include @@ -41,6 +44,7 @@ static void usage() " -p, --pidfile When run as a daemon, write pid to specified file\n" " -e Read the events from (in .scap format) instead of tapping into live.\n" " -r Rules file (defaults to value set in configuration file, or /etc/falco_rules.yaml).\n" + " Can be specified multiple times to read from multiple files.\n" " -D Disable any rules matching the regex . Can be specified multiple times.\n" " -L Show the name and description of all rules and exit.\n" " -l Show the name and description of the rule with name and exit.\n" @@ -140,7 +144,7 @@ int falco_init(int argc, char **argv) int long_index = 0; string scap_filename; string conf_filename; - string rules_filename; + list rules_filenames; bool daemon = false; string pidfilename = "/var/run/falco.pid"; bool describe_all_rules = false; @@ -192,7 +196,7 @@ int falco_init(int argc, char **argv) scap_filename = optarg; break; case 'r': - rules_filename = optarg; + rules_filenames.push_back(optarg); break; case 'D': pattern = optarg; @@ -273,14 +277,16 @@ int falco_init(int argc, char **argv) falco_logger::log(LOG_INFO, "Falco initialized. No configuration file found, proceeding with defaults\n"); } - if (rules_filename.size()) + if (rules_filenames.size()) { - config.m_rules_filename = rules_filename; + config.m_rules_filenames = rules_filenames; } - engine->load_rules_file(rules_filename, verbose, all_events); - - falco_logger::log(LOG_INFO, "Parsed rules from file " + rules_filename + "\n"); + for (auto filename : config.m_rules_filenames) + { + engine->load_rules_file(filename, verbose, all_events); + falco_logger::log(LOG_INFO, "Parsed rules from file " + filename + "\n"); + } for (auto pattern : disabled_rule_patterns) {