From 344b8c002c3fc2f77c47eb3cfbb4073de9eb0f30 Mon Sep 17 00:00:00 2001 From: Lorenzo Fontana Date: Thu, 19 Nov 2020 16:00:26 +0100 Subject: [PATCH] new(userspace): initial lifecycle implementation Signed-off-by: Lorenzo Fontana --- CMakeLists.txt | 1 + userspace/falco/CMakeLists.txt | 14 +----- userspace/falco/falco.cpp | 19 ++++---- userspace/libhawk/CMakeLists.txt | 39 +++++++++++++++ userspace/libhawk/exception.h | 23 +++++++++ userspace/libhawk/hawk.h | 31 ++++++++++-- userspace/libhawk/lifecycle.cpp | 83 ++++++++++++++++++++++++++++++++ userspace/libhawk/lifecycle.h | 40 +++++++++++++++ 8 files changed, 225 insertions(+), 25 deletions(-) create mode 100644 userspace/libhawk/CMakeLists.txt create mode 100644 userspace/libhawk/exception.h create mode 100644 userspace/libhawk/lifecycle.cpp create mode 100644 userspace/libhawk/lifecycle.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8efa759f..79f58783 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,6 +226,7 @@ set(FALCO_ABSOLUTE_SHARE_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}") set(FALCO_BIN_DIR bin) add_subdirectory(scripts) +add_subdirectory(userspace/libhawk) add_subdirectory(userspace/engine) add_subdirectory(userspace/falco) add_subdirectory(tests) diff --git a/userspace/falco/CMakeLists.txt b/userspace/falco/CMakeLists.txt index 5a4d6a89..aa736ec5 100644 --- a/userspace/falco/CMakeLists.txt +++ b/userspace/falco/CMakeLists.txt @@ -30,6 +30,7 @@ set( set( FALCO_INCLUDE_DIRECTORIES + "${LIBHAWK_INCLUDE_DIRECTORY}" "${PROJECT_SOURCE_DIR}/userspace/engine" "${PROJECT_BINARY_DIR}/userspace/falco" "${PROJECT_BINARY_DIR}/driver/src" @@ -52,6 +53,7 @@ set( set( FALCO_LIBRARIES falco_engine + libhawk sinsp "${LIBYAML_LIB}" "${YAMLCPP_LIB}" @@ -112,18 +114,6 @@ add_executable( ${FALCO_SOURCES} ) -if(DEFINED LIBHAWK_LIBRARIES) - message(STATUS "Using externally provided libhawk implementations: ${LIBHAWK_LIBRARIES}") - list( - APPEND FALCO_LIBRARIES - "${LIBHAWK_LIBRARIES}" - ) - list( - APPEND FALCO_INCLUDE_DIRECTORIES - "${PROJECT_SOURCE_DIR}/userspace/libhawk" - ) -endif() - add_dependencies(falco ${FALCO_DEPENDENCIES}) target_link_libraries( diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index e03886ff..a6958d57 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -36,9 +36,9 @@ limitations under the License. #include "logger.h" #include "utils.h" -#include "chisel.h" #include "fields_info.h" +#include "lifecycle.h" #include "event_drops.h" #include "configuration.h" #include "falco_engine.h" @@ -48,10 +48,6 @@ limitations under the License. #include "webserver.h" #include "grpc_server.h" #endif -extern "C" -{ -#include "hawk.h" -} #include "banned.h" // This raises a compilation error when certain functions are used typedef function open_t; @@ -463,6 +459,7 @@ int falco_init(int argc, char **argv) falco_engine *engine_blueprint; std::thread watchrules_thread; falco_outputs *outputs = NULL; + libhawk::lifecycle *hawk_lifecycle = NULL; syscall_evt_drop_mgr sdropmgr; int op; int long_index = 0; @@ -810,6 +807,8 @@ int falco_init(int argc, char **argv) throw std::invalid_argument("If -d is provided, a pid file must also be provided"); } + hawk_lifecycle = new libhawk::lifecycle(); + ifstream conf_stream; if (conf_filename.size()) { @@ -948,10 +947,11 @@ int falco_init(int argc, char **argv) // engine->enable_rule_by_tag(enabled_rule_tags, true); } - hawk_init(); watchrules_thread = std::thread([&] { - // todo: pass verbose, and all_events - hawk_watch_rules((hawk_watch_rules_cb)rules_cb, reinterpret_cast(&engine_blueprint)); + hawk_lifecycle->watch_rules( + (hawk_watch_rules_cb)rules_cb, + reinterpret_cast(&engine_blueprint), + "hawk_example_c"); }); falco_logger::log(LOG_INFO, "DOPO\n"); @@ -1455,7 +1455,6 @@ int falco_init(int argc, char **argv) sdropmgr.print_stats(); if(watchrules_thread.joinable()) { - hawk_destroy(); watchrules_thread.join(); } #ifndef MINIMAL_BUILD @@ -1472,7 +1471,6 @@ int falco_init(int argc, char **argv) display_fatal_err("Runtime error: " + string(e.what()) + ". Exiting.\n"); if(watchrules_thread.joinable()) { - hawk_destroy(); watchrules_thread.join(); } result = EXIT_FAILURE; @@ -1492,6 +1490,7 @@ exit: delete inspector; delete engine_blueprint; delete outputs; + delete hawk_lifecycle; return result; } diff --git a/userspace/libhawk/CMakeLists.txt b/userspace/libhawk/CMakeLists.txt new file mode 100644 index 00000000..b870f00d --- /dev/null +++ b/userspace/libhawk/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# Copyright (C) 2020 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(CheckSymbolExists) + +set( + LIBHAWK_SOURCES + lifecycle.cpp +) + +set( + LIBHAWK_PUBLIC_INCLUDES + hawk.h +) + +set(LIBHAWK_INCLUDE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) + +add_library(libhawk STATIC ${LIBHAWK_SOURCES}) + +if(DEFINED LIBHAWK_LIBRARIES) + message(STATUS "Using externally provided libhawk plugins: ${LIBHAWK_LIBRARIES}") + target_link_libraries(libhawk ${LIBHAWK_LIBRARIES}) +endif() + +#todo: we want to provide a default version of the libhawk plugin functions +# we need to manage the situation where the user only provides parts of it and not others +install( + FILES ${LIBHAWK_PUBLIC_INCLUDES} + DESTINATION "${FALCO_SHARE_DIR}" +) diff --git a/userspace/libhawk/exception.h b/userspace/libhawk/exception.h new file mode 100644 index 00000000..9253a4f2 --- /dev/null +++ b/userspace/libhawk/exception.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include +#include + +namespace libhawk +{ +class hawk_exception : public std::runtime_error +{ +public: + hawk_exception(const std::string& message): + std::runtime_error(message) {} +}; + +class hawk_plugin_exception: public hawk_exception +{ +public: + hawk_plugin_exception(const std::string& plugin_name, const std::string& message): + hawk_exception("plugin: " + plugin_name + ", error: " + message) {} +}; +} // namespace libhawk diff --git a/userspace/libhawk/hawk.h b/userspace/libhawk/hawk.h index 87cacc77..4fe6314c 100644 --- a/userspace/libhawk/hawk.h +++ b/userspace/libhawk/hawk.h @@ -1,10 +1,35 @@ #ifndef HAWK_H #define HAWK_H -extern void hawk_init(); -extern void hawk_destroy(); + +#define HAWK_VERSION_CODE 0x000001 +#define HAWK_VERSION_BITS(x, y, z) ((x) << 16 | (y) << 8 | (z)) +#define HAWK_AT_LEAST_VERSION(x, y, z) \ + (HAWK_VERSION_CODE >= HAWK_VERSION_BITS(x, y, z)) typedef void* hawk_engine; typedef void (*hawk_watch_rules_cb)(char* rules_content, hawk_engine* engine); -extern void hawk_watch_rules(hawk_watch_rules_cb cb, hawk_engine* engine); + +typedef struct +{ + void (*hawk_init)(void); + void (*hawk_destroy)(void); + void (*hawk_watch_rules)(hawk_watch_rules_cb, hawk_engine*); +} hawk_plugin_definition; + +typedef void(register_plugin_cb)(const char *, hawk_plugin_definition); + +typedef struct +{ + register_plugin_cb* register_plugin; +} hawk_plugin_registry; + +extern hawk_plugin_registry plugin_registry; + +#define HAWK_REGISTER_PLUGIN(name, definition) \ + void name##_hawk_plugin_init(void) __attribute__((constructor)); \ + void name##_hawk_plugin_init(void) \ + { \ + plugin_registry.register_plugin(#name, definition); \ + } #endif //HAWK_H diff --git a/userspace/libhawk/lifecycle.cpp b/userspace/libhawk/lifecycle.cpp new file mode 100644 index 00000000..11c557d6 --- /dev/null +++ b/userspace/libhawk/lifecycle.cpp @@ -0,0 +1,83 @@ +/* +Copyright (C) 2020 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 "lifecycle.h" +#include "exception.h" + +#include + +std::map *libhawk::g_plugins; + +void libhawk_register_plugin(const char *name, hawk_plugin_definition def) +{ + if(libhawk::g_plugins == nullptr) + { + libhawk::g_plugins = new std::map(); + } + + auto name_str = std::string(name); + auto plugin = libhawk::g_plugins->find(name_str); + if(plugin != libhawk::g_plugins->end()) + { + throw libhawk::hawk_exception("cannot register an already registered plugin: " + name_str); + } + libhawk::g_plugins->insert(std::make_pair(name_str, def)); +}; + +hawk_plugin_registry plugin_registry = { + .register_plugin = &libhawk_register_plugin, +}; + +libhawk::lifecycle::lifecycle() +{ + if(g_plugins == nullptr) + { + throw hawk_exception("no libhawk plugins registered"); + } + + for(auto plugin : *g_plugins) + { + if(plugin.second.hawk_init != nullptr) + { + plugin.second.hawk_init(); + } + } +} + +libhawk::lifecycle::~lifecycle() +{ + for(auto plugin : *g_plugins) + { + if(plugin.second.hawk_destroy != nullptr) + { + plugin.second.hawk_destroy(); + } + } +} + +void libhawk::lifecycle::watch_rules(hawk_watch_rules_cb cb, hawk_engine *engine, const std::string &plugin_name) +{ + auto plugin = g_plugins->find(plugin_name); + if(plugin == g_plugins->end()) + { + throw hawk_plugin_exception(plugin_name, "cannot watch_rules on a non existing plugin"); + } + if(plugin->second.hawk_watch_rules == nullptr) + { + throw hawk_plugin_exception(plugin_name, "plugin does not implement hawk_watch_rules"); + } + plugin->second.hawk_watch_rules(cb, engine); +} diff --git a/userspace/libhawk/lifecycle.h b/userspace/libhawk/lifecycle.h new file mode 100644 index 00000000..89f26d0e --- /dev/null +++ b/userspace/libhawk/lifecycle.h @@ -0,0 +1,40 @@ +/* +Copyright (C) 2020 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 + +#include +#include +#include + +extern "C" +{ +#include "hawk.h" +} + +namespace libhawk +{ +extern std::map* g_plugins; + +class lifecycle +{ +public: + lifecycle(); + virtual ~lifecycle(); + + void watch_rules(hawk_watch_rules_cb cb, hawk_engine* engine, const std::string& plugin_name); +}; +} // namespace libhawk