mirror of
https://github.com/falcosecurity/falco.git
synced 2025-07-05 19:06:44 +00:00
Merge pull request #41 from draios/error-on-filtered-syscall
Error on filtered syscall
This commit is contained in:
commit
fda5162061
@ -3,10 +3,31 @@
|
|||||||
#############
|
#############
|
||||||
|
|
||||||
# File actions
|
# File actions
|
||||||
- macro: write
|
|
||||||
condition: (syscall.type=write and fd.type in (file, directory))
|
|
||||||
- macro: read
|
# Currently disabled as read/write are ignored syscalls. The nearly
|
||||||
condition: (syscall.type=read and evt.dir=> and fd.type in (file, directory))
|
# similar open_write/open_read check for files being opened for
|
||||||
|
# reading/writing.
|
||||||
|
# - macro: write
|
||||||
|
# condition: (syscall.type=write and fd.type in (file, directory))
|
||||||
|
# - macro: read
|
||||||
|
# condition: (syscall.type=read and evt.dir=> and fd.type in (file, directory))
|
||||||
|
|
||||||
|
- macro: open_write
|
||||||
|
condition: >
|
||||||
|
(evt.type=open or evt.type=openat) and
|
||||||
|
fd.typechar='f' and
|
||||||
|
(evt.arg.flags contains O_WRONLY or
|
||||||
|
evt.arg.flags contains O_RDWR or
|
||||||
|
evt.arg.flags contains O_CREAT or
|
||||||
|
evt.arg.flags contains O_TRUNC)
|
||||||
|
- macro: open_read
|
||||||
|
condition: >
|
||||||
|
(evt.type=open or evt.type=openat) and
|
||||||
|
fd.typechar='f' and
|
||||||
|
(evt.arg.flags contains O_RDONLY or
|
||||||
|
evt.arg.flags contains O_RDWR)
|
||||||
|
|
||||||
- macro: rename
|
- macro: rename
|
||||||
condition: syscall.type = rename
|
condition: syscall.type = rename
|
||||||
- macro: mkdir
|
- macro: mkdir
|
||||||
@ -79,8 +100,10 @@
|
|||||||
# Network
|
# Network
|
||||||
- macro: inbound
|
- macro: inbound
|
||||||
condition: (syscall.type=listen and evt.dir=>) or (syscall.type=accept and evt.dir=<)
|
condition: (syscall.type=listen and evt.dir=>) or (syscall.type=accept and evt.dir=<)
|
||||||
|
|
||||||
|
# Currently sendto is an ignored syscall, otherwise this could also check for (syscall.type=sendto and evt.dir=>)
|
||||||
- macro: outbound
|
- macro: outbound
|
||||||
condition: ((syscall.type=connect and evt.dir=<) or (syscall.type=sendto and evt.dir=>)) and (fd.typechar=4 or fd.typechar=6)
|
condition: syscall.type=connect and evt.dir=< and (fd.typechar=4 or fd.typechar=6)
|
||||||
|
|
||||||
- macro: ssh_port
|
- macro: ssh_port
|
||||||
condition: fd.lport=22
|
condition: fd.lport=22
|
||||||
@ -112,17 +135,17 @@
|
|||||||
#######
|
#######
|
||||||
|
|
||||||
# Don't write to binary dirs
|
# Don't write to binary dirs
|
||||||
- condition: evt.dir = > and write and bin_dir
|
- condition: evt.dir = > and open_write and bin_dir
|
||||||
output: "Write to bin dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
output: "Write to bin dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||||
priority: WARNING
|
priority: WARNING
|
||||||
|
|
||||||
# Don't write to /etc
|
# Don't write to /etc
|
||||||
- condition: evt.dir = > and write and etc_dir
|
- condition: evt.dir = > and open_write and etc_dir
|
||||||
output: "Write to etc dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
output: "Write to etc dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||||
priority: WARNING
|
priority: WARNING
|
||||||
|
|
||||||
# Don't read 'sensitive' files
|
# Don't read 'sensitive' files
|
||||||
- condition: read and not proc.name in (sshd, sudo, su) and not_cron and sensitive_files
|
- condition: open_read and not proc.name in (sshd, sudo, su) and not_cron and sensitive_files
|
||||||
output: "Read sensitive file (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
output: "Read sensitive file (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||||
priority: WARNING
|
priority: WARNING
|
||||||
|
|
||||||
@ -132,7 +155,7 @@
|
|||||||
priority: WARNING
|
priority: WARNING
|
||||||
|
|
||||||
# Don't load shared objects coming from unexpected places
|
# Don't load shared objects coming from unexpected places
|
||||||
- condition: read and fd.name contains .so and not (ubuntu_so_dirs or centos_so_dirs)
|
- condition: open_read and fd.name contains .so and not (ubuntu_so_dirs or centos_so_dirs)
|
||||||
output: "Loaded .so from unexpected dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
output: "Loaded .so from unexpected dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||||
priority: WARNING
|
priority: WARNING
|
||||||
|
|
||||||
|
@ -111,6 +111,51 @@ function get_macros(ast, set)
|
|||||||
return set
|
return set
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function check_for_ignored_syscalls_events(ast, filter_type, source)
|
||||||
|
|
||||||
|
function check_syscall(val)
|
||||||
|
if ignored_syscalls[val] then
|
||||||
|
error("Ignored syscall \""..val.."\" in "..filter_type..": "..source)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function check_event(val)
|
||||||
|
if ignored_events[val] then
|
||||||
|
error("Ignored event \""..val.."\" in "..filter_type..": "..source)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function cb(node)
|
||||||
|
if node.left.type == "FieldName" and
|
||||||
|
(node.left.value == "evt.type" or
|
||||||
|
node.left.value == "syscall.type") then
|
||||||
|
|
||||||
|
if node.operator == "in" then
|
||||||
|
for i, v in ipairs(node.right.elements) do
|
||||||
|
if v.type == "BareString" then
|
||||||
|
if node.left.value == "evt.type" then
|
||||||
|
check_event(v.value)
|
||||||
|
else
|
||||||
|
check_syscall(v.value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if node.right.type == "BareString" then
|
||||||
|
if node.left.value == "evt.type" then
|
||||||
|
check_event(node.right.value)
|
||||||
|
else
|
||||||
|
check_syscall(node.right.value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
parser.traverse_ast(ast, "BinaryRelOp", cb)
|
||||||
|
end
|
||||||
|
|
||||||
function compiler.compile_macro(line)
|
function compiler.compile_macro(line)
|
||||||
local ast, error_msg = parser.parse_filter(line)
|
local ast, error_msg = parser.parse_filter(line)
|
||||||
|
|
||||||
@ -119,6 +164,10 @@ function compiler.compile_macro(line)
|
|||||||
error(error_msg)
|
error(error_msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Traverse the ast looking for events/syscalls in the ignored
|
||||||
|
-- syscalls table. If any are found, return an error.
|
||||||
|
check_for_ignored_syscalls_events(ast, 'macro', line)
|
||||||
|
|
||||||
return ast
|
return ast
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -133,6 +182,10 @@ function compiler.compile_filter(source, macro_defs)
|
|||||||
error(error_msg)
|
error(error_msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Traverse the ast looking for events/syscalls in the ignored
|
||||||
|
-- syscalls table. If any are found, return an error.
|
||||||
|
check_for_ignored_syscalls_events(ast, 'rule', source)
|
||||||
|
|
||||||
if (ast.type == "Rule") then
|
if (ast.type == "Rule") then
|
||||||
-- Line is a filter, so expand macro references
|
-- Line is a filter, so expand macro references
|
||||||
repeat
|
repeat
|
||||||
|
@ -291,4 +291,46 @@ function print_ast(ast, level)
|
|||||||
end
|
end
|
||||||
parser.print_ast = print_ast
|
parser.print_ast = print_ast
|
||||||
|
|
||||||
|
-- Traverse the provided ast and call the provided callback function
|
||||||
|
-- for any nodes of the specified type. The callback function should
|
||||||
|
-- have the signature:
|
||||||
|
-- cb(ast_node, ctx)
|
||||||
|
-- ctx is optional.
|
||||||
|
function traverse_ast(ast, node_type, cb, ctx)
|
||||||
|
local t = ast.type
|
||||||
|
|
||||||
|
if t == node_type then
|
||||||
|
cb(ast, ctx)
|
||||||
|
end
|
||||||
|
|
||||||
|
if t == "Rule" then
|
||||||
|
traverse_ast(ast.filter, node_type, cb, ctx)
|
||||||
|
|
||||||
|
elseif t == "Filter" then
|
||||||
|
traverse_ast(ast.value, node_type, cb, ctx)
|
||||||
|
|
||||||
|
elseif t == "BinaryBoolOp" or t == "BinaryRelOp" then
|
||||||
|
traverse_ast(ast.left, node_type, cb, ctx)
|
||||||
|
traverse_ast(ast.right, node_type, cb, ctx)
|
||||||
|
|
||||||
|
elseif t == "UnaryRelOp" or t == "UnaryBoolOp" then
|
||||||
|
traverse_ast(ast.argument, node_type, cb, ctx)
|
||||||
|
|
||||||
|
elseif t == "List" then
|
||||||
|
for i, v in ipairs(ast.elements) do
|
||||||
|
traverse_ast(v, node_type, cb, ctx)
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif t == "MacroDef" then
|
||||||
|
traverse_ast(ast.value, node_type, cb, ctx)
|
||||||
|
|
||||||
|
elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then
|
||||||
|
-- do nothing, no traversal needed
|
||||||
|
|
||||||
|
else
|
||||||
|
error ("Unexpected type in traverse_ast: "..t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
parser.traverse_ast = traverse_ast
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
@ -9,6 +9,7 @@ extern "C" {
|
|||||||
|
|
||||||
falco_rules::falco_rules(sinsp* inspector, lua_State *ls, string lua_main_filename)
|
falco_rules::falco_rules(sinsp* inspector, lua_State *ls, string lua_main_filename)
|
||||||
{
|
{
|
||||||
|
m_inspector = inspector;
|
||||||
m_ls = ls;
|
m_ls = ls;
|
||||||
|
|
||||||
m_lua_parser = new lua_parser(inspector, m_ls);
|
m_lua_parser = new lua_parser(inspector, m_ls);
|
||||||
@ -44,6 +45,42 @@ void falco_rules::load_rules(string rules_filename)
|
|||||||
lua_getglobal(m_ls, m_lua_load_rules.c_str());
|
lua_getglobal(m_ls, m_lua_load_rules.c_str());
|
||||||
if(lua_isfunction(m_ls, -1))
|
if(lua_isfunction(m_ls, -1))
|
||||||
{
|
{
|
||||||
|
// Create a table containing the syscalls/events that
|
||||||
|
// are ignored by the kernel module. load_rules will
|
||||||
|
// return an error if any rule references one of these
|
||||||
|
// syscalls/events.
|
||||||
|
sinsp_evttables* einfo = m_inspector->get_event_info_tables();
|
||||||
|
const struct ppm_event_info* etable = einfo->m_event_info;
|
||||||
|
const struct ppm_syscall_desc* stable = einfo->m_syscall_info_table;
|
||||||
|
|
||||||
|
lua_newtable(m_ls);
|
||||||
|
|
||||||
|
for(uint32_t j = 0; j < PPM_EVENT_MAX; j++)
|
||||||
|
{
|
||||||
|
if(etable[j].flags & EF_DROP_FALCO)
|
||||||
|
{
|
||||||
|
lua_pushstring(m_ls, etable[j].name);
|
||||||
|
lua_pushnumber(m_ls, 1);
|
||||||
|
lua_settable(m_ls, -3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_setglobal(m_ls, m_lua_ignored_events.c_str());
|
||||||
|
|
||||||
|
lua_newtable(m_ls);
|
||||||
|
|
||||||
|
for(uint32_t j = 0; j < PPM_SC_MAX; j++)
|
||||||
|
{
|
||||||
|
if(stable[j].flags & EF_DROP_FALCO)
|
||||||
|
{
|
||||||
|
lua_pushstring(m_ls, stable[j].name);
|
||||||
|
lua_pushnumber(m_ls, 1);
|
||||||
|
lua_settable(m_ls, -3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_setglobal(m_ls, m_lua_ignored_syscalls.c_str());
|
||||||
|
|
||||||
lua_pushstring(m_ls, rules_filename.c_str());
|
lua_pushstring(m_ls, rules_filename.c_str());
|
||||||
if(lua_pcall(m_ls, 1, 0, 0) != 0)
|
if(lua_pcall(m_ls, 1, 0, 0) != 0)
|
||||||
{
|
{
|
||||||
|
@ -15,8 +15,11 @@ class falco_rules
|
|||||||
void load_compiler(string lua_main_filename);
|
void load_compiler(string lua_main_filename);
|
||||||
|
|
||||||
lua_parser* m_lua_parser;
|
lua_parser* m_lua_parser;
|
||||||
|
sinsp* m_inspector;
|
||||||
lua_State* m_ls;
|
lua_State* m_ls;
|
||||||
|
|
||||||
string m_lua_load_rules = "load_rules";
|
string m_lua_load_rules = "load_rules";
|
||||||
|
string m_lua_ignored_syscalls = "ignored_syscalls";
|
||||||
|
string m_lua_ignored_events = "ignored_events";
|
||||||
string m_lua_on_event = "on_event";
|
string m_lua_on_event = "on_event";
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user