mirror of
https://github.com/falcosecurity/falco.git
synced 2025-09-10 02:59:38 +00:00
Compile and load digwatch rules!
This commit is contained in:
@@ -453,17 +453,17 @@ end
|
|||||||
to the line-oriented compiler.
|
to the line-oriented compiler.
|
||||||
--]]
|
--]]
|
||||||
function compiler.init()
|
function compiler.init()
|
||||||
return {macros={}}
|
return {macros={}, ast=nil}
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Compiles a digwatch filter or macro
|
Compiles a single line from a digwatch ruleset and updates the passed-in state object. Returns the AST of the line.
|
||||||
--]]
|
--]]
|
||||||
function compiler.compile_line(line, state)
|
function compiler.compile_line(line, state)
|
||||||
local ast, error_msg = compiler.parser.parse_line(line)
|
local ast, error_msg = compiler.parser.parse_line(line)
|
||||||
|
|
||||||
if (error_msg) then
|
if (error_msg) then
|
||||||
return nil, error_msg
|
error(error_msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
local macros = get_macros(ast.value, {})
|
local macros = get_macros(ast.value, {})
|
||||||
@@ -474,20 +474,31 @@ function compiler.compile_line(line, state)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if (ast.type == "MacroDef") then
|
if (ast.type == "MacroDef") then
|
||||||
|
-- Parsed line is a macro definition, so update our dictionary of macros and
|
||||||
|
-- return
|
||||||
state.macros[ast.name] = ast.value
|
state.macros[ast.name] = ast.value
|
||||||
return ast, error_msg
|
return ast
|
||||||
|
|
||||||
elseif (ast.type == "Filter") then
|
elseif (ast.type == "Filter") then
|
||||||
|
-- Line is a filter, so expand in-clauses and macro references, then
|
||||||
|
-- stitch it into global ast
|
||||||
|
|
||||||
expand_in(ast)
|
expand_in(ast)
|
||||||
|
|
||||||
repeat
|
repeat
|
||||||
expanded = expand_macros(ast, state.macros, false)
|
expanded = expand_macros(ast, state.macros, false)
|
||||||
until expanded == false
|
until expanded == false
|
||||||
|
|
||||||
|
if (state.ast == nil) then
|
||||||
|
state.ast = ast
|
||||||
|
else
|
||||||
|
state.ast = { type = "BinaryBoolOp", operator = "or", left = state.ast, right = ast }
|
||||||
|
end
|
||||||
else
|
else
|
||||||
error("Unexpected top-level AST type: "..ast.type)
|
error("Unexpected top-level AST type: "..ast.type)
|
||||||
end
|
end
|
||||||
|
|
||||||
return ast, error_msg
|
return ast
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
78
lua/rule_loader.lua
Normal file
78
lua/rule_loader.lua
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
--[[
|
||||||
|
Compile and install digwatch rules.
|
||||||
|
|
||||||
|
This module exports functions that are called from digwatch c++-side to compile and install a set of rules.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local compiler = require "compiler"
|
||||||
|
|
||||||
|
local function install_filter(node)
|
||||||
|
local t = node.type
|
||||||
|
|
||||||
|
if t == "Filter" then
|
||||||
|
install_filter(node.value)
|
||||||
|
|
||||||
|
elseif t == "BinaryBoolOp" then
|
||||||
|
filter.nest() --io.write("(")
|
||||||
|
install_filter(node.left)
|
||||||
|
filter.bool_op(node.operator) --io.write(" "..node.operator.." ")
|
||||||
|
install_filter(node.right)
|
||||||
|
filter.unnest() --io.write(")")
|
||||||
|
|
||||||
|
|
||||||
|
elseif t == "UnaryBoolOp" then
|
||||||
|
filter.nest() --io.write("(")
|
||||||
|
filter.bool_op(node.operator) -- io.write(" "..node.operator.." ")
|
||||||
|
install_filter(node.argument)
|
||||||
|
filter.unnest() -- io.write(")")
|
||||||
|
|
||||||
|
elseif t == "BinaryRelOp" then
|
||||||
|
filter.rel_expr(node.left.value, node.operator, node.right.value)
|
||||||
|
-- io.write(node.left.value.." "..node.operator.." "..node.right.value)
|
||||||
|
|
||||||
|
-- xxx still need to handle case where node.right.type=="list"
|
||||||
|
|
||||||
|
elseif t == "UnaryRelOp" then
|
||||||
|
filter.rel_expr(node.argument.value, node.operator)
|
||||||
|
--io.write(node.argument.value.." "..node.operator)
|
||||||
|
|
||||||
|
elseif t == "List" then
|
||||||
|
error("Not handling List yet")
|
||||||
|
|
||||||
|
elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then
|
||||||
|
error ("Unexpected type: "..t)
|
||||||
|
|
||||||
|
io.write(t.." "..node.value)
|
||||||
|
|
||||||
|
elseif t == "MacroDef" then
|
||||||
|
error ("Unexpected type: "..t)
|
||||||
|
else
|
||||||
|
error ("Unexpected type: "..t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- filter.rel_expr("proc.name", "=", "cat")
|
||||||
|
-- filter.bool_op("and")
|
||||||
|
-- filter.nest()
|
||||||
|
-- filter.nest()
|
||||||
|
-- filter.rel_expr("fd.num", "=", "1")
|
||||||
|
-- filter.bool_op("or")
|
||||||
|
-- filter.rel_expr("fd.num", "=", "2")
|
||||||
|
-- filter.unnest()
|
||||||
|
-- filter.unnest()
|
||||||
|
|
||||||
|
local state
|
||||||
|
|
||||||
|
|
||||||
|
function load_rule(r)
|
||||||
|
if (state == nil) then
|
||||||
|
state = compiler.init()
|
||||||
|
end
|
||||||
|
compiler.compile_line(r, state)
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_done()
|
||||||
|
install_filter(state.ast)
|
||||||
|
end
|
@@ -1,4 +1,4 @@
|
|||||||
local compiler = require "sysdig-parser"
|
local compiler = require "compiler"
|
||||||
|
|
||||||
if #arg ~= 1 then
|
if #arg ~= 1 then
|
||||||
print("Usage: test.lua <string>")
|
print("Usage: test.lua <string>")
|
||||||
@@ -8,18 +8,19 @@ end
|
|||||||
local state = compiler.init()
|
local state = compiler.init()
|
||||||
|
|
||||||
local function doit(line)
|
local function doit(line)
|
||||||
local ast, error_msg = compiler.compile_line(line, state)
|
local ast = compiler.compile_line(line, state)
|
||||||
|
|
||||||
if not ast then
|
if not ast then
|
||||||
print("error", error_msg)
|
print("error", error_msg)
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
compiler.parser.print_ast(ast)
|
|
||||||
end
|
end
|
||||||
for str in string.gmatch(arg[1], "([^;]+)") do
|
for str in string.gmatch(arg[1], "([^;]+)") do
|
||||||
doit(str)
|
doit(str)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
compiler.parser.print_ast(state.ast)
|
||||||
|
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
|
|
||||||
|
@@ -33,7 +33,7 @@ static void usage()
|
|||||||
" -h, --help Print this page\n"
|
" -h, --help Print this page\n"
|
||||||
" -m <filename>, --main-lua <filename>\n"
|
" -m <filename>, --main-lua <filename>\n"
|
||||||
" Name of lua compiler main file\n"
|
" Name of lua compiler main file\n"
|
||||||
" (default: rules_loader.lua\n"
|
" (default: rules_loader.lua)\n"
|
||||||
" -M <num_seconds> Stop collecting after <num_seconds> reached.\n"
|
" -M <num_seconds> Stop collecting after <num_seconds> reached.\n"
|
||||||
" -N Don't convert port numbers to names.\n"
|
" -N Don't convert port numbers to names.\n"
|
||||||
" -n <num>, --numevents=<num>\n"
|
" -n <num>, --numevents=<num>\n"
|
||||||
@@ -244,18 +244,18 @@ int digwatch_init(int argc, char **argv)
|
|||||||
//
|
//
|
||||||
sinsp_evt_formatter formatter(inspector, output_format);
|
sinsp_evt_formatter formatter(inspector, output_format);
|
||||||
|
|
||||||
trim(lua_main_filename);
|
|
||||||
if (lua_main_filename.size() == 0)
|
|
||||||
{
|
|
||||||
lua_main_filename = DIGWATCH_LUA_MAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* env_lua_dir = getenv("DIGWATCH_LUA_DIR");
|
char* env_lua_dir = getenv("DIGWATCH_LUA_DIR");
|
||||||
if (env_lua_dir)
|
if (env_lua_dir)
|
||||||
{
|
{
|
||||||
lua_dir = string(env_lua_dir);
|
lua_dir = string(env_lua_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trim(lua_main_filename);
|
||||||
|
if (lua_main_filename.size() == 0)
|
||||||
|
{
|
||||||
|
lua_main_filename = lua_dir + DIGWATCH_LUA_MAIN;
|
||||||
|
}
|
||||||
|
|
||||||
rules = new digwatch_rules(inspector, lua_main_filename, lua_dir);
|
rules = new digwatch_rules(inspector, lua_main_filename, lua_dir);
|
||||||
|
|
||||||
rules->load_rules(rules_file);
|
rules->load_rules(rules_file);
|
||||||
|
@@ -67,18 +67,18 @@ void digwatch_rules::load_rules(string rules_filename)
|
|||||||
throw sinsp_exception("can't open file " + rules_filename);
|
throw sinsp_exception("can't open file " + rules_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_getglobal(m_ls, m_lua_compiler_cb.c_str());
|
lua_getglobal(m_ls, m_lua_load_rule.c_str());
|
||||||
if(lua_isfunction(m_ls, -1))
|
if(lua_isfunction(m_ls, -1))
|
||||||
{
|
{
|
||||||
lua_pop(m_ls, 1);
|
lua_pop(m_ls, 1);
|
||||||
} else {
|
} else {
|
||||||
throw sinsp_exception("No function " + m_lua_compiler_cb + " found in lua compiler module");
|
throw sinsp_exception("No function " + m_lua_load_rule + " found in lua compiler module");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(is, line))
|
while (std::getline(is, line))
|
||||||
{
|
{
|
||||||
lua_getglobal(m_ls, m_lua_compiler_cb.c_str());
|
lua_getglobal(m_ls, m_lua_load_rule.c_str());
|
||||||
lua_pushstring(m_ls, line.c_str());
|
lua_pushstring(m_ls, line.c_str());
|
||||||
|
|
||||||
if(lua_pcall(m_ls, 1, 0, 0) != 0)
|
if(lua_pcall(m_ls, 1, 0, 0) != 0)
|
||||||
@@ -89,6 +89,18 @@ void digwatch_rules::load_rules(string rules_filename)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lua_getglobal(m_ls, m_lua_on_done.c_str());
|
||||||
|
if(lua_isfunction(m_ls, -1))
|
||||||
|
{
|
||||||
|
if(lua_pcall(m_ls, 0, 0, 0) != 0)
|
||||||
|
{
|
||||||
|
const char* lerr = lua_tostring(m_ls, -1);
|
||||||
|
string err = "Error installing rules: " + string(lerr);
|
||||||
|
throw sinsp_exception(err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw sinsp_exception("No function " + m_lua_on_done + " found in lua compiler module");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,6 +17,6 @@ class digwatch_rules
|
|||||||
|
|
||||||
lua_parser* m_lua_parser;
|
lua_parser* m_lua_parser;
|
||||||
lua_State* m_ls;
|
lua_State* m_ls;
|
||||||
string m_lua_compiler_cb = "load_rules";
|
string m_lua_load_rule = "load_rule";
|
||||||
string m_lua_;
|
string m_lua_on_done = "on_done";
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user