Also validate macros at parse time.

Also validate macros when they are parsed. Macros are also validated as
a part of rules being parsed, but it's possible to have an individual
rules file containing only macros, or a macro not explicitly tied to any
rule. In this case, it's useful to be able to check the macro to see if
it contains dangling macro references.
This commit is contained in:
Mark Stemm 2017-06-27 16:44:42 -07:00
parent 2991ea423a
commit 9e7ce4d36f
2 changed files with 29 additions and 13 deletions

View File

@ -58,15 +58,16 @@ end
definition uses another macro). definition uses another macro).
--]] --]]
function expand_macros(ast, defs, changed)
function copy(obj) function copy_ast_obj(obj)
if type(obj) ~= 'table' then return obj end if type(obj) ~= 'table' then return obj end
local res = {} local res = {}
for k, v in pairs(obj) do res[copy(k)] = copy(v) end for k, v in pairs(obj) do res[copy_ast_obj(k)] = copy_ast_obj(v) end
return res return res
end end
function expand_macros(ast, defs, changed)
if (ast.type == "Rule") then if (ast.type == "Rule") then
return expand_macros(ast.filter, defs, changed) return expand_macros(ast.filter, defs, changed)
elseif ast.type == "Filter" then elseif ast.type == "Filter" then
@ -74,7 +75,7 @@ function expand_macros(ast, defs, changed)
if (defs[ast.value.value] == nil) then if (defs[ast.value.value] == nil) then
error("Undefined macro '".. ast.value.value .. "' used in filter.") error("Undefined macro '".. ast.value.value .. "' used in filter.")
end end
ast.value = copy(defs[ast.value.value]) ast.value = copy_ast_obj(defs[ast.value.value])
changed = true changed = true
return changed return changed
end end
@ -86,7 +87,7 @@ function expand_macros(ast, defs, changed)
if (defs[ast.left.value] == nil) then if (defs[ast.left.value] == nil) then
error("Undefined macro '".. ast.left.value .. "' used in filter.") error("Undefined macro '".. ast.left.value .. "' used in filter.")
end end
ast.left = copy(defs[ast.left.value]) ast.left = copy_ast_obj(defs[ast.left.value])
changed = true changed = true
end end
@ -94,7 +95,7 @@ function expand_macros(ast, defs, changed)
if (defs[ast.right.value] == nil) then if (defs[ast.right.value] == nil) then
error("Undefined macro ".. ast.right.value .. " used in filter.") error("Undefined macro ".. ast.right.value .. " used in filter.")
end end
ast.right = copy(defs[ast.right.value]) ast.right = copy_ast_obj(defs[ast.right.value])
changed = true changed = true
end end
@ -107,7 +108,7 @@ function expand_macros(ast, defs, changed)
if (defs[ast.argument.value] == nil) then if (defs[ast.argument.value] == nil) then
error("Undefined macro ".. ast.argument.value .. " used in filter.") error("Undefined macro ".. ast.argument.value .. " used in filter.")
end end
ast.argument = copy(defs[ast.argument.value]) ast.argument = copy_ast_obj(defs[ast.argument.value])
changed = true changed = true
end end
return expand_macros(ast.argument, defs, changed) return expand_macros(ast.argument, defs, changed)
@ -281,7 +282,7 @@ function get_evttypes(name, ast, source)
return evttypes return evttypes
end end
function compiler.compile_macro(line, list_defs) function compiler.compile_macro(line, macro_defs, list_defs)
for name, items in pairs(list_defs) do for name, items in pairs(list_defs) do
line = string.gsub(line, name, table.concat(items, ", ")) line = string.gsub(line, name, table.concat(items, ", "))
@ -300,6 +301,21 @@ function compiler.compile_macro(line, list_defs)
check_for_ignored_syscalls_events(ast, 'macro', line) check_for_ignored_syscalls_events(ast, 'macro', line)
end end
-- Simply as a validation step, try to expand all macros in this
-- macro's condition. This changes the ast, so we make a copy
-- first.
local ast_copy = copy_ast_obj(ast)
if (ast.type == "Rule") then
-- Line is a filter, so expand macro references
repeat
expanded = expand_macros(ast_copy, macro_defs, false)
until expanded == false
else
error("Unexpected top-level AST type: "..ast.type)
end
return ast return ast
end end

View File

@ -283,7 +283,7 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac
local v = state.macros_by_name[name] local v = state.macros_by_name[name]
local ast = compiler.compile_macro(v['condition'], state.lists) local ast = compiler.compile_macro(v['condition'], state.macros, state.lists)
state.macros[v['macro']] = ast.filter.value state.macros[v['macro']] = ast.filter.value
end end