Compare commits

...

17 Commits

Author SHA1 Message Date
Leonardo Grasso
df3b4c1ae9 chore(userpsace/engine): update fields checksum
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-01-17 17:36:57 +01:00
Mark Stemm
85e25cb0d9 Skip EPF_TABLE_ONLY fields with --list -N
When listing fields with -N (names only), also skip fields with the
EPF_TABLE_ONLY flag. (Skipping fields without -N is handled in libs,
in the as_string() method).

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-01-17 17:29:16 +01:00
Federico Di Pierro
0c290d98f8 fix(tests): avoid hardcoding plugin version 0.1.0 in plugin tests.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-01-17 17:20:33 +01:00
Federico Di Pierro
1befb053d0 update(gitignore): drop 2 useless lines from gitignore that are now installed in the build folder.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-01-17 17:20:33 +01:00
Federico Di Pierro
ae57718bda update(build): updated libs to latest master version. Updated plugins versions. Updated falco engine version.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-01-17 17:20:33 +01:00
Luca Guerra
55ce38cf3a use debian 11 slim as nodriver image
Signed-off-by: Luca Guerra <luca@guerra.sh>
2022-01-17 16:26:07 +01:00
Luca Guerra
18571eb20d ci: build stripped tgz
Signed-off-by: Luca Guerra <luca@guerra.sh>
2022-01-17 16:26:07 +01:00
Luca Guerra
9c449901f3 cmake: do not strip tar gz builds
Signed-off-by: Luca Guerra <luca@guerra.sh>
2022-01-17 16:26:07 +01:00
Jason Dellaluce
4ab8d6db98 refactor(configuration): remove plugin config loading from file feature
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-01-17 14:55:11 +01:00
Jason Dellaluce
5e354859a9 new(configuration): allow defining plugin config as YAML maps
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-01-17 14:55:11 +01:00
Jason Dellaluce
f4b79296fc fix: improve nested configuration field support
This fixes the parser introduced in https://github.com/falcosecurity/falco/pull/1792.
Now, nested fields such as `arr[1].subval` are supported, whereas the parser used
to recognize the `.` as an unexpected character.

Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-01-17 14:55:11 +01:00
Jason Dellaluce
6bf8f34d9f fix(engine): correctly format json output in json_event
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-01-14 13:29:33 +01:00
vadim.zyarko
f8f053c7fa Add an emty line to sattisfy the rules tests
Signed-off-by: vadim.zyarko <vadim.zyarko@sysdig.com>
2022-01-13 09:44:57 +01:00
VadimZy
b88a1cbb09 replace .. with table concat
Signed-off-by: vadim.zyarko <vadim.zyarko@sysdig.com>
2022-01-13 09:44:57 +01:00
Mark Stemm
c86615f68c Embed .lua files into falco executable
Instead of having .lua files external to the program responsible for
loading rules, embed the contents of those files into the executable
and load them as strings instead of as files:

Add a cmake custom command below userspace/engine/lua that calls a
bash script lua-to-cpp.sh to generate falco_engine_lua_files.{cpp,hh}
that are compiled into the falco engine library.

The script creates a .cpp file that has const char * symbols for each
file, as well as lists of files that should be loaded when the falco
engine is loaded. There are actually two lists:

- lua_module_strings: these are loaded and also added to the lua
  runtime package.preload table, so they are available when lua code
  require()s them.

- lua_code_strings: these are loaded *and* evaluated, so the functions
  in them are availble to be called from C++.

This simplifies some of the falco_common methods, as there's no need
to keep track of a "main" lua file to load or paths from which the lua
loader should find files for modules, and there's no need to keep
track of an "alternate" lua directory that occurs for debug builds.

Also, there's no need to include any .lua files in the installed
packages, as they're built into the falco binary.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-01-13 09:26:35 +01:00
Mark Stemm
08df1c63cf Clean up lyaml build a bit
change LYAML_SRC to LYAML_ROOT, which points to the top source
directory now.

LYAML_LIB and (new) LYAML_LUA_DIR are based relative to that
directory.

There's no install step at all now--the static library and the .lua
files are now used directly from the source tree.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-01-13 09:26:35 +01:00
Mark Stemm
10512b9ef9 Move compiler/parser lua files to a "modules" subdir
This will distinguish it from rule_loader.lua, which is *not* a module
but lua code with functions that can be called directly.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-01-13 09:26:35 +01:00
21 changed files with 311 additions and 230 deletions

View File

@@ -392,8 +392,8 @@ jobs:
- run: - run:
name: Publish bin-dev name: Publish bin-dev
command: | command: |
FALCO_VERSION=$(cat /build-static/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//') FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
/source/falco/scripts/publish-bin -f /build-static/release/falco-${FALCO_VERSION}-x86_64.tar.gz -r bin-dev -a x86_64 /source/falco/scripts/publish-bin -f /build/release/falco-${FALCO_VERSION}-x86_64.tar.gz -r bin-dev -a x86_64
"publish/packages-deb-dev": "publish/packages-deb-dev":
docker: docker:
- image: docker.io/debian:stable - image: docker.io/debian:stable
@@ -506,8 +506,8 @@ jobs:
- run: - run:
name: Publish bin name: Publish bin
command: | command: |
FALCO_VERSION=$(cat /build-static/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//') FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
/source/falco/scripts/publish-bin -f /build-static/release/falco-${FALCO_VERSION}-x86_64.tar.gz -r bin -a x86_64 /source/falco/scripts/publish-bin -f /build/release/falco-${FALCO_VERSION}-x86_64.tar.gz -r bin -a x86_64
"publish/packages-deb": "publish/packages-deb":
docker: docker:
- image: docker.io/debian:stable - image: docker.io/debian:stable
@@ -711,7 +711,6 @@ workflows:
- falco - falco
- test-infra - test-infra
requires: requires:
- "build/musl"
- "rpm/sign" - "rpm/sign"
filters: filters:
tags: tags:

5
.gitignore vendored
View File

@@ -10,11 +10,8 @@ test/.phoronix-test-suite
test/results*.json.* test/results*.json.*
test/build test/build
userspace/engine/lua/lyaml
userspace/engine/lua/lyaml.lua
.vscode/* .vscode/*
.luacheckcache .luacheckcache
*.idea* *.idea*

View File

@@ -10,5 +10,4 @@ endif()
if(CPACK_GENERATOR MATCHES "TGZ") if(CPACK_GENERATOR MATCHES "TGZ")
set(CPACK_SET_DESTDIR "ON") set(CPACK_SET_DESTDIR "ON")
set(CPACK_STRIP_FILES "OFF")
endif() endif()

View File

@@ -24,8 +24,8 @@ else()
# default below In case you want to test against another falcosecurity/libs version just pass the variable - ie., `cmake # default below In case you want to test against another falcosecurity/libs version just pass the variable - ie., `cmake
# -DFALCOSECURITY_LIBS_VERSION=dev ..` # -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION) if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "bb9bee8e522fc953c2a79093d688d3d82b925e8b") set(FALCOSECURITY_LIBS_VERSION "4de7ad2857fb55439eb10455aacd1d262b70551b")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=ab2f18ff9c8d92dd06088ccfa73d4230fce3617613229f5afd839a37c13b0459") set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=3769e410fc0e31d5c7c37f33a7a73dfe52418a850d8f166fbafc67a723c619b6")
endif() endif()
# cd /path/to/build && cmake /path/to/source # cd /path/to/build && cmake /path/to/source

View File

@@ -11,9 +11,10 @@
# specific language governing permissions and limitations under the License. # specific language governing permissions and limitations under the License.
# #
set(LYAML_SRC "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/ext/yaml") set(LYAML_ROOT "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml")
set(LYAML_LIB "${LYAML_SRC}/.libs/yaml.a") set(LYAML_LIB "${LYAML_ROOT}/ext/yaml/.libs/yaml.a")
message(STATUS "Using bundled lyaml in '${LYAML_SRC}'") set(LYAML_LUA_DIR "${LYAML_ROOT}/lib")
message(STATUS "Using bundled lyaml in '${LYAML_ROOT}'")
externalproject_add( externalproject_add(
lyaml lyaml
DEPENDS luajit libyaml DEPENDS luajit libyaml
@@ -22,7 +23,6 @@ externalproject_add(
BUILD_COMMAND ${CMD_MAKE} BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1 BUILD_IN_SOURCE 1
BUILD_BYPRODUCTS ${LYAML_LIB} BUILD_BYPRODUCTS ${LYAML_LIB}
INSTALL_COMMAND ""
CONFIGURE_COMMAND ./configure --enable-static CFLAGS=-I${LIBYAML_INSTALL_DIR}/include CPPFLAGS=-I${LIBYAML_INSTALL_DIR}/include LDFLAGS=-L${LIBYAML_INSTALL_DIR}/lib LIBS=-lyaml LUA=${LUAJIT_SRC}/luajit LUA_INCLUDE=-I${LUAJIT_INCLUDE} CONFIGURE_COMMAND ./configure --enable-static CFLAGS=-I${LIBYAML_INSTALL_DIR}/include CPPFLAGS=-I${LIBYAML_INSTALL_DIR}/include LDFLAGS=-L${LIBYAML_INSTALL_DIR}/lib LIBS=-lyaml LUA=${LUAJIT_SRC}/luajit LUA_INCLUDE=-I${LUAJIT_INCLUDE}
INSTALL_COMMAND sh -c
"cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua"
) )

View File

@@ -13,12 +13,10 @@
include(ExternalProject) include(ExternalProject)
set(PLUGINS_VERSION "0.1.0-rc1-28-g019437e")
ExternalProject_Add( ExternalProject_Add(
cloudtrail-plugin cloudtrail-plugin
URL "https://download.falco.org/plugins/dev/cloudtrail-${PLUGINS_VERSION}-${CMAKE_HOST_SYSTEM_PROCESSOR}.tar.gz" URL "https://download.falco.org/plugins/stable/cloudtrail-0.2.0-${CMAKE_HOST_SYSTEM_PROCESSOR}.tar.gz"
URL_HASH "SHA256=ad9692957c5435238e07d1625e1b247eabe98b85f54de9218367fdd73a6f3f0b" URL_HASH "SHA256=917ebc5c3b1ad78d959372baa73ac2e9b18b38f51e1e42bd0974166dc04a964c"
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""
INSTALL_COMMAND "") INSTALL_COMMAND "")
@@ -27,8 +25,8 @@ install(FILES "${PROJECT_BINARY_DIR}/cloudtrail-plugin-prefix/src/cloudtrail-plu
ExternalProject_Add( ExternalProject_Add(
json-plugin json-plugin
URL "https://download.falco.org/plugins/dev/json-${PLUGINS_VERSION}-${CMAKE_HOST_SYSTEM_PROCESSOR}.tar.gz" URL "https://download.falco.org/plugins/stable/json-0.2.0-${CMAKE_HOST_SYSTEM_PROCESSOR}.tar.gz"
URL_HASH "SHA256=721ea5226b0f623915d0d5c34870589ad33a8ff795b0daa1af72f21a67430077" URL_HASH "SHA256=250f0b04db7ab08f3bfa5ecd90cc9b39a6992fc2e96b887ed6f319a6ba156fd7"
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""
INSTALL_COMMAND "") INSTALL_COMMAND "")

View File

@@ -20,7 +20,7 @@ RUN curl -L -o falco.tar.gz \
RUN sed -e 's/time_format_iso_8601: false/time_format_iso_8601: true/' < /falco/etc/falco/falco.yaml > /falco/etc/falco/falco.yaml.new \ RUN sed -e 's/time_format_iso_8601: false/time_format_iso_8601: true/' < /falco/etc/falco/falco.yaml > /falco/etc/falco/falco.yaml.new \
&& mv /falco/etc/falco/falco.yaml.new /falco/etc/falco/falco.yaml && mv /falco/etc/falco/falco.yaml.new /falco/etc/falco/falco.yaml
FROM scratch FROM debian:11-slim
LABEL maintainer="cncf-falco-dev@lists.cncf.io" LABEL maintainer="cncf-falco-dev@lists.cncf.io"

View File

@@ -82,7 +82,7 @@ trace_files: !mux
incompat_plugin_rules_version: incompat_plugin_rules_version:
exit_status: 1 exit_status: 1
stderr_contains: "Runtime error: Plugin cloudtrail version 0.1.0 not compatible with required plugin version 100000.0.0. Exiting." stderr_contains: "Runtime error: Plugin cloudtrail version .* not compatible with required plugin version 100000.0.0. Exiting."
conf_file: BUILD_DIR/test/confs/plugins/cloudtrail_json_create_instances.yaml conf_file: BUILD_DIR/test/confs/plugins/cloudtrail_json_create_instances.yaml
rules_file: rules_file:
- rules/plugins/cloudtrail_incompat_plugin_version.yaml - rules/plugins/cloudtrail_incompat_plugin_version.yaml

View File

@@ -10,6 +10,8 @@
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the # "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. # specific language governing permissions and limitations under the License.
add_subdirectory(lua)
set(FALCO_ENGINE_SOURCE_FILES set(FALCO_ENGINE_SOURCE_FILES
rules.cpp rules.cpp
falco_common.cpp falco_common.cpp
@@ -36,7 +38,8 @@ if(MINIMAL_BUILD)
"${STRING_VIEW_LITE_INCLUDE}" "${STRING_VIEW_LITE_INCLUDE}"
"${LIBSCAP_INCLUDE_DIRS}" "${LIBSCAP_INCLUDE_DIRS}"
"${LIBSINSP_INCLUDE_DIRS}" "${LIBSINSP_INCLUDE_DIRS}"
"${PROJECT_BINARY_DIR}/userspace/engine") "${PROJECT_BINARY_DIR}/userspace/engine"
"${PROJECT_BINARY_DIR}/userspace/engine/lua")
else() else()
target_include_directories( target_include_directories(
falco_engine falco_engine
@@ -48,24 +51,11 @@ else()
"${STRING_VIEW_LITE_INCLUDE}" "${STRING_VIEW_LITE_INCLUDE}"
"${LIBSCAP_INCLUDE_DIRS}" "${LIBSCAP_INCLUDE_DIRS}"
"${LIBSINSP_INCLUDE_DIRS}" "${LIBSINSP_INCLUDE_DIRS}"
"${PROJECT_BINARY_DIR}/userspace/engine") "${PROJECT_BINARY_DIR}/userspace/engine"
"${PROJECT_BINARY_DIR}/userspace/engine/lua")
endif() endif()
target_link_libraries(falco_engine "${FALCO_SINSP_LIBRARY}" "${LPEG_LIB}" "${LYAML_LIB}" "${LIBYAML_LIB}") target_link_libraries(falco_engine "${FALCO_SINSP_LIBRARY}" "${LPEG_LIB}" "${LYAML_LIB}" "${LIBYAML_LIB}" luafiles)
configure_file(config_falco_engine.h.in config_falco_engine.h) configure_file(config_falco_engine.h.in config_falco_engine.h)
if(DEFINED FALCO_COMPONENT)
install(
DIRECTORY lua
DESTINATION "${FALCO_SHARE_DIR}"
COMPONENT "${FALCO_COMPONENT}"
FILES_MATCHING
PATTERN *.lua)
else()
install(
DIRECTORY lua
DESTINATION "${FALCO_SHARE_DIR}"
FILES_MATCHING
PATTERN *.lua)
endif()

View File

@@ -19,6 +19,7 @@ limitations under the License.
#include "config_falco_engine.h" #include "config_falco_engine.h"
#include "falco_common.h" #include "falco_common.h"
#include "banned.h" // This raises a compilation error when certain functions are used #include "banned.h" // This raises a compilation error when certain functions are used
#include "falco_engine_lua_files.hh"
std::vector<std::string> falco_common::priority_names = { std::vector<std::string> falco_common::priority_names = {
"Emergency", "Emergency",
@@ -48,68 +49,33 @@ falco_common::~falco_common()
} }
} }
void falco_common::init(const char *lua_main_filename, const char *alternate_lua_dir) void falco_common::init()
{ {
ifstream is; // Strings in the list lua_module_strings need to be loaded as
string lua_dir = FALCO_ENGINE_LUA_DIR; // lua modules, which also involves adding them to the
string lua_main_path = lua_dir + lua_main_filename; // package.module table.
for(const auto &pair : lua_module_strings)
is.open(lua_main_path);
if (!is.is_open())
{ {
lua_dir = alternate_lua_dir; lua_getglobal(m_ls, "package");
lua_main_path = lua_dir + lua_main_filename; lua_getfield(m_ls, -1, "preload");
is.open(lua_main_path); if(luaL_loadstring(m_ls, pair.first))
if (!is.is_open())
{ {
throw falco_exception("Could not find Falco Lua entrypoint (tried " + throw falco_exception("Failed to load embedded lua code " +
string(FALCO_ENGINE_LUA_DIR) + lua_main_filename + ", " + string(pair.second) + ": " + lua_tostring(m_ls, -1));
string(alternate_lua_dir) + lua_main_filename + ")"); }
lua_setfield(m_ls, -2, pair.second);
}
// Strings in the list lua_code_strings need to be loaded and
// evaluated so any public functions can be directly called.
for(const auto &str : lua_code_strings)
{
if(luaL_loadstring(m_ls, str) || lua_pcall(m_ls, 0, 0, 0))
{
throw falco_exception("Failed to load + evaluate embedded lua code " +
string(str) + ": " + lua_tostring(m_ls, -1));
} }
} }
// Initialize Lua interpreter
add_lua_path(lua_dir);
// Load the main program, which defines all the available functions.
string scriptstr((istreambuf_iterator<char>(is)),
istreambuf_iterator<char>());
if(luaL_loadstring(m_ls, scriptstr.c_str()) || lua_pcall(m_ls, 0, 0, 0))
{
throw falco_exception("Failed to load script " +
lua_main_path + ": " + lua_tostring(m_ls, -1));
}
}
void falco_common::add_lua_path(string &path)
{
string cpath = string(path);
path += "?.lua";
cpath += "?.so";
lua_getglobal(m_ls, "package");
lua_getfield(m_ls, -1, "path");
string cur_path = lua_tostring(m_ls, -1 );
cur_path += ';';
lua_pop(m_ls, 1);
cur_path.append(path.c_str());
lua_pushstring(m_ls, cur_path.c_str());
lua_setfield(m_ls, -2, "path");
lua_getfield(m_ls, -1, "cpath");
string cur_cpath = lua_tostring(m_ls, -1 );
cur_cpath += ';';
lua_pop(m_ls, 1);
cur_cpath.append(cpath.c_str());
lua_pushstring(m_ls, cur_cpath.c_str());
lua_setfield(m_ls, -2, "cpath");
lua_pop(m_ls, 1);
} }

View File

@@ -69,7 +69,7 @@ public:
falco_common(); falco_common();
virtual ~falco_common(); virtual ~falco_common();
void init(const char *lua_main_filename, const char *alternate_lua_dir); void init();
// Priority levels, as a vector of strings // Priority levels, as a vector of strings
static std::vector<std::string> priority_names; static std::vector<std::string> priority_names;
@@ -91,7 +91,4 @@ protected:
lua_State *m_ls; lua_State *m_ls;
std::mutex m_ls_semaphore; std::mutex m_ls_semaphore;
private:
void add_lua_path(std::string &path);
}; };

View File

@@ -53,7 +53,7 @@ falco_engine::falco_engine(bool seed_rng, const std::string& alternate_lua_dir)
luaopen_lpeg(m_ls); luaopen_lpeg(m_ls);
luaopen_yaml(m_ls); luaopen_yaml(m_ls);
falco_common::init(m_lua_main_filename.c_str(), alternate_lua_dir.c_str()); falco_common::init();
falco_rules::init(m_ls); falco_rules::init(m_ls);
m_required_plugin_versions.clear(); m_required_plugin_versions.clear();
@@ -136,6 +136,12 @@ void falco_engine::list_fields(std::string &source, bool verbose, bool names_onl
{ {
for(auto &field : fld_class.fields) for(auto &field : fld_class.fields)
{ {
// Skip fields with the EPF_TABLE_ONLY flag.
if(field.tags.find("EPF_TABLE_ONLY") != field.tags.end())
{
continue;
}
printf("%s\n", field.name.c_str()); printf("%s\n", field.name.c_str());
} }
} }

View File

@@ -265,7 +265,6 @@ private:
uint32_t m_sampling_ratio; uint32_t m_sampling_ratio;
double m_sampling_multiplier; double m_sampling_multiplier;
std::string m_lua_main_filename = "rule_loader.lua";
static const std::string s_default_ruleset; static const std::string s_default_ruleset;
uint32_t m_default_ruleset_id; uint32_t m_default_ruleset_id;

View File

@@ -22,4 +22,3 @@ limitations under the License.
// represents the fields supported by this version of Falco. It's used // represents the fields supported by this version of Falco. It's used
// at build time to detect a changed set of fields. // at build time to detect a changed set of fields.
#define FALCO_FIELDS_CHECKSUM "4de812495f8529ac20bda2b9774462b15911a51df293d59fe9ccb6b922fdeb9d" #define FALCO_FIELDS_CHECKSUM "4de812495f8529ac20bda2b9774462b15911a51df293d59fe9ccb6b922fdeb9d"

View File

@@ -1529,12 +1529,9 @@ void json_event_formatter::set_format(output_format of, const std::string &forma
bool json_event_formatter::tostring_withformat(gen_event *gevt, std::string &output, gen_event_formatter::output_format of) bool json_event_formatter::tostring_withformat(gen_event *gevt, std::string &output, gen_event_formatter::output_format of)
{ {
json_event *ev = static_cast<json_event *>(gevt); json_event *ev = static_cast<json_event *>(gevt);
std::string ret;
if(of == OF_JSON) if(of == OF_JSON)
{ {
ret = tojson(ev); output = tojson(ev);
return true; return true;
} }
else else

View File

@@ -0,0 +1,21 @@
#
# Copyright (C) 2021 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.
file(GLOB_RECURSE lua_module_files ${CMAKE_CURRENT_SOURCE_DIR} *.lua)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/falco_engine_lua_files.cpp
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/lua-to-cpp.sh ${CMAKE_CURRENT_SOURCE_DIR} ${LYAML_LUA_DIR} ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${lua_files} ${CMAKE_CURRENT_SOURCE_DIR}/lua-to-cpp.sh lyaml)
add_library(luafiles falco_engine_lua_files.cpp)
target_include_directories(luafiles PUBLIC ${CMAKE_CURRENT_BINARY_DIR})

View File

@@ -0,0 +1,84 @@
#!/bin/bash
set -euo pipefail
LUA_FILE_DIR=$1
LYAML_LUA_DIR=$2
OUTPUT_DIR=$3
MODULE_SYMS=()
CODE_SYMS=()
function add_lua_file {
filename=$1
is_module=$2
# Take the basename of the file
BASE_NAME=$(basename ${file} .lua)
SYMBOL_NAME="${BASE_NAME}_lua_file_contents"
FILE_CONTENTS=$(<${file})
# Add a symbol to the .cc file containing the contents of the file
echo "const char *${SYMBOL_NAME}=R\"LUAFILE(${FILE_CONTENTS})LUAFILE\";" >> ${OUTPUT_DIR}/falco_engine_lua_files.cpp
# Add an extern reference to the .hh file
echo "extern const char *${SYMBOL_NAME};" >> ${OUTPUT_DIR}/falco_engine_lua_files.hh
if [[ "${is_module}" == "true" ]]; then
# Determine the module name for the file
if [[ "${file}" == *"/"* ]]; then
MODULE_NAME=$(echo ${file} | tr / . | sed -e 's/.lua//')
else
MODULE_NAME=$(basename ${file} .lua)
fi
# Add the pair (string contents, module name) to MODULE_SYMS
PAIR=$(echo "{${SYMBOL_NAME},\"${MODULE_NAME}\"}")
MODULE_SYMS+=(${PAIR})
else
# Add the string to CODE_SYMS
CODE_SYMS+=(${SYMBOL_NAME})
fi
}
cat <<EOF > ${OUTPUT_DIR}/falco_engine_lua_files.cpp
// Automatically generated. Do not edit
#include "falco_engine_lua_files.hh"
EOF
cat <<EOF > ${OUTPUT_DIR}/falco_engine_lua_files.hh
#pragma once
// Automatically generated. Do not edit
#include <list>
#include <utility>
EOF
# lyaml and any files in the "modules" subdirectory are treated as lua
# modules.
pushd ${LYAML_LUA_DIR}
for file in *.lua */*.lua; do
add_lua_file $file "true"
done
popd
pushd ${LUA_FILE_DIR}/modules
for file in *.lua; do
add_lua_file $file "true"
done
popd
# Any .lua files in this directory are treated as code with functions
# to execute.
pushd ${LUA_FILE_DIR}
for file in ${LUA_FILE_DIR}/*.lua; do
add_lua_file $file "false"
done
popd
# Create a list of lua module (string, module name) pairs from MODULE_SYMS
echo "extern std::list<std::pair<const char *,const char *>> lua_module_strings;" >> ${OUTPUT_DIR}/falco_engine_lua_files.hh
echo "std::list<std::pair<const char *,const char *>> lua_module_strings = {$(IFS=, ; echo "${MODULE_SYMS[*]}")};" >> ${OUTPUT_DIR}/falco_engine_lua_files.cpp
# Create a list of lua code strings from CODE_SYMS
echo "extern std::list<const char *> lua_code_strings;" >> ${OUTPUT_DIR}/falco_engine_lua_files.hh
echo "std::list<const char *> lua_code_strings = {$(IFS=, ; echo "${CODE_SYMS[*]}")};" >> ${OUTPUT_DIR}/falco_engine_lua_files.cpp

View File

@@ -293,19 +293,20 @@ function split_lines(rules_content)
end end
function get_orig_yaml_obj(rules_lines, row) function get_orig_yaml_obj(rules_lines, row)
local ret = "" idx = row
local t = {}
while (idx <= #rules_lines) do
t[#t + 1] = rules_lines[idx]
idx = idx + 1
idx = row if idx > #rules_lines or rules_lines[idx] == "" or string.sub(rules_lines[idx], 1, 1) == '-' then
while (idx <= #rules_lines) do break
ret = ret..rules_lines[idx].."\n" end
idx = idx + 1 end
t[#t + 1] = ""
if idx > #rules_lines or rules_lines[idx] == "" or string.sub(rules_lines[idx], 1, 1) == '-' then local ret = ""
break ret = table.concat(t, "\n")
end return ret
end
return ret
end end
function get_lines(rules_lines, row, num_lines) function get_lines(rules_lines, row, num_lines)
@@ -754,65 +755,69 @@ end
-- Populates exfields with all fields used -- Populates exfields with all fields used
function build_exception_condition_string_multi_fields(eitem, exfields) function build_exception_condition_string_multi_fields(eitem, exfields)
local fields = eitem['fields'] local fields = eitem['fields']
local comps = eitem['comps'] local comps = eitem['comps']
local icond = "(" local icond = {}
for i, values in ipairs(eitem['values']) do icond[#icond + 1] = "("
if #fields ~= #values then local lcount = 0
return nil, "Exception item "..eitem['name']..": fields and values lists must have equal length" for i, values in ipairs(eitem['values']) do
end if #fields ~= #values then
return nil, "Exception item " .. eitem['name'] .. ": fields and values lists must have equal length"
end
if icond ~= "(" then if lcount ~= 0 then
icond=icond.." or " icond[#icond + 1] = " or "
end end
lcount = lcount + 1
icond=icond.."(" icond[#icond + 1] = "("
for k=1,#fields do for k = 1, #fields do
if k > 1 then if k > 1 then
icond=icond.." and " icond[#icond + 1] = " and "
end end
local ival = values[k] local ival = values[k]
local istr = "" local istr = ""
-- If ival is a table, express it as (titem1, titem2, etc) -- If ival is a table, express it as (titem1, titem2, etc)
if type(ival) == "table" then if type(ival) == "table" then
istr = "(" istr = "("
for _, item in ipairs(ival) do for _, item in ipairs(ival) do
if istr ~= "(" then if istr ~= "(" then
istr = istr..", " istr = istr .. ", "
end end
istr = istr..quote_item(item) istr = istr .. quote_item(item)
end end
istr = istr..")" istr = istr .. ")"
else else
-- If the corresponding operator is one that works on lists, possibly add surrounding parentheses. -- If the corresponding operator is one that works on lists, possibly add surrounding parentheses.
if defined_list_comp_operators[comps[k]] then if defined_list_comp_operators[comps[k]] then
istr = paren_item(ival) istr = paren_item(ival)
else else
-- Quote the value if not already quoted -- Quote the value if not already quoted
istr = quote_item(ival) istr = quote_item(ival)
end end
end end
icond = icond..fields[k].." "..comps[k].." "..istr icond[#icond + 1] = fields[k] .. " " .. comps[k] .. " " .. istr
exfields[fields[k]] = true exfields[fields[k]] = true
end end
icond=icond..")" icond[#icond + 1] = ")"
end end
icond = icond..")" icond[#icond + 1] = ")"
-- Don't return a trivially empty condition string -- Don't return a trivially empty condition string
if icond == "()" then local ret = table.concat(icond)
icond = "" if ret == "()" then
end return "", nil
end
return icond, nil return ret, nil
end end

View File

@@ -168,6 +168,10 @@ private:
int nodeIdx = std::stoi(key.substr(i + 1, close_param_idx - i - 1)); int nodeIdx = std::stoi(key.substr(i + 1, close_param_idx - i - 1));
ret.reset(ret[nodeIdx]); ret.reset(ret[nodeIdx]);
i = close_param_idx; i = close_param_idx;
if (i < key.size() - 1 && key[i + 1] == '.')
{
i++;
}
} }
} }
} }
@@ -276,49 +280,61 @@ private:
}; };
namespace YAML { namespace YAML {
template<>
struct convert<nlohmann::json> {
static bool decode(const Node& node, nlohmann::json& res)
{
int int_val;
double double_val;
bool bool_val;
std::string str_val;
nlohmann::json sub{};
switch (node.Type()) {
case YAML::NodeType::Map:
for (auto &&it: node)
{
YAML::convert<nlohmann::json>::decode(it.second, sub);
res[it.first.as<std::string>()] = sub;
}
break;
case YAML::NodeType::Sequence:
for (auto &&it : node)
{
YAML::convert<nlohmann::json>::decode(it, sub);
res.emplace_back(sub);
}
break;
case YAML::NodeType::Scalar:
if (YAML::convert<int>::decode(node, int_val))
{
res = int_val;
}
else if (YAML::convert<double>::decode(node, double_val))
{
res = double_val;
}
else if (YAML::convert<bool>::decode(node, bool_val))
{
res = bool_val;
}
else if (YAML::convert<std::string>::decode(node, str_val))
{
res = str_val;
}
default:
break;
}
return true;
}
};
template<> template<>
struct convert<falco_configuration::plugin_config> { struct convert<falco_configuration::plugin_config> {
static bool read_file_from_key(const Node &node, const std::string &prefix, std::string &value) // Note that this loses the distinction between init configs
{ // defined as YAML maps or as opaque strings.
std::string key = prefix;
if(node[key])
{
value = node[key].as<std::string>();
return true;
}
key += "_file";
if(node[key])
{
std::string path = node[key].as<std::string>();
// prepend share dir if path is not absolute
if(path.at(0) != '/')
{
path = string(FALCO_ENGINE_PLUGINS_DIR) + path;
}
// Intentionally letting potential
// exception be thrown, will get
// caught when reading config.
std::ifstream f(path);
std::string str((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>());
value = str;
return true;
}
return false;
}
// Note that the distinction between
// init_config/init_config_file and
// open_params/open_params_file is lost. But also,
// this class doesn't write yaml config anyway.
static Node encode(const falco_configuration::plugin_config & rhs) { static Node encode(const falco_configuration::plugin_config & rhs) {
Node node; Node node;
node["name"] = rhs.m_name; node["name"] = rhs.m_name;
@@ -338,36 +354,44 @@ namespace YAML {
{ {
return false; return false;
} }
else rhs.m_name = node["name"].as<std::string>();
{
rhs.m_name = node["name"].as<std::string>();
}
if(!node["library_path"]) if(!node["library_path"])
{ {
return false; return false;
} }
rhs.m_library_path = node["library_path"].as<std::string>();
if(rhs.m_library_path.at(0) != '/')
{
// prepend share dir if path is not absolute
rhs.m_library_path = string(FALCO_ENGINE_PLUGINS_DIR) + rhs.m_library_path;
}
if(!node["init_config"])
{
return false;
}
// By convention, if the init config is a YAML map we convert it
// in a JSON object string. This is useful for plugins implementing
// the `get_init_schema` API symbol, which right now support the
// JSON Schema specific. If we ever support other schema/data types,
// we may want to bundle the conversion logic in an ad-hoc class.
// The benefit of this is being able of parsing/editing the config as
// a YAML map instead of having an opaque string.
if (node["init_config"].IsMap())
{
nlohmann::json json;
YAML::convert<nlohmann::json>::decode(node["init_config"], json);
rhs.m_init_config = json.dump();
}
else else
{ {
rhs.m_library_path = node["library_path"].as<std::string>(); rhs.m_init_config = node["init_config"].as<std::string>();
// prepend share dir if path is not absolute
if(rhs.m_library_path.at(0) != '/')
{
rhs.m_library_path = string(FALCO_ENGINE_PLUGINS_DIR) + rhs.m_library_path;
}
} }
if(!read_file_from_key(node, string("init_config"), rhs.m_init_config)) if(node["open_params"])
{ {
return false; rhs.m_open_params = node["open_params"].as<std::string>();
}
if(node["open_params"] &&
!read_file_from_key(node, string("open_params"), rhs.m_open_params))
{
return false;
} }
return true; return true;