diff --git a/userspace/engine/lua/compiler.lua b/userspace/engine/lua/compiler.lua index 0feed84e..e0e53fd3 100644 --- a/userspace/engine/lua/compiler.lua +++ b/userspace/engine/lua/compiler.lua @@ -76,7 +76,8 @@ function expand_macros(ast, defs, changed) if (defs[ast.value.value] == nil) then error("Undefined macro '".. ast.value.value .. "' used in filter.") end - ast.value = copy_ast_obj(defs[ast.value.value]) + defs[ast.value.value].used = true + ast.value = copy_ast_obj(defs[ast.value.value].ast) changed = true return changed end @@ -88,7 +89,8 @@ function expand_macros(ast, defs, changed) if (defs[ast.left.value] == nil) then error("Undefined macro '".. ast.left.value .. "' used in filter.") end - ast.left = copy_ast_obj(defs[ast.left.value]) + defs[ast.left.value].used = true + ast.left = copy_ast_obj(defs[ast.left.value].ast) changed = true end @@ -96,7 +98,8 @@ function expand_macros(ast, defs, changed) if (defs[ast.right.value] == nil) then error("Undefined macro ".. ast.right.value .. " used in filter.") end - ast.right = copy_ast_obj(defs[ast.right.value]) + defs[ast.right.value].used = true + ast.right = copy_ast_obj(defs[ast.right.value].ast) changed = true end @@ -109,7 +112,8 @@ function expand_macros(ast, defs, changed) if (defs[ast.argument.value] == nil) then error("Undefined macro ".. ast.argument.value .. " used in filter.") end - ast.argument = copy_ast_obj(defs[ast.argument.value]) + defs[ast.argument.value].used = true + ast.argument = copy_ast_obj(defs[ast.argument.value].ast) changed = true end return expand_macros(ast.argument, defs, changed) @@ -283,11 +287,28 @@ function get_evttypes(name, ast, source) return evttypes end +function compiler.expand_lists_in(source, list_defs) + + for name, def in pairs(list_defs) do + local begin_name_pat = "^("..name..")([%s(),=])" + local mid_name_pat = "([%s(),=])("..name..")([%s(),=])" + local end_name_pat = "([%s(),=])("..name..")$" + + source, subcount1 = string.gsub(source, begin_name_pat, table.concat(def.items, ", ").."%2") + source, subcount2 = string.gsub(source, mid_name_pat, "%1"..table.concat(def.items, ", ").."%3") + source, subcount3 = string.gsub(source, end_name_pat, "%1"..table.concat(def.items, ", ")) + + if (subcount1 + subcount2 + subcount3) > 0 then + def.used = true + end + end + + return source +end + function compiler.compile_macro(line, macro_defs, list_defs) - for name, items in pairs(list_defs) do - line = string.gsub(line, name, table.concat(items, ", ")) - end + line = compiler.expand_lists_in(line, list_defs) local ast, error_msg = parser.parse_filter(line) @@ -325,14 +346,7 @@ end --]] function compiler.compile_filter(name, source, macro_defs, list_defs) - for name, items in pairs(list_defs) do - local begin_name_pat = "^("..name..")([%s(),=])" - local mid_name_pat = "([%s(),=])("..name..")([%s(),=])" - local end_name_pat = "([%s(),=])("..name..")$" - source = string.gsub(source, begin_name_pat, table.concat(items, ", ").."%2") - source = string.gsub(source, mid_name_pat, "%1"..table.concat(items, ", ").."%3") - source = string.gsub(source, end_name_pat, "%1"..table.concat(items, ", ")) - end + source = compiler.expand_lists_in(source, list_defs) local ast, error_msg = parser.parse_filter(source) diff --git a/userspace/engine/lua/rule_loader.lua b/userspace/engine/lua/rule_loader.lua index 8fc44b68..6aa6980d 100644 --- a/userspace/engine/lua/rule_loader.lua +++ b/userspace/engine/lua/rule_loader.lua @@ -347,13 +347,13 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac if (state.lists[item] == nil) then items[#items+1] = item else - for i, exp_item in ipairs(state.lists[item]) do + for i, exp_item in ipairs(state.lists[item].items) do items[#items+1] = exp_item end end end - state.lists[v['list']] = items + state.lists[v['list']] = {["items"] = items, ["used"] = false} end for i, name in ipairs(state.ordered_macro_names) do @@ -361,7 +361,7 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac local v = state.macros_by_name[name] local ast = compiler.compile_macro(v['condition'], state.macros, state.lists) - state.macros[v['macro']] = ast.filter.value + state.macros[v['macro']] = {["ast"] = ast.filter.value, ["used"] = false} end for i, name in ipairs(state.ordered_rule_names) do @@ -443,6 +443,21 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac end end + if verbose then + -- Print info on any dangling lists or macros that were not used anywhere + for name, macro in pairs(state.macros) do + if macro.used == false then + print("Warning: macro "..name.." not refered to by any rule/macro") + end + end + + for name, list in pairs(state.lists) do + if list.used == false then + print("Warning: list "..name.." not refered to by any rule/macro/list") + end + end + end + io.flush() end diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index 0febc8ee..e4d1af51 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -111,7 +111,8 @@ static void usage() " single line emitted by falco to be flushed, which generates higher CPU\n" " usage but is useful when piping those outputs into another process\n" " or into a script.\n" - " -V,--validate Read the contents of the specified rules file and exit\n" + " -V,--validate Read the contents of the specified rules(s) file and exit\n" + " Can be specified multiple times to validate multiple files.\n" " -v Verbose output.\n" " --version Print version number.\n" "\n" @@ -245,7 +246,7 @@ int falco_init(int argc, char **argv) string pidfilename = "/var/run/falco.pid"; bool describe_all_rules = false; string describe_rule = ""; - string validate_rules_file = ""; + list validate_rules_filenames; string stats_filename = ""; bool verbose = false; bool all_events = false; @@ -396,7 +397,7 @@ int falco_init(int argc, char **argv) verbose = true; break; case 'V': - validate_rules_file = optarg; + validate_rules_filenames.push_back(optarg); break; case 'w': outfile = optarg; @@ -460,10 +461,17 @@ int falco_init(int argc, char **argv) } } - if(validate_rules_file != "") + if(validate_rules_filenames.size() > 0) { - falco_logger::log(LOG_INFO, "Validating rules file: " + validate_rules_file + "...\n"); - engine->load_rules_file(validate_rules_file, verbose, all_events); + falco_logger::log(LOG_INFO, "Validating rules file(s):\n"); + for(auto file : validate_rules_filenames) + { + falco_logger::log(LOG_INFO, " " + file + "\n"); + } + for(auto file : validate_rules_filenames) + { + engine->load_rules_file(file, verbose, all_events); + } falco_logger::log(LOG_INFO, "Ok\n"); goto exit; }