update(engine): create a lua helper for rule filter manipulation

The lua_filter_helper class is a simple Lua wrapper that can be used in the Lua rule loader to
parse/compile rule filters, and manipulate them to resolve/replace list and macro references.

Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
Jason Dellaluce
2022-02-28 17:14:29 +00:00
committed by poiana
parent 3879a283bf
commit 911bd16556
6 changed files with 263 additions and 5 deletions

View File

@@ -19,7 +19,9 @@ set(FALCO_ENGINE_SOURCE_FILES
falco_utils.cpp
json_evt.cpp
ruleset.cpp
formats.cpp)
formats.cpp
filter_macro_resolver.cpp
lua_filter_helper.cpp)
add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES})
add_dependencies(falco_engine njson lyaml string-view-lite)

View File

@@ -28,8 +28,8 @@ limitations under the License.
#include "formats.h"
#include "lua_filter_helper.h"
extern "C" {
#include "lpeg.h"
#include "lyaml.h"
}
@@ -53,6 +53,7 @@ falco_engine::falco_engine(bool seed_rng)
falco_common::init();
falco_rules::init(m_ls);
lua_filter_helper::init(m_ls);
m_required_plugin_versions.clear();

View File

@@ -1418,7 +1418,7 @@ json_event_filter_check *k8s_audit_filter_check::allocate_new()
return (json_event_filter_check *)chk;
}
json_event_filter::json_event_filter()
json_event_filter::json_event_filter(): sinsp_filter(NULL)
{
}

View File

@@ -27,7 +27,7 @@ limitations under the License.
#include <nlohmann/json.hpp>
#include "prefix_search.h"
#include "gen_filter.h"
#include <sinsp.h>
class json_event : public gen_event
{
@@ -383,7 +383,8 @@ public:
json_event_filter_check &jchk);
};
class json_event_filter : public gen_event_filter
class json_event_filter : public sinsp_filter
{
public:
json_event_filter();

View File

@@ -0,0 +1,217 @@
/*
Copyright (C) 2022 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <sinsp.h>
#include "lua_filter_helper.h"
#include "filter_macro_resolver.h"
#include "filter_list_resolver.h"
#include "rules.h"
using namespace std;
using namespace libsinsp::filter;
// The code below implements the Lua wrapper.
// todo(jasondellaluce): remove this once Lua is removed from Falco
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
const static struct luaL_Reg ll_filter_helper[] =
{
{"compile_filter", &lua_filter_helper::compile_filter},
{"parse_filter", &lua_filter_helper::parse_filter},
{"expand_list", &lua_filter_helper::expand_list},
{"expand_macro", &lua_filter_helper::expand_macro},
{"find_unknown_macro", &lua_filter_helper::find_unknown_macro},
{"clone_ast", &lua_filter_helper::clone_ast},
{"delete_ast", &lua_filter_helper::delete_ast},
{NULL, NULL}
};
void lua_filter_helper::init(lua_State *ls)
{
luaL_openlib(ls, "filter_helper", ll_filter_helper, 0);
}
int lua_filter_helper::parse_filter(lua_State *ls)
{
if (! lua_isstring(ls, -1))
{
lua_pushstring(ls, "invalid argument passed to parse_filter()");
lua_error(ls);
}
string filter_str = lua_tostring(ls, -1);
parser p(filter_str);
p.set_max_depth(1000);
try
{
auto filter = p.parse();
lua_pushboolean(ls, true);
lua_pushlightuserdata(ls, filter);
}
catch (const sinsp_exception& e)
{
string err = to_string(p.get_pos().col) + ": " + e.what();
lua_pushboolean(ls, false);
lua_pushstring(ls, err.c_str());
}
return 2;
}
int lua_filter_helper::compile_filter(lua_State *ls)
{
if (! lua_islightuserdata(ls, -4) ||
! lua_islightuserdata(ls, -3) ||
! lua_isstring(ls, -2) ||
! lua_isnumber(ls, -1))
{
lua_pushstring(ls, "invalid argument passed to compile_filter()");
lua_error(ls);
}
falco_rules *rules = (falco_rules *) lua_topointer(ls, -4);
ast::expr* ast = (ast::expr*) lua_topointer(ls, -3);
std::string source = lua_tostring(ls, -2);
int32_t check_id = (int32_t) luaL_checkinteger(ls, -1);
try
{
sinsp_filter_compiler compiler(rules->get_filter_factory(source), ast);
compiler.set_check_id(check_id);
gen_event_filter* filter = compiler.compile();
lua_pushboolean(ls, true);
lua_pushlightuserdata(ls, filter);
}
catch (const sinsp_exception& e)
{
lua_pushboolean(ls, false);
lua_pushstring(ls, e.what());
}
catch (const falco_exception& e)
{
lua_pushboolean(ls, false);
lua_pushstring(ls, e.what());
}
return 2;
}
int lua_filter_helper::expand_list(lua_State *ls)
{
if (! lua_islightuserdata(ls, -3) || // ast
! lua_isstring(ls, -2) || // name
! lua_istable(ls, -1)) // values
{
lua_pushstring(ls, "invalid arguments passed to expand_list()");
lua_error(ls);
}
ast::expr* ast = (ast::expr*) lua_topointer(ls, -3);
std::string name = lua_tostring(ls, -2);
vector<string> values;
// first key
lua_pushnil(ls);
while (lua_next(ls, -2) != 0) {
// key is at index -2, value is at index
// -1. We want the values.
values.push_back(lua_tostring(ls, -1));
// Remove value, keep key for next iteration
lua_pop(ls, 1);
}
filter_list_resolver resolver;
resolver.define_list(name, values);
resolver.process(ast);
lua_pushboolean(ls, !resolver.get_resolved_lists().empty());
lua_pushlightuserdata(ls, ast);
return 2;
}
int lua_filter_helper::expand_macro(lua_State *ls)
{
if (! lua_islightuserdata(ls, -3) || // ast
! lua_isstring(ls, -2) || // name
! lua_islightuserdata(ls, -1)) // macro
{
lua_pushstring(ls, "invalid arguments passed to expand_macro()");
lua_error(ls);
}
ast::expr* ast = (ast::expr*) lua_topointer(ls, -3);
std::string name = lua_tostring(ls, -2);
ast::expr* macro = (ast::expr*) lua_topointer(ls, -1);
filter_macro_resolver resolver;
resolver.define_macro(name, macro);
resolver.process(ast);
lua_pushboolean(ls, !resolver.get_resolved_macros().empty());
lua_pushlightuserdata(ls, ast);
return 2;
}
int lua_filter_helper::find_unknown_macro(lua_State *ls)
{
if (! lua_islightuserdata(ls, -1)) // ast
{
lua_pushstring(ls, "invalid arguments passed to find_unknown_macro()");
lua_error(ls);
}
ast::expr* ast = (ast::expr*) lua_topointer(ls, -1);
filter_macro_resolver resolver;
resolver.process(ast);
if (!resolver.get_unknown_macros().empty())
{
lua_pushboolean(ls, true);
lua_pushstring(ls, resolver.get_unknown_macros().begin()->c_str());
}
else
{
lua_pushboolean(ls, false);
lua_pushstring(ls, "");
}
return 2;
}
int lua_filter_helper::clone_ast(lua_State *ls)
{
if (! lua_islightuserdata(ls, -1)) // ast
{
lua_pushstring(ls, "Invalid arguments passed to clone_ast()");
lua_error(ls);
}
ast::expr* ast = (ast::expr*) lua_topointer(ls, -1);
ast::expr* cloned_ast = ast::clone(ast);
lua_pushlightuserdata(ls, cloned_ast);
return 1;
}
int lua_filter_helper::delete_ast(lua_State *ls)
{
if (! lua_islightuserdata(ls, -1)) // ptr
{
lua_pushstring(ls, "Invalid arguments passed to delete_ast()");
lua_error(ls);
}
delete (ast::expr*) lua_topointer(ls, -1);
return 0;
}

View File

@@ -0,0 +1,37 @@
/*
Copyright (C) 2022 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
// todo(jasondellaluce): remove this once Lua is removed from Falco
typedef struct lua_State lua_State;
/*!
\brief This is a Lua helper for filter-related operations
todo(jasondellaluce): remove this once Lua is removed from Falco
*/
class lua_filter_helper
{
public:
static void init(lua_State *ls);
static int compile_filter(lua_State *ls);
static int parse_filter(lua_State *ls);
static int expand_list(lua_State *ls);
static int expand_macro(lua_State *ls);
static int find_unknown_macro(lua_State *ls);
static int clone_ast(lua_State *ls);
static int delete_ast(lua_State *ls);
};