From a38f7f181bb9c92c12bafc14f41b4d5e3e72e402 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 22 Sep 2017 17:08:00 -0700 Subject: [PATCH] Add ability to append to rules/macros Add the ability to append to rules/macros, like we already do with lists. For rules/macros, if the object has an append: true key, the condition value is appended to the condition of an existing rule/macro with the same name. Like lists, it's an error to specify append: true without there being an existing rule/macro. Also add tests that test the same kind of things we did for lists: - That append: true really does append - That append: false overwrites the rule/macro - That it's an error to append with a prior rule/macro existing. --- test/falco_tests.yaml | 41 +++++++++++++++ test/rules/macro_append.yaml | 12 +++++ test/rules/macro_append_failure.yaml | 3 ++ test/rules/macro_append_false.yaml | 12 +++++ test/rules/rule_append.yaml | 9 ++++ test/rules/rule_append_failure.yaml | 3 ++ test/rules/rule_append_false.yaml | 9 ++++ userspace/engine/lua/rule_loader.lua | 76 +++++++++++++++++++++------- 8 files changed, 147 insertions(+), 18 deletions(-) create mode 100644 test/rules/macro_append.yaml create mode 100644 test/rules/macro_append_failure.yaml create mode 100644 test/rules/macro_append_false.yaml create mode 100644 test/rules/rule_append.yaml create mode 100644 test/rules/rule_append_failure.yaml create mode 100644 test/rules/rule_append_false.yaml diff --git a/test/falco_tests.yaml b/test/falco_tests.yaml index e887ee7d..0449b1f0 100644 --- a/test/falco_tests.yaml +++ b/test/falco_tests.yaml @@ -599,3 +599,44 @@ trace_files: !mux rules_file: - rules/list_append_false.yaml trace_file: trace_files/cat_write.scap + + macro_append_failure: + exit_status: 1 + stderr_contains: "Macro my_macro has 'append' key but no macro by that name already exists. Exiting" + rules_file: + - rules/macro_append_failure.yaml + trace_file: trace_files/cat_write.scap + + macro_append: + detect: True + detect_level: WARNING + rules_file: + - rules/macro_append.yaml + trace_file: trace_files/cat_write.scap + + macro_append_false: + detect: False + rules_file: + - rules/macro_append_false.yaml + trace_file: trace_files/cat_write.scap + + rule_append_failure: + exit_status: 1 + stderr_contains: "Rule my_rule has 'append' key but no rule by that name already exists. Exiting" + rules_file: + - rules/rule_append_failure.yaml + trace_file: trace_files/cat_write.scap + + rule_append: + detect: True + detect_level: WARNING + rules_file: + - rules/rule_append.yaml + trace_file: trace_files/cat_write.scap + + rule_append_false: + detect: False + rules_file: + - rules/rule_append_false.yaml + trace_file: trace_files/cat_write.scap + diff --git a/test/rules/macro_append.yaml b/test/rules/macro_append.yaml new file mode 100644 index 00000000..92d1722c --- /dev/null +++ b/test/rules/macro_append.yaml @@ -0,0 +1,12 @@ +- macro: my_macro + condition: proc.name=not-cat + +- macro: my_macro + append: true + condition: or proc.name=cat + +- rule: Open From Cat + desc: A process named cat does an open + condition: evt.type=open and my_macro + output: "An open was seen (command=%proc.cmdline)" + priority: WARNING \ No newline at end of file diff --git a/test/rules/macro_append_failure.yaml b/test/rules/macro_append_failure.yaml new file mode 100644 index 00000000..55eef77c --- /dev/null +++ b/test/rules/macro_append_failure.yaml @@ -0,0 +1,3 @@ +- macro: my_macro + condition: proc.name=not-cat + append: true diff --git a/test/rules/macro_append_false.yaml b/test/rules/macro_append_false.yaml new file mode 100644 index 00000000..384b31de --- /dev/null +++ b/test/rules/macro_append_false.yaml @@ -0,0 +1,12 @@ +- macro: my_macro + condition: proc.name=cat + +- macro: my_macro + append: false + condition: proc.name=not-cat + +- rule: Open From Cat + desc: A process named cat does an open + condition: evt.type=open and my_macro + output: "An open was seen (command=%proc.cmdline)" + priority: WARNING \ No newline at end of file diff --git a/test/rules/rule_append.yaml b/test/rules/rule_append.yaml new file mode 100644 index 00000000..782cf776 --- /dev/null +++ b/test/rules/rule_append.yaml @@ -0,0 +1,9 @@ +- rule: my_rule + desc: A process named cat does an open + condition: evt.type=open and fd.name=not-a-real-file + output: "An open of /dev/null was seen (command=%proc.cmdline)" + priority: WARNING + +- rule: my_rule + append: true + condition: or fd.name=/dev/null diff --git a/test/rules/rule_append_failure.yaml b/test/rules/rule_append_failure.yaml new file mode 100644 index 00000000..1cc40e09 --- /dev/null +++ b/test/rules/rule_append_failure.yaml @@ -0,0 +1,3 @@ +- rule: my_rule + condition: evt.type=open + append: true diff --git a/test/rules/rule_append_false.yaml b/test/rules/rule_append_false.yaml new file mode 100644 index 00000000..f58ac574 --- /dev/null +++ b/test/rules/rule_append_false.yaml @@ -0,0 +1,9 @@ +- rule: my_rule + desc: A process named cat does an open + condition: evt.type=open and fd.name=/dev/null + output: "An open of /dev/null was seen (command=%proc.cmdline)" + priority: WARNING + +- rule: my_rule + append: true + condition: and fd.name=not-a-real-file \ No newline at end of file diff --git a/userspace/engine/lua/rule_loader.lua b/userspace/engine/lua/rule_loader.lua index 41448e82..1d9c60dd 100644 --- a/userspace/engine/lua/rule_loader.lua +++ b/userspace/engine/lua/rule_loader.lua @@ -208,7 +208,23 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac end end - state.macros_by_name[v['macro']] = v + -- Possibly append to the condition field of an existing macro + append = false + + if v['append'] then + append = v['append'] + end + + if append then + if state.macros_by_name[v['macro']] == nil then + error ("Macro " ..v['macro'].. " has 'append' key but no macro by that name already exists") + end + + state.macros_by_name[v['macro']]['condition'] = state.macros_by_name[v['macro']]['condition'] .. " " .. v['condition'] + + else + state.macros_by_name[v['macro']] = v + end elseif (v['list']) then @@ -247,25 +263,49 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac error ("Missing name in rule") end - for i, field in ipairs({'condition', 'output', 'desc', 'priority'}) do - if (v[field] == nil) then - error ("Missing "..field.." in rule with name "..v['rule']) + -- Possibly append to the condition field of an existing rule + append = false + + if v['append'] then + append = v['append'] + end + + if append then + + -- For append rules, all you need is the condition + for i, field in ipairs({'condition'}) do + if (v[field] == nil) then + error ("Missing "..field.." in rule with name "..v['rule']) + end end + + if state.rules_by_name[v['rule']] == nil then + error ("Rule " ..v['rule'].. " has 'append' key but no rule by that name already exists") + end + + state.rules_by_name[v['rule']]['condition'] = state.rules_by_name[v['rule']]['condition'] .. " " .. v['condition'] + + else + + for i, field in ipairs({'condition', 'output', 'desc', 'priority'}) do + if (v[field] == nil) then + error ("Missing "..field.." in rule with name "..v['rule']) + end + end + + -- Note that we can overwrite rules, but the rules are still + -- loaded in the order in which they first appeared, + -- potentially across multiple files. + if state.rules_by_name[v['rule']] == nil then + state.ordered_rule_names[#state.ordered_rule_names+1] = v['rule'] + end + + -- The output field might be a folded-style, which adds a + -- newline to the end. Remove any trailing newlines. + v['output'] = compiler.trim(v['output']) + + state.rules_by_name[v['rule']] = v end - - -- Note that we can overwrite rules, but the rules are still - -- loaded in the order in which they first appeared, - -- potentially across multiple files. - if state.rules_by_name[v['rule']] == nil then - state.ordered_rule_names[#state.ordered_rule_names+1] = v['rule'] - end - - -- The output field might be a folded-style, which adds a - -- newline to the end. Remove any trailing newlines. - v['output'] = compiler.trim(v['output']) - - state.rules_by_name[v['rule']] = v - else error ("Unknown rule object: "..table.tostring(v)) end