From 421c5c58f11155a134f67d8291abc696fffabfc9 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Mon, 30 Sep 2024 10:44:31 +0200 Subject: [PATCH 1/4] update: ignore_some_files Signed-off-by: Andrea Terzolo --- .clang-format-ignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.clang-format-ignore b/.clang-format-ignore index df0ba12c4ec..ce101ee3e9d 100644 --- a/.clang-format-ignore +++ b/.clang-format-ignore @@ -1 +1,3 @@ -# Add here new files to ignore +# These files contain some JSON schema definitions that are not C++ code +userspace/falco/config_json_schema.h +userspace/engine/rule_json_schema.h From e9d287d82dbde80c29eefb5b0e24c608717d2e90 Mon Sep 17 00:00:00 2001 From: Poiana Date: Mon, 30 Sep 2024 10:53:51 +0200 Subject: [PATCH 2/4] chore(falco): apply code formatting Signed-off-by: Poiana --- CMakeLists.txt | 208 ++-- cmake/cpack/CMakeCPackOptions.cmake | 53 +- cmake/modules/CPackConfig.cmake | 62 +- cmake/modules/CompilerFlags.cmake | 49 +- cmake/modules/Coverage.cmake | 27 +- cmake/modules/copy_files_to_build_dir.cmake | 32 +- cmake/modules/cpp-httplib.cmake | 26 +- cmake/modules/cxxopts.cmake | 40 +- cmake/modules/driver-repo/CMakeLists.txt | 27 +- cmake/modules/driver.cmake | 76 +- cmake/modules/falco-version.cmake | 45 +- cmake/modules/falcoctl.cmake | 70 +- .../falcosecurity-libs-repo/CMakeLists.txt | 25 +- cmake/modules/falcosecurity-libs.cmake | 165 ++-- cmake/modules/njson.cmake | 26 +- cmake/modules/rules.cmake | 106 ++- cmake/modules/static-analysis.cmake | 70 +- cmake/modules/yaml-cpp.cmake | 26 +- scripts/CMakeLists.txt | 80 +- unit_tests/CMakeLists.txt | 109 +-- unit_tests/engine/test_add_source.cpp | 28 +- unit_tests/engine/test_alt_rule_loader.cpp | 149 ++- unit_tests/engine/test_enable_rule.cpp | 21 +- unit_tests/engine/test_extra_output.cpp | 43 +- unit_tests/engine/test_falco_utils.cpp | 27 +- .../engine/test_filter_details_resolver.cpp | 58 +- .../engine/test_filter_macro_resolver.cpp | 117 ++- .../engine/test_filter_warning_resolver.cpp | 6 +- .../engine/test_plugin_requirements.cpp | 46 +- unit_tests/engine/test_rule_loader.cpp | 484 +++++----- unit_tests/engine/test_rulesets.cpp | 23 +- .../falco/app/actions/app_action_helpers.h | 16 +- .../test_configure_interesting_sets.cpp | 329 ++++--- .../test_configure_syscall_buffer_num.cpp | 6 +- .../falco/app/actions/test_load_config.cpp | 6 +- .../app/actions/test_select_event_sources.cpp | 143 ++- .../falco/test_atomic_signal_handler.cpp | 53 +- unit_tests/falco/test_configuration.cpp | 214 ++--- .../falco/test_configuration_config_files.cpp | 277 +++--- .../falco/test_configuration_env_vars.cpp | 171 ++-- .../test_configuration_output_options.cpp | 50 +- .../test_configuration_rule_selection.cpp | 44 +- .../falco/test_configuration_schema.cpp | 58 +- unit_tests/test_falco_engine.cpp | 56 +- unit_tests/test_falco_engine.h | 6 +- userspace/engine/CMakeLists.txt | 61 +- userspace/engine/evttype_index_ruleset.cpp | 69 +- userspace/engine/evttype_index_ruleset.h | 38 +- userspace/engine/falco_common.cpp | 68 +- userspace/engine/falco_common.h | 57 +- userspace/engine/falco_engine.cpp | 711 ++++++-------- userspace/engine/falco_engine.h | 212 +++-- userspace/engine/falco_engine_version.h | 12 +- userspace/engine/falco_load_result.cpp | 179 ++-- userspace/engine/falco_load_result.h | 6 +- userspace/engine/falco_rule.h | 37 +- userspace/engine/falco_source.h | 37 +- userspace/engine/falco_utils.cpp | 172 ++-- userspace/engine/falco_utils.h | 12 +- userspace/engine/filter_details_resolver.cpp | 83 +- userspace/engine/filter_details_resolver.h | 34 +- userspace/engine/filter_macro_resolver.cpp | 80 +- userspace/engine/filter_macro_resolver.h | 211 ++--- userspace/engine/filter_ruleset.cpp | 6 +- userspace/engine/filter_ruleset.h | 270 +++--- userspace/engine/filter_warning_resolver.cpp | 47 +- userspace/engine/filter_warning_resolver.h | 43 +- userspace/engine/formats.cpp | 113 +-- userspace/engine/formats.h | 35 +- userspace/engine/indexable_ruleset.h | 281 ++---- userspace/engine/indexed_vector.h | 98 +- userspace/engine/logger.cpp | 148 +-- userspace/engine/logger.h | 24 +- userspace/engine/rule_loader.cpp | 428 ++++----- userspace/engine/rule_loader.h | 892 +++++++++--------- userspace/engine/rule_loader_collector.cpp | 285 +++--- userspace/engine/rule_loader_collector.h | 47 +- userspace/engine/rule_loader_compile_output.h | 29 +- userspace/engine/rule_loader_compiler.cpp | 544 +++++------ userspace/engine/rule_loader_compiler.h | 91 +- userspace/engine/rule_loader_reader.cpp | 734 +++++++------- userspace/engine/rule_loader_reader.h | 66 +- userspace/engine/rule_loading_messages.h | 24 +- userspace/engine/stats_manager.cpp | 49 +- userspace/engine/stats_manager.h | 45 +- userspace/engine/yaml_helper.h | 433 ++++----- userspace/falco/CMakeLists.txt | 325 +++---- userspace/falco/app/actions/actions.h | 6 +- .../falco/app/actions/close_inspectors.cpp | 12 +- .../actions/configure_interesting_sets.cpp | 207 ++-- .../actions/configure_syscall_buffer_num.cpp | 20 +- .../actions/configure_syscall_buffer_size.cpp | 60 +- .../app/actions/create_requested_paths.cpp | 61 +- .../app/actions/create_signal_handlers.cpp | 171 ++-- userspace/falco/app/actions/helpers.h | 41 +- .../falco/app/actions/helpers_generic.cpp | 90 +- .../falco/app/actions/helpers_inspector.cpp | 129 +-- .../falco/app/actions/init_falco_engine.cpp | 106 ++- .../falco/app/actions/init_inspectors.cpp | 181 ++-- userspace/falco/app/actions/init_outputs.cpp | 53 +- userspace/falco/app/actions/list_fields.cpp | 14 +- userspace/falco/app/actions/list_plugins.cpp | 9 +- userspace/falco/app/actions/load_config.cpp | 67 +- userspace/falco/app/actions/load_plugins.cpp | 24 +- .../falco/app/actions/load_rules_files.cpp | 93 +- userspace/falco/app/actions/pidfile.cpp | 17 +- .../falco/app/actions/print_config_schema.cpp | 6 +- .../actions/print_generated_gvisor_config.cpp | 9 +- userspace/falco/app/actions/print_help.cpp | 6 +- .../app/actions/print_ignored_events.cpp | 9 +- .../app/actions/print_kernel_version.cpp | 14 +- .../falco/app/actions/print_page_size.cpp | 20 +- .../falco/app/actions/print_plugin_info.cpp | 63 +- .../falco/app/actions/print_rule_schema.cpp | 6 +- userspace/falco/app/actions/print_support.cpp | 60 +- .../app/actions/print_syscall_events.cpp | 108 +-- userspace/falco/app/actions/print_version.cpp | 13 +- .../falco/app/actions/process_events.cpp | 429 ++++----- .../app/actions/select_event_sources.cpp | 35 +- .../falco/app/actions/start_grpc_server.cpp | 55 +- .../falco/app/actions/start_webserver.cpp | 41 +- .../app/actions/validate_rules_files.cpp | 67 +- userspace/falco/app/app.cpp | 102 +- userspace/falco/app/app.h | 4 +- userspace/falco/app/options.cpp | 364 +++++-- userspace/falco/app/options.h | 14 +- userspace/falco/app/restart_handler.cpp | 312 +++--- userspace/falco/app/restart_handler.h | 76 +- userspace/falco/app/run_result.h | 109 +-- userspace/falco/app/signals.h | 4 +- userspace/falco/app/state.h | 276 +++--- userspace/falco/atomic_signal_handler.h | 187 ++-- userspace/falco/configuration.cpp | 640 ++++++------- userspace/falco/configuration.h | 374 ++++---- userspace/falco/event_drops.cpp | 223 +++-- userspace/falco/event_drops.h | 23 +- userspace/falco/falco.cpp | 25 +- userspace/falco/falco_metrics.cpp | 384 ++++---- userspace/falco/falco_metrics.h | 7 +- userspace/falco/falco_outputs.cpp | 244 +++-- userspace/falco/falco_outputs.h | 90 +- userspace/falco/falco_semaphore.h | 79 +- userspace/falco/grpc_context.cpp | 22 +- userspace/falco/grpc_context.h | 34 +- userspace/falco/grpc_queue.h | 30 +- userspace/falco/grpc_request_context.cpp | 105 +-- userspace/falco/grpc_request_context.h | 63 +- userspace/falco/grpc_server.cpp | 161 ++-- userspace/falco/grpc_server.h | 27 +- userspace/falco/outputs.h | 33 +- userspace/falco/outputs_file.cpp | 27 +- userspace/falco/outputs_file.h | 13 +- userspace/falco/outputs_grpc.cpp | 35 +- userspace/falco/outputs_grpc.h | 13 +- userspace/falco/outputs_http.cpp | 77 +- userspace/falco/outputs_http.h | 21 +- userspace/falco/outputs_program.cpp | 24 +- userspace/falco/outputs_program.h | 13 +- userspace/falco/outputs_stdout.cpp | 9 +- userspace/falco/outputs_stdout.h | 13 +- userspace/falco/outputs_syslog.cpp | 3 +- userspace/falco/outputs_syslog.h | 13 +- userspace/falco/stats_writer.cpp | 416 ++++---- userspace/falco/stats_writer.h | 83 +- userspace/falco/versions_info.cpp | 98 +- userspace/falco/versions_info.h | 60 +- userspace/falco/watchdog.h | 49 +- userspace/falco/webserver.cpp | 164 ++-- userspace/falco/webserver.h | 14 +- 169 files changed, 8745 insertions(+), 9603 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd1686ccaee..51f9e71ff51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,14 +2,15 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # cmake_minimum_required(VERSION 3.5.1) @@ -18,7 +19,11 @@ project(falco) option(USE_BUNDLED_DEPS "Bundle hard to find dependencies into the Falco binary" ON) option(USE_DYNAMIC_LIBELF "Dynamically link libelf" ON) option(BUILD_WARNINGS_AS_ERRORS "Enable building with -Wextra -Werror flags" OFF) -option(MINIMAL_BUILD "Build a minimal version of Falco, containing only the engine and basic input/output (EXPERIMENTAL)" OFF) +option( + MINIMAL_BUILD + "Build a minimal version of Falco, containing only the engine and basic input/output (EXPERIMENTAL)" + OFF +) option(MUSL_OPTIMIZED_BUILD "Enable if you want a musl optimized build" OFF) option(BUILD_FALCO_UNIT_TESTS "Build falco unit tests" OFF) option(USE_ASAN "Build with AddressSanitizer" OFF) @@ -26,54 +31,70 @@ option(USE_UBSAN "Build with UndefinedBehaviorSanitizer" OFF) option(UBSAN_HALT_ON_ERROR "Halt on error when building with UBSan" ON) if(WIN32) - if(POLICY CMP0091) - # Needed for CMAKE_MSVC_RUNTIME_LIBRARY - # https://cmake.org/cmake/help/latest/policy/CMP0091.html - cmake_policy(SET CMP0091 NEW) - endif() + if(POLICY CMP0091) + # Needed for CMAKE_MSVC_RUNTIME_LIBRARY + # https://cmake.org/cmake/help/latest/policy/CMP0091.html + cmake_policy(SET CMP0091 NEW) + endif() set(CPACK_GENERATOR "NSIS") # this needs NSIS installed, and available -elseif (APPLE) +elseif(APPLE) set(CPACK_GENERATOR "DragNDrop") elseif(EMSCRIPTEN) - set(USE_BUNDLED_DEPS ON CACHE BOOL "" FORCE) - set(BUILD_DRIVER OFF CACHE BOOL "" FORCE) - set(ENABLE_DKMS OFF CACHE BOOL "" FORCE) - set(BUILD_BPF OFF CACHE BOOL "" FORCE) - set(CPACK_GENERATOR TGZ CACHE BOOL "" FORCE) + set(USE_BUNDLED_DEPS + ON + CACHE BOOL "" FORCE + ) + set(BUILD_DRIVER + OFF + CACHE BOOL "" FORCE + ) + set(ENABLE_DKMS + OFF + CACHE BOOL "" FORCE + ) + set(BUILD_BPF + OFF + CACHE BOOL "" FORCE + ) + set(CPACK_GENERATOR + TGZ + CACHE BOOL "" FORCE + ) endif() # gVisor is currently only supported on Linux x86_64 -if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD) - option(BUILD_FALCO_GVISOR "Build gVisor support for Falco" ON) - if (BUILD_FALCO_GVISOR) - add_definitions(-DHAS_GVISOR) - endif() +if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" + AND CMAKE_SYSTEM_NAME MATCHES "Linux" + AND NOT MINIMAL_BUILD +) + option(BUILD_FALCO_GVISOR "Build gVisor support for Falco" ON) + if(BUILD_FALCO_GVISOR) + add_definitions(-DHAS_GVISOR) + endif() endif() # Modern BPF is not supported on not Linux systems and in MINIMAL_BUILD if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD) - option(BUILD_FALCO_MODERN_BPF "Build modern BPF support for Falco" ON) - if(BUILD_FALCO_MODERN_BPF) - add_definitions(-DHAS_MODERN_BPF) - endif() + option(BUILD_FALCO_MODERN_BPF "Build modern BPF support for Falco" ON) + if(BUILD_FALCO_MODERN_BPF) + add_definitions(-DHAS_MODERN_BPF) + endif() endif() # We shouldn't need to set this, see https://gitlab.kitware.com/cmake/cmake/-/issues/16419 option(EP_UPDATE_DISCONNECTED "ExternalProject update disconnected" OFF) -if (${EP_UPDATE_DISCONNECTED}) - set_property( - DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - PROPERTY EP_UPDATE_DISCONNECTED TRUE) +if(${EP_UPDATE_DISCONNECTED}) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY EP_UPDATE_DISCONNECTED TRUE) endif() -# Elapsed time -# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time") # TODO(fntlnz, leodido): add a flag to enable this +# Elapsed time set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time") # +# TODO(fntlnz, leodido): add a flag to enable this # Make flag for parallel processing include(ProcessorCount) -processorcount(PROCESSOR_COUNT) +ProcessorCount(PROCESSOR_COUNT) if(NOT PROCESSOR_COUNT EQUAL 0) - set(PROCESSOUR_COUNT_MAKE_FLAG -j${PROCESSOR_COUNT}) + set(PROCESSOUR_COUNT_MAKE_FLAG -j${PROCESSOR_COUNT}) endif() # Custom CMake modules @@ -83,14 +104,14 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") include(GNUInstallDirs) if(NOT DEFINED FALCO_ETC_DIR) - set(FALCO_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falco") + set(FALCO_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falco") endif() # This will be used to print the architecture for which Falco is compiled. -if (EMSCRIPTEN) - set(FALCO_TARGET_ARCH "wasm") +if(EMSCRIPTEN) + set(FALCO_TARGET_ARCH "wasm") else() - set(FALCO_TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR}) + set(FALCO_TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR}) endif() include(CompilerFlags) @@ -100,19 +121,20 @@ set(DRIVER_NAME "falco") set(DRIVER_DEVICE_NAME "falco") set(DRIVERS_REPO "https://download.falco.org/driver") -# If no path is provided, try to search the BPF probe in: `home/.falco/falco-bpf.o` -# This is the same fallback that we had in the libraries: `SCAP_PROBE_BPF_FILEPATH`. +# If no path is provided, try to search the BPF probe in: `home/.falco/falco-bpf.o` This is the same +# fallback that we had in the libraries: `SCAP_PROBE_BPF_FILEPATH`. set(FALCO_PROBE_BPF_FILEPATH ".${DRIVER_NAME}/${DRIVER_NAME}-bpf.o") add_definitions(-DFALCO_PROBE_BPF_FILEPATH="${FALCO_PROBE_BPF_FILEPATH}") if(NOT DEFINED FALCO_COMPONENT_NAME) - set(FALCO_COMPONENT_NAME "${CMAKE_PROJECT_NAME}") + set(FALCO_COMPONENT_NAME "${CMAKE_PROJECT_NAME}") endif() if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX - /usr - CACHE PATH "Default install path" FORCE) + set(CMAKE_INSTALL_PREFIX + /usr + CACHE PATH "Default install path" FORCE + ) endif() set(CMD_MAKE make) @@ -131,61 +153,93 @@ include(njson) # yaml-cpp include(yaml-cpp) -if(NOT WIN32 AND NOT APPLE AND NOT MINIMAL_BUILD AND NOT EMSCRIPTEN) - # OpenSSL - include(openssl) +if(NOT WIN32 + AND NOT APPLE + AND NOT MINIMAL_BUILD + AND NOT EMSCRIPTEN +) + # OpenSSL + include(openssl) - # libcurl - include(curl) + # libcurl + include(curl) - # todo(jasondellaluce,rohith-raju): support webserver for non-linux builds too - # cpp-httlib - include(cpp-httplib) + # todo(jasondellaluce,rohith-raju): support webserver for non-linux builds too cpp-httlib + include(cpp-httplib) endif() include(cxxopts) # One TBB -if (NOT EMSCRIPTEN) - include(tbb) +if(NOT EMSCRIPTEN) + include(tbb) endif() include(zlib) include(valijson) -if (NOT MINIMAL_BUILD) - if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN) - include(cares) - include(protobuf) - # gRPC - include(grpc) - endif() +if(NOT MINIMAL_BUILD) + if(NOT WIN32 + AND NOT APPLE + AND NOT EMSCRIPTEN + ) + include(cares) + include(protobuf) + # gRPC + include(grpc) + endif() endif() # Installation if(WIN32) - set(FALCO_INSTALL_CONF_FILE "%PROGRAMFILES%/${PACKAGE_NAME}-${FALCO_VERSION}/etc/falco/falco.yaml") - install(FILES falco.yaml DESTINATION etc/falco/ COMPONENT "${FALCO_COMPONENT_NAME}") - install(DIRECTORY DESTINATION etc/falco/config.d COMPONENT "${FALCO_COMPONENT_NAME}") + set(FALCO_INSTALL_CONF_FILE + "%PROGRAMFILES%/${PACKAGE_NAME}-${FALCO_VERSION}/etc/falco/falco.yaml" + ) + install( + FILES falco.yaml + DESTINATION etc/falco/ + COMPONENT "${FALCO_COMPONENT_NAME}" + ) + install( + DIRECTORY + DESTINATION etc/falco/config.d + COMPONENT "${FALCO_COMPONENT_NAME}" + ) elseif(APPLE) set(FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml") - install(FILES falco.yaml DESTINATION etc/falco/ COMPONENT "${FALCO_COMPONENT_NAME}") - install(DIRECTORY DESTINATION etc/falco/config.d COMPONENT "${FALCO_COMPONENT_NAME}") + install( + FILES falco.yaml + DESTINATION etc/falco/ + COMPONENT "${FALCO_COMPONENT_NAME}" + ) + install( + DIRECTORY + DESTINATION etc/falco/config.d + COMPONENT "${FALCO_COMPONENT_NAME}" + ) else() set(FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml") - install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}") - install(DIRECTORY DESTINATION "${FALCO_ETC_DIR}/config.d" COMPONENT "${FALCO_COMPONENT_NAME}") + install( + FILES falco.yaml + DESTINATION "${FALCO_ETC_DIR}" + COMPONENT "${FALCO_COMPONENT_NAME}" + ) + install( + DIRECTORY + DESTINATION "${FALCO_ETC_DIR}/config.d" + COMPONENT "${FALCO_COMPONENT_NAME}" + ) endif() if(NOT MINIMAL_BUILD) - # Coverage - include(Coverage) + # Coverage + include(Coverage) endif() # Rules include(rules) -# Clang format -# add_custom_target(format COMMAND clang-format --style=file -i $ COMMENT "Formatting ..." VERBATIM) +# Clang format add_custom_target(format COMMAND clang-format --style=file -i +# $ COMMENT "Formatting ..." VERBATIM) # Static analysis include(static-analysis) @@ -199,13 +253,17 @@ add_subdirectory(scripts) add_subdirectory(userspace/engine) add_subdirectory(userspace/falco) -if(NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT MUSL_OPTIMIZED_BUILD) - include(falcoctl) +if(NOT WIN32 + AND NOT APPLE + AND NOT EMSCRIPTEN + AND NOT MUSL_OPTIMIZED_BUILD +) + include(falcoctl) endif() # Packages configuration include(CPackConfig) if(BUILD_FALCO_UNIT_TESTS) - add_subdirectory(unit_tests) + add_subdirectory(unit_tests) endif() diff --git a/cmake/cpack/CMakeCPackOptions.cmake b/cmake/cpack/CMakeCPackOptions.cmake index ee1b842f294..32274eeb6be 100644 --- a/cmake/cpack/CMakeCPackOptions.cmake +++ b/cmake/cpack/CMakeCPackOptions.cmake @@ -2,24 +2,53 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # if(CPACK_GENERATOR MATCHES "DEB" OR CPACK_GENERATOR MATCHES "RPM") - list(APPEND CPACK_INSTALL_COMMANDS "mkdir -p _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system") - list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/systemd/falco-kmod-inject.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system") - list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/systemd/falco-kmod.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system") - list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/systemd/falco-bpf.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system") - list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/systemd/falco-modern-bpf.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system") - list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/systemd/falco-custom.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system") - list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/systemd/falcoctl-artifact-follow.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system") + list( + APPEND + CPACK_INSTALL_COMMANDS + "mkdir -p _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system" + ) + list( + APPEND + CPACK_INSTALL_COMMANDS + "cp scripts/systemd/falco-kmod-inject.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system" + ) + list( + APPEND + CPACK_INSTALL_COMMANDS + "cp scripts/systemd/falco-kmod.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system" + ) + list( + APPEND + CPACK_INSTALL_COMMANDS + "cp scripts/systemd/falco-bpf.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system" + ) + list( + APPEND + CPACK_INSTALL_COMMANDS + "cp scripts/systemd/falco-modern-bpf.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system" + ) + list( + APPEND + CPACK_INSTALL_COMMANDS + "cp scripts/systemd/falco-custom.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system" + ) + list( + APPEND + CPACK_INSTALL_COMMANDS + "cp scripts/systemd/falcoctl-artifact-follow.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system" + ) endif() if(CPACK_GENERATOR MATCHES "TGZ") diff --git a/cmake/modules/CPackConfig.cmake b/cmake/modules/CPackConfig.cmake index 628cec6647c..e4074359d9c 100644 --- a/cmake/modules/CPackConfig.cmake +++ b/cmake/modules/CPackConfig.cmake @@ -2,19 +2,21 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # set(CPACK_PACKAGE_NAME "${PACKAGE_NAME}") set(CPACK_PACKAGE_VENDOR "Cloud Native Computing Foundation (CNCF) cncf.io.") -set(CPACK_PACKAGE_CONTACT "cncf-falco-dev@lists.cncf.io") # todo: change this once we've got @falco.org addresses +set(CPACK_PACKAGE_CONTACT "cncf-falco-dev@lists.cncf.io") # todo: change this once we've got +# @falco.org addresses set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Falco - Container Native Runtime Security") set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/scripts/description.txt") set(CPACK_PACKAGE_VERSION "${FALCO_VERSION}") @@ -24,32 +26,35 @@ set(CPACK_PACKAGE_VERSION_PATCH "${FALCO_VERSION_PATCH}") set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_SOURCE_DIR}/cmake/cpack/CMakeCPackOptions.cmake") set(CPACK_STRIP_FILES "ON") set(CPACK_PACKAGE_RELOCATABLE "OFF") -if (EMSCRIPTEN) - set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-wasm") +if(EMSCRIPTEN) + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-wasm") else() - set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}") + set(CPACK_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}" + ) endif() if(WIN32) - SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") + set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") endif() # Built packages will include only the following components set(CPACK_INSTALL_CMAKE_PROJECTS - "${CMAKE_CURRENT_BINARY_DIR};${FALCO_COMPONENT_NAME};${FALCO_COMPONENT_NAME};/" + "${CMAKE_CURRENT_BINARY_DIR};${FALCO_COMPONENT_NAME};${FALCO_COMPONENT_NAME};/" ) if(CMAKE_SYSTEM_NAME MATCHES "Linux") # only Linux has drivers - list(APPEND CPACK_INSTALL_CMAKE_PROJECTS - "${CMAKE_CURRENT_BINARY_DIR};${DRIVER_COMPONENT_NAME};${DRIVER_COMPONENT_NAME};/") + list(APPEND CPACK_INSTALL_CMAKE_PROJECTS + "${CMAKE_CURRENT_BINARY_DIR};${DRIVER_COMPONENT_NAME};${DRIVER_COMPONENT_NAME};/" + ) endif() if(NOT CPACK_GENERATOR) - if (CMAKE_SYSTEM_NAME MATCHES "Linux") - set(CPACK_GENERATOR DEB RPM TGZ) - else() - set(CPACK_GENERATOR TGZ) - endif() + if(CMAKE_SYSTEM_NAME MATCHES "Linux") + set(CPACK_GENERATOR DEB RPM TGZ) + else() + set(CPACK_GENERATOR TGZ) + endif() endif() message(STATUS "Using package generators: ${CPACK_GENERATOR}") @@ -57,15 +62,15 @@ message(STATUS "Package architecture: ${CMAKE_SYSTEM_PROCESSOR}") set(CPACK_DEBIAN_PACKAGE_SECTION "utils") if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") - set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") + set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") endif() if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") - set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64") + set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64") endif() set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://www.falco.org") set(CPACK_DEBIAN_PACKAGE_DEPENDS "dkms (>= 2.1.0.0)") set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA - "${CMAKE_BINARY_DIR}/scripts/debian/postinst;${CMAKE_BINARY_DIR}/scripts/debian/prerm;${CMAKE_BINARY_DIR}/scripts/debian/postrm;${PROJECT_SOURCE_DIR}/cmake/cpack/debian/conffiles" + "${CMAKE_BINARY_DIR}/scripts/debian/postinst;${CMAKE_BINARY_DIR}/scripts/debian/prerm;${CMAKE_BINARY_DIR}/scripts/debian/postrm;${PROJECT_SOURCE_DIR}/cmake/cpack/debian/conffiles" ) set(CPACK_RPM_PACKAGE_LICENSE "Apache v2.0") @@ -77,13 +82,14 @@ set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${CMAKE_BINARY_DIR}/scripts/rpm/preunin set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${CMAKE_BINARY_DIR}/scripts/rpm/postuninstall") set(CPACK_RPM_PACKAGE_VERSION "${FALCO_VERSION}") set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION - /usr/src - /usr/share/man - /usr/share/man/man8 - /etc - /usr - /usr/bin - /usr/share) + /usr/src + /usr/share/man + /usr/share/man/man8 + /etc + /usr + /usr/bin + /usr/share +) set(CPACK_RPM_PACKAGE_RELOCATABLE "OFF") include(CPack) diff --git a/cmake/modules/CompilerFlags.cmake b/cmake/modules/CompilerFlags.cmake index 302f68a6f24..62ed575810a 100644 --- a/cmake/modules/CompilerFlags.cmake +++ b/cmake/modules/CompilerFlags.cmake @@ -2,51 +2,51 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_EXTENSIONS OFF) if(NOT FALCO_EXTRA_DEBUG_FLAGS) - set(FALCO_EXTRA_DEBUG_FLAGS "-D_DEBUG") + set(FALCO_EXTRA_DEBUG_FLAGS "-D_DEBUG") endif() string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE) if(CMAKE_BUILD_TYPE STREQUAL "debug") - set(KBUILD_FLAGS "${FALCO_EXTRA_DEBUG_FLAGS} ${FALCO_EXTRA_FEATURE_FLAGS}") + set(KBUILD_FLAGS "${FALCO_EXTRA_DEBUG_FLAGS} ${FALCO_EXTRA_FEATURE_FLAGS}") else() - set(CMAKE_BUILD_TYPE "release") - set(KBUILD_FLAGS "${FALCO_EXTRA_FEATURE_FLAGS}") - add_definitions(-DBUILD_TYPE_RELEASE) + set(CMAKE_BUILD_TYPE "release") + set(KBUILD_FLAGS "${FALCO_EXTRA_FEATURE_FLAGS}") + add_definitions(-DBUILD_TYPE_RELEASE) endif() message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") if(MINIMAL_BUILD) - set(MINIMAL_BUILD_FLAGS "-DMINIMAL_BUILD") + set(MINIMAL_BUILD_FLAGS "-DMINIMAL_BUILD") endif() if(MUSL_OPTIMIZED_BUILD) - set(MUSL_FLAGS "-static -Os -fPIE -pie") - add_definitions(-DMUSL_OPTIMIZED) + set(MUSL_FLAGS "-static -Os -fPIE -pie") + add_definitions(-DMUSL_OPTIMIZED) endif() # explicitly set hardening flags set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(FALCO_SECURITY_FLAGS "") if(LINUX) - set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -fstack-protector-strong") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro,-z,now") + set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -fstack-protector-strong") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro,-z,now") endif() - if(NOT MSVC) if(CMAKE_BUILD_TYPE STREQUAL "release") @@ -64,7 +64,9 @@ if(NOT MSVC) endif() endif() - set(CMAKE_COMMON_FLAGS "${FALCO_SECURITY_FLAGS} -Wall -ggdb ${FALCO_EXTRA_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}") + set(CMAKE_COMMON_FLAGS + "${FALCO_SECURITY_FLAGS} -Wall -ggdb ${FALCO_EXTRA_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}" + ) if(BUILD_WARNINGS_AS_ERRORS) set(CMAKE_SUPPRESSED_WARNINGS @@ -87,18 +89,11 @@ else() # MSVC set(MINIMAL_BUILD ON) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - # The WIN32_LEAN_AND_MEAN define avoids possible macro pollution - # when a libsinsp consumer includes the windows.h header: - # https://stackoverflow.com/a/28380820 - # Same goes for NOMINMAX: + # The WIN32_LEAN_AND_MEAN define avoids possible macro pollution when a libsinsp consumer + # includes the windows.h header: https://stackoverflow.com/a/28380820 Same goes for NOMINMAX: # https://stackoverflow.com/questions/5004858/why-is-stdmin-failing-when-windows-h-is-included add_compile_definitions( - _HAS_STD_BYTE=0 - _CRT_SECURE_NO_WARNINGS - WIN32 - MINIMAL_BUILD - WIN32_LEAN_AND_MEAN - NOMINMAX + _HAS_STD_BYTE=0 _CRT_SECURE_NO_WARNINGS WIN32 MINIMAL_BUILD WIN32_LEAN_AND_MEAN NOMINMAX ) set(FALCOSECURITY_LIBS_COMMON_FLAGS "/EHsc /W3 /Zi /std:c++17") diff --git a/cmake/modules/Coverage.cmake b/cmake/modules/Coverage.cmake index b8a46e7ab37..8d8c323e032 100644 --- a/cmake/modules/Coverage.cmake +++ b/cmake/modules/Coverage.cmake @@ -2,25 +2,28 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # # Tests coverage option(FALCO_COVERAGE "Build test suite with coverage information" OFF) if(FALCO_COVERAGE) - if(NOT (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))) - message(FATAL_ERROR "FALCO_COVERAGE requires GCC or Clang.") - endif() + if(NOT (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES + "Clang")) + ) + message(FATAL_ERROR "FALCO_COVERAGE requires GCC or Clang.") + endif() - message(STATUS "Building with coverage information") - add_compile_options(-g --coverage) - set(CMAKE_SHARED_LINKER_FLAGS "--coverage ${CMAKE_SHARED_LINKER_FLAGS}") - set(CMAKE_EXE_LINKER_FLAGS "--coverage ${CMAKE_EXE_LINKER_FLAGS}") + message(STATUS "Building with coverage information") + add_compile_options(-g --coverage) + set(CMAKE_SHARED_LINKER_FLAGS "--coverage ${CMAKE_SHARED_LINKER_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "--coverage ${CMAKE_EXE_LINKER_FLAGS}") endif() diff --git a/cmake/modules/copy_files_to_build_dir.cmake b/cmake/modules/copy_files_to_build_dir.cmake index a3c3ab39249..add10dbd51f 100644 --- a/cmake/modules/copy_files_to_build_dir.cmake +++ b/cmake/modules/copy_files_to_build_dir.cmake @@ -2,30 +2,32 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # function(copy_files_to_build_dir source_files targetsuffix) - set(build_files) + set(build_files) - foreach(file_path ${source_files}) - get_filename_component(trace_file ${file_path} NAME) - list(APPEND build_files ${CMAKE_CURRENT_BINARY_DIR}/${trace_file}) - endforeach() + foreach(file_path ${source_files}) + get_filename_component(trace_file ${file_path} NAME) + list(APPEND build_files ${CMAKE_CURRENT_BINARY_DIR}/${trace_file}) + endforeach() - add_custom_target(copy-files-${targetsuffix} ALL - DEPENDS ${build_files}) + add_custom_target(copy-files-${targetsuffix} ALL DEPENDS ${build_files}) - add_custom_command(OUTPUT ${build_files} - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${source_files} ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${source_files}) + add_custom_command( + OUTPUT ${build_files} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${source_files} ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${source_files} + ) endfunction() diff --git a/cmake/modules/cpp-httplib.cmake b/cmake/modules/cpp-httplib.cmake index 3b7a166f0f4..28c9de8fa9e 100644 --- a/cmake/modules/cpp-httplib.cmake +++ b/cmake/modules/cpp-httplib.cmake @@ -2,25 +2,27 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # option(USE_BUNDLED_CPPHTTPLIB "Enable building of the bundled cpp-httplib" ${USE_BUNDLED_DEPS}) if(USE_BUNDLED_CPPHTTPLIB) - include(FetchContent) - FetchContent_Declare(cpp-httplib - URL https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.15.3.tar.gz - URL_HASH SHA256=2121bbf38871bb2aafb5f7f2b9b94705366170909f434428352187cb0216124e - ) - FetchContent_MakeAvailable(cpp-httplib) + include(FetchContent) + FetchContent_Declare( + cpp-httplib + URL https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.15.3.tar.gz + URL_HASH SHA256=2121bbf38871bb2aafb5f7f2b9b94705366170909f434428352187cb0216124e + ) + FetchContent_MakeAvailable(cpp-httplib) else() - find_package(httplib CONFIG REQUIRED) + find_package(httplib CONFIG REQUIRED) endif() diff --git a/cmake/modules/cxxopts.cmake b/cmake/modules/cxxopts.cmake index 0b821418595..4515a725bb8 100644 --- a/cmake/modules/cxxopts.cmake +++ b/cmake/modules/cxxopts.cmake @@ -2,14 +2,15 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # # @@ -19,25 +20,26 @@ option(USE_BUNDLED_CXXOPTS "Enable building of the bundled cxxopts" ${USE_BUNDLED_DEPS}) if(CXXOPTS_INCLUDE_DIR) - # we already have cxxopts + # we already have cxxopts elseif(NOT USE_BUNDLED_CXXOPTS) - find_package(cxxopts CONFIG REQUIRED) - get_target_property(CXXOPTS_INCLUDE_DIR cxxopts::cxxopts INTERFACE_INCLUDE_DIRECTORIES) + find_package(cxxopts CONFIG REQUIRED) + get_target_property(CXXOPTS_INCLUDE_DIR cxxopts::cxxopts INTERFACE_INCLUDE_DIRECTORIES) else() - set(CXXOPTS_SRC "${PROJECT_BINARY_DIR}/cxxopts-prefix/src/cxxopts/") - set(CXXOPTS_INCLUDE_DIR "${CXXOPTS_SRC}/include") + set(CXXOPTS_SRC "${PROJECT_BINARY_DIR}/cxxopts-prefix/src/cxxopts/") + set(CXXOPTS_INCLUDE_DIR "${CXXOPTS_SRC}/include") - message(STATUS "Using bundled cxxopts in ${CXXOPTS_SRC}") + message(STATUS "Using bundled cxxopts in ${CXXOPTS_SRC}") - ExternalProject_Add( - cxxopts - URL "https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.0.0.tar.gz" - URL_HASH "SHA256=36f41fa2a46b3c1466613b63f3fa73dc24d912bc90d667147f1e43215a8c6d00" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "") + ExternalProject_Add( + cxxopts + URL "https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.0.0.tar.gz" + URL_HASH "SHA256=36f41fa2a46b3c1466613b63f3fa73dc24d912bc90d667147f1e43215a8c6d00" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + ) endif() if(NOT TARGET cxxopts) - add_custom_target(cxxopts) + add_custom_target(cxxopts) endif() diff --git a/cmake/modules/driver-repo/CMakeLists.txt b/cmake/modules/driver-repo/CMakeLists.txt index 96f73aeb70c..d065ea271fa 100644 --- a/cmake/modules/driver-repo/CMakeLists.txt +++ b/cmake/modules/driver-repo/CMakeLists.txt @@ -2,14 +2,15 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # cmake_minimum_required(VERSION 3.5.1) @@ -20,12 +21,12 @@ message(STATUS "Driver repository: ${DRIVER_REPO}") message(STATUS "Driver version: ${DRIVER_VERSION}") ExternalProject_Add( - driver - URL "https://github.com/${DRIVER_REPO}/archive/${DRIVER_VERSION}.tar.gz" - URL_HASH "${DRIVER_CHECKSUM}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" - PATCH_COMMAND sh -c "mv ./driver ../driver.tmp && rm -rf ./* && mv ../driver.tmp/* ." + driver + URL "https://github.com/${DRIVER_REPO}/archive/${DRIVER_VERSION}.tar.gz" + URL_HASH "${DRIVER_CHECKSUM}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + PATCH_COMMAND sh -c "mv ./driver ../driver.tmp && rm -rf ./* && mv ../driver.tmp/* ." ) diff --git a/cmake/modules/driver.cmake b/cmake/modules/driver.cmake index d1ff32be247..012549a430f 100644 --- a/cmake/modules/driver.cmake +++ b/cmake/modules/driver.cmake @@ -2,14 +2,15 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # set(DRIVER_CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/driver-repo") @@ -18,37 +19,42 @@ set(DRIVER_CMAKE_WORKING_DIR "${CMAKE_BINARY_DIR}/driver-repo") file(MAKE_DIRECTORY ${DRIVER_CMAKE_WORKING_DIR}) if(DRIVER_SOURCE_DIR) - set(DRIVER_VERSION "0.0.0-local") - message(STATUS "Using local version for driver: '${DRIVER_SOURCE_DIR}'") + set(DRIVER_VERSION "0.0.0-local") + message(STATUS "Using local version for driver: '${DRIVER_SOURCE_DIR}'") else() - # DRIVER_REPO accepts a repository name (/) alternative to the falcosecurity/libs repository. - # In case you want to test against a fork of falcosecurity/libs just pass the variable - - # ie., `cmake -DDRIVER_REPO=/libs ..` - if (NOT DRIVER_REPO) - set(DRIVER_REPO "falcosecurity/libs") - endif() - - # DRIVER_VERSION accepts a git reference (branch name, commit hash, or tag) to the falcosecurity/libs repository - # which contains the driver source code under the `/driver` directory. - # The chosen driver version must be compatible with the given FALCOSECURITY_LIBS_VERSION. - # In case you want to test against another driver version (or branch, or commit) just pass the variable - - # ie., `cmake -DDRIVER_VERSION=dev ..` - if(NOT DRIVER_VERSION) - set(DRIVER_VERSION "7.3.0+driver") - set(DRIVER_CHECKSUM "SHA256=8f572d9a83feda635a3fa53b859d61e37af127c241e35068aadee3bc50d212c0") - endif() - - # cd /path/to/build && cmake /path/to/source - execute_process(COMMAND "${CMAKE_COMMAND}" - -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" - -DDRIVER_REPO=${DRIVER_REPO} - -DDRIVER_VERSION=${DRIVER_VERSION} - -DDRIVER_CHECKSUM=${DRIVER_CHECKSUM} - ${DRIVER_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${DRIVER_CMAKE_WORKING_DIR}) - - # cmake --build . - execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${DRIVER_CMAKE_WORKING_DIR}") - set(DRIVER_SOURCE_DIR "${DRIVER_CMAKE_WORKING_DIR}/driver-prefix/src/driver") + # DRIVER_REPO accepts a repository name (/) alternative to the + # falcosecurity/libs repository. In case you want to test against a fork of falcosecurity/libs + # just pass the variable - ie., `cmake -DDRIVER_REPO=/libs ..` + if(NOT DRIVER_REPO) + set(DRIVER_REPO "falcosecurity/libs") + endif() + + # DRIVER_VERSION accepts a git reference (branch name, commit hash, or tag) to the + # falcosecurity/libs repository which contains the driver source code under the `/driver` + # directory. The chosen driver version must be compatible with the given + # FALCOSECURITY_LIBS_VERSION. In case you want to test against another driver version (or + # branch, or commit) just pass the variable - ie., `cmake -DDRIVER_VERSION=dev ..` + if(NOT DRIVER_VERSION) + set(DRIVER_VERSION "7.3.0+driver") + set(DRIVER_CHECKSUM + "SHA256=8f572d9a83feda635a3fa53b859d61e37af127c241e35068aadee3bc50d212c0" + ) + endif() + + # cd /path/to/build && cmake /path/to/source + execute_process( + COMMAND + "${CMAKE_COMMAND}" -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" -DDRIVER_REPO=${DRIVER_REPO} + -DDRIVER_VERSION=${DRIVER_VERSION} -DDRIVER_CHECKSUM=${DRIVER_CHECKSUM} + ${DRIVER_CMAKE_SOURCE_DIR} + WORKING_DIRECTORY ${DRIVER_CMAKE_WORKING_DIR} + ) + + # cmake --build . + execute_process( + COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${DRIVER_CMAKE_WORKING_DIR}" + ) + set(DRIVER_SOURCE_DIR "${DRIVER_CMAKE_WORKING_DIR}/driver-prefix/src/driver") endif() add_definitions(-D_GNU_SOURCE) diff --git a/cmake/modules/falco-version.cmake b/cmake/modules/falco-version.cmake index 81da8799f2e..fc95d813a3a 100644 --- a/cmake/modules/falco-version.cmake +++ b/cmake/modules/falco-version.cmake @@ -2,14 +2,15 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # # Retrieve git ref and commit hash @@ -17,33 +18,39 @@ include(GetVersionFromGit) # Get Falco version variable according to git index if(NOT FALCO_VERSION) - set(FALCO_VERSION "0.0.0") - get_version_from_git(FALCO_VERSION "" "") + set(FALCO_VERSION "0.0.0") + get_version_from_git(FALCO_VERSION "" "") endif() # Remove the starting "v" in case there is one string(REGEX REPLACE "^v(.*)" "\\1" FALCO_VERSION "${FALCO_VERSION}") string(REGEX MATCH "^(0|[1-9][0-9]*)" FALCO_VERSION_MAJOR "${FALCO_VERSION}") -string(REGEX REPLACE "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\..*" "\\2" FALCO_VERSION_MINOR "${FALCO_VERSION}") -string(REGEX REPLACE "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*).*" "\\3" FALCO_VERSION_PATCH - "${FALCO_VERSION}") +string(REGEX REPLACE "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\..*" "\\2" FALCO_VERSION_MINOR + "${FALCO_VERSION}" +) +string(REGEX REPLACE "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*).*" "\\3" + FALCO_VERSION_PATCH "${FALCO_VERSION}" +) string( - REGEX - REPLACE - "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*).*" - "\\5" - FALCO_VERSION_PRERELEASE - "${FALCO_VERSION}") + REGEX + REPLACE + "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*).*" + "\\5" + FALCO_VERSION_PRERELEASE + "${FALCO_VERSION}" +) if(FALCO_VERSION_PRERELEASE STREQUAL "${FALCO_VERSION}") - set(FALCO_VERSION_PRERELEASE "") + set(FALCO_VERSION_PRERELEASE "") endif() if(NOT FALCO_VERSION_BUILD) - string(REGEX REPLACE ".*\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)" "\\1" FALCO_VERSION_BUILD "${FALCO_VERSION}") + string(REGEX REPLACE ".*\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)" "\\1" FALCO_VERSION_BUILD + "${FALCO_VERSION}" + ) endif() if(FALCO_VERSION_BUILD STREQUAL "${FALCO_VERSION}") - set(FALCO_VERSION_BUILD "") + set(FALCO_VERSION_BUILD "") endif() message(STATUS "Falco version: ${FALCO_VERSION}") diff --git a/cmake/modules/falcoctl.cmake b/cmake/modules/falcoctl.cmake index c202e4d06ee..e56f70da6da 100644 --- a/cmake/modules/falcoctl.cmake +++ b/cmake/modules/falcoctl.cmake @@ -2,14 +2,15 @@ # # Copyright (C) 2023 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 +# 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. +# 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(ExternalProject) @@ -17,30 +18,39 @@ include(ExternalProject) option(ADD_FALCOCTL_DEPENDENCY "Add falcoctl dependency while building falco" ON) if(ADD_FALCOCTL_DEPENDENCY) -string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} FALCOCTL_SYSTEM_NAME) - -set(FALCOCTL_VERSION "0.10.0") - -message(STATUS "Building with falcoctl: ${FALCOCTL_VERSION}") - -if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64") - set(FALCOCTL_SYSTEM_PROC_GO "amd64") - set(FALCOCTL_HASH "32d1be4ab2335d9c3fc8ae8900341bcc26d3166094fc553ddb7bb783aa6c7b68") -else() # aarch64 - set(FALCOCTL_SYSTEM_PROC_GO "arm64") - set(FALCOCTL_HASH "9186fd948c1230c338a7fa36d6569ce85d3c4aa8153b30e8d86d2e887eb76756") -endif() - -ExternalProject_Add( - falcoctl - URL "https://github.com/falcosecurity/falcoctl/releases/download/v${FALCOCTL_VERSION}/falcoctl_${FALCOCTL_VERSION}_${FALCOCTL_SYSTEM_NAME}_${FALCOCTL_SYSTEM_PROC_GO}.tar.gz" - URL_HASH "SHA256=${FALCOCTL_HASH}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "") - -install(PROGRAMS "${PROJECT_BINARY_DIR}/falcoctl-prefix/src/falcoctl/falcoctl" DESTINATION "${FALCO_BIN_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}") -install(DIRECTORY DESTINATION "${FALCO_ABSOLUTE_SHARE_DIR}/plugins" COMPONENT "${FALCO_COMPONENT_NAME}") + string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} FALCOCTL_SYSTEM_NAME) + + set(FALCOCTL_VERSION "0.10.0") + + message(STATUS "Building with falcoctl: ${FALCOCTL_VERSION}") + + if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64") + set(FALCOCTL_SYSTEM_PROC_GO "amd64") + set(FALCOCTL_HASH "32d1be4ab2335d9c3fc8ae8900341bcc26d3166094fc553ddb7bb783aa6c7b68") + else() # aarch64 + set(FALCOCTL_SYSTEM_PROC_GO "arm64") + set(FALCOCTL_HASH "9186fd948c1230c338a7fa36d6569ce85d3c4aa8153b30e8d86d2e887eb76756") + endif() + + ExternalProject_Add( + falcoctl + URL "https://github.com/falcosecurity/falcoctl/releases/download/v${FALCOCTL_VERSION}/falcoctl_${FALCOCTL_VERSION}_${FALCOCTL_SYSTEM_NAME}_${FALCOCTL_SYSTEM_PROC_GO}.tar.gz" + URL_HASH "SHA256=${FALCOCTL_HASH}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + ) + + install( + PROGRAMS "${PROJECT_BINARY_DIR}/falcoctl-prefix/src/falcoctl/falcoctl" + DESTINATION "${FALCO_BIN_DIR}" + COMPONENT "${FALCO_COMPONENT_NAME}" + ) + install( + DIRECTORY + DESTINATION "${FALCO_ABSOLUTE_SHARE_DIR}/plugins" + COMPONENT "${FALCO_COMPONENT_NAME}" + ) else() - message(STATUS "Won't build with falcoctl") + message(STATUS "Won't build with falcoctl") endif() diff --git a/cmake/modules/falcosecurity-libs-repo/CMakeLists.txt b/cmake/modules/falcosecurity-libs-repo/CMakeLists.txt index 748737c7b43..f73a36d75b0 100644 --- a/cmake/modules/falcosecurity-libs-repo/CMakeLists.txt +++ b/cmake/modules/falcosecurity-libs-repo/CMakeLists.txt @@ -2,14 +2,15 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # cmake_minimum_required(VERSION 3.5.1) @@ -20,11 +21,11 @@ message(STATUS "Libs repository: ${FALCOSECURITY_LIBS_REPO}") message(STATUS "Libs version: ${FALCOSECURITY_LIBS_VERSION}") ExternalProject_Add( - falcosecurity-libs - URL "https://github.com/${FALCOSECURITY_LIBS_REPO}/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz" - URL_HASH "${FALCOSECURITY_LIBS_CHECKSUM}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" + falcosecurity-libs + URL "https://github.com/${FALCOSECURITY_LIBS_REPO}/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz" + URL_HASH "${FALCOSECURITY_LIBS_CHECKSUM}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" ) diff --git a/cmake/modules/falcosecurity-libs.cmake b/cmake/modules/falcosecurity-libs.cmake index 79476070d09..7d2468a2e3b 100644 --- a/cmake/modules/falcosecurity-libs.cmake +++ b/cmake/modules/falcosecurity-libs.cmake @@ -2,65 +2,82 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # -set(FALCOSECURITY_LIBS_CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/falcosecurity-libs-repo") +set(FALCOSECURITY_LIBS_CMAKE_SOURCE_DIR + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/falcosecurity-libs-repo" +) set(FALCOSECURITY_LIBS_CMAKE_WORKING_DIR "${CMAKE_BINARY_DIR}/falcosecurity-libs-repo") file(MAKE_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR}) # explicitly disable the bundled driver, since we pull it separately -set(USE_BUNDLED_DRIVER OFF CACHE BOOL "") +set(USE_BUNDLED_DRIVER + OFF + CACHE BOOL "" +) if(FALCOSECURITY_LIBS_SOURCE_DIR) - set(FALCOSECURITY_LIBS_VERSION "0.0.0-local") - message(STATUS "Using local version of falcosecurity/libs: '${FALCOSECURITY_LIBS_SOURCE_DIR}'") + set(FALCOSECURITY_LIBS_VERSION "0.0.0-local") + message(STATUS "Using local version of falcosecurity/libs: '${FALCOSECURITY_LIBS_SOURCE_DIR}'") else() - # FALCOSECURITY_LIBS_REPO accepts a repository name (/) alternative to the falcosecurity/libs repository. - # In case you want to test against a fork of falcosecurity/libs just pass the variable - - # ie., `cmake -DFALCOSECURITY_LIBS_REPO=/libs ..` - if (NOT FALCOSECURITY_LIBS_REPO) - set(FALCOSECURITY_LIBS_REPO "falcosecurity/libs") - endif() - - # FALCOSECURITY_LIBS_VERSION accepts a git reference (branch name, commit hash, or tag) to the falcosecurity/libs repository. - # In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable - - # ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..` - if(NOT FALCOSECURITY_LIBS_VERSION) - set(FALCOSECURITY_LIBS_VERSION "0.18.1") - set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=1812e8236c4cb51d3fe5dd066d71be99f25da7ed22d8feeeebeed09bdc26325f") - endif() - - # cd /path/to/build && cmake /path/to/source - execute_process(COMMAND "${CMAKE_COMMAND}" - -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" - -DFALCOSECURITY_LIBS_REPO=${FALCOSECURITY_LIBS_REPO} - -DFALCOSECURITY_LIBS_VERSION=${FALCOSECURITY_LIBS_VERSION} - -DFALCOSECURITY_LIBS_CHECKSUM=${FALCOSECURITY_LIBS_CHECKSUM} - ${FALCOSECURITY_LIBS_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR}) - - # cmake --build . - execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR}") - set(FALCOSECURITY_LIBS_SOURCE_DIR "${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR}/falcosecurity-libs-prefix/src/falcosecurity-libs") + # FALCOSECURITY_LIBS_REPO accepts a repository name (/) alternative to the + # falcosecurity/libs repository. In case you want to test against a fork of falcosecurity/libs + # just pass the variable - ie., `cmake -DFALCOSECURITY_LIBS_REPO=/libs ..` + if(NOT FALCOSECURITY_LIBS_REPO) + set(FALCOSECURITY_LIBS_REPO "falcosecurity/libs") + endif() + + # FALCOSECURITY_LIBS_VERSION accepts a git reference (branch name, commit hash, or tag) to the + # falcosecurity/libs repository. In case you want to test against another falcosecurity/libs + # version (or branch, or commit) just pass the variable - ie., `cmake + # -DFALCOSECURITY_LIBS_VERSION=dev ..` + if(NOT FALCOSECURITY_LIBS_VERSION) + set(FALCOSECURITY_LIBS_VERSION "0.18.1") + set(FALCOSECURITY_LIBS_CHECKSUM + "SHA256=1812e8236c4cb51d3fe5dd066d71be99f25da7ed22d8feeeebeed09bdc26325f" + ) + endif() + + # cd /path/to/build && cmake /path/to/source + execute_process( + COMMAND + "${CMAKE_COMMAND}" -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" + -DFALCOSECURITY_LIBS_REPO=${FALCOSECURITY_LIBS_REPO} + -DFALCOSECURITY_LIBS_VERSION=${FALCOSECURITY_LIBS_VERSION} + -DFALCOSECURITY_LIBS_CHECKSUM=${FALCOSECURITY_LIBS_CHECKSUM} + ${FALCOSECURITY_LIBS_CMAKE_SOURCE_DIR} + WORKING_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR} + ) + + # cmake --build . + execute_process( + COMMAND "${CMAKE_COMMAND}" --build . + WORKING_DIRECTORY "${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR}" + ) + set(FALCOSECURITY_LIBS_SOURCE_DIR + "${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR}/falcosecurity-libs-prefix/src/falcosecurity-libs" + ) endif() set(LIBS_PACKAGE_NAME "falcosecurity") if(CMAKE_SYSTEM_NAME MATCHES "Linux") - add_definitions(-D_GNU_SOURCE) - add_definitions(-DHAS_CAPTURE) + add_definitions(-D_GNU_SOURCE) + add_definitions(-DHAS_CAPTURE) endif() if(MUSL_OPTIMIZED_BUILD) - add_definitions(-DMUSL_OPTIMIZED) + add_definitions(-DMUSL_OPTIMIZED) endif() set(SCAP_HOST_ROOT_ENV_VAR_NAME "HOST_ROOT") @@ -68,27 +85,60 @@ set(SCAP_HOSTNAME_ENV_VAR "FALCO_HOSTNAME") set(SINSP_AGENT_CGROUP_MEM_PATH_ENV_VAR "FALCO_CGROUP_MEM_PATH") if(NOT LIBS_DIR) - set(LIBS_DIR "${FALCOSECURITY_LIBS_SOURCE_DIR}") + set(LIBS_DIR "${FALCOSECURITY_LIBS_SOURCE_DIR}") endif() # configure gVisor support -set(BUILD_LIBSCAP_GVISOR ${BUILD_FALCO_GVISOR} CACHE BOOL "") +set(BUILD_LIBSCAP_GVISOR + ${BUILD_FALCO_GVISOR} + CACHE BOOL "" +) # configure modern BPF support -set(BUILD_LIBSCAP_MODERN_BPF ${BUILD_FALCO_MODERN_BPF} CACHE BOOL "") +set(BUILD_LIBSCAP_MODERN_BPF + ${BUILD_FALCO_MODERN_BPF} + CACHE BOOL "" +) # explicitly disable the tests/examples of this dependency -set(CREATE_TEST_TARGETS OFF CACHE BOOL "") -set(BUILD_LIBSCAP_EXAMPLES OFF CACHE BOOL "") - -set(USE_BUNDLED_TBB ON CACHE BOOL "") -set(USE_BUNDLED_JSONCPP ON CACHE BOOL "") -set(USE_BUNDLED_VALIJSON ON CACHE BOOL "") -set(USE_BUNDLED_RE2 ON CACHE BOOL "") -set(USE_BUNDLED_UTHASH ON CACHE BOOL "") +set(CREATE_TEST_TARGETS + OFF + CACHE BOOL "" +) +set(BUILD_LIBSCAP_EXAMPLES + OFF + CACHE BOOL "" +) + +set(USE_BUNDLED_TBB + ON + CACHE BOOL "" +) +set(USE_BUNDLED_JSONCPP + ON + CACHE BOOL "" +) +set(USE_BUNDLED_VALIJSON + ON + CACHE BOOL "" +) +set(USE_BUNDLED_RE2 + ON + CACHE BOOL "" +) +set(USE_BUNDLED_UTHASH + ON + CACHE BOOL "" +) if(USE_DYNAMIC_LIBELF) - set(USE_BUNDLED_LIBELF OFF CACHE BOOL "") - set(USE_SHARED_LIBELF ON CACHE BOOL "") + set(USE_BUNDLED_LIBELF + OFF + CACHE BOOL "" + ) + set(USE_SHARED_LIBELF + ON + CACHE BOOL "" + ) endif() list(APPEND CMAKE_MODULE_PATH "${FALCOSECURITY_LIBS_SOURCE_DIR}/cmake/modules") @@ -97,15 +147,18 @@ include(CheckSymbolExists) check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY) if(HAVE_STRLCPY) - message(STATUS "Existing strlcpy and strlcat found, will *not* use local definition by setting -DHAVE_STRLCPY and -DHAVE_STRLCAT.") - add_definitions(-DHAVE_STRLCPY) - add_definitions(-DHAVE_STRLCAT) + message( + STATUS + "Existing strlcpy and strlcat found, will *not* use local definition by setting -DHAVE_STRLCPY and -DHAVE_STRLCAT." + ) + add_definitions(-DHAVE_STRLCPY) + add_definitions(-DHAVE_STRLCAT) else() - message(STATUS "No strlcpy and strlcat found, will use local definition") + message(STATUS "No strlcpy and strlcat found, will use local definition") endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux") - include(driver) + include(driver) endif() include(libscap) include(libsinsp) diff --git a/cmake/modules/njson.cmake b/cmake/modules/njson.cmake index c83d48f2b62..7e29b8e7c33 100644 --- a/cmake/modules/njson.cmake +++ b/cmake/modules/njson.cmake @@ -2,25 +2,27 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # option(USE_BUNDLED_NLOHMANN_JSON "Enable building of the bundled nlohmann-json" ${USE_BUNDLED_DEPS}) if(USE_BUNDLED_NLOHMANN_JSON) - include(FetchContent) - FetchContent_Declare(nlohmann_json - URL https://github.com/nlohmann/json/archive/v3.11.3.tar.gz - URL_HASH SHA256=0d8ef5af7f9794e3263480193c491549b2ba6cc74bb018906202ada498a79406 - ) - FetchContent_MakeAvailable(nlohmann_json) + include(FetchContent) + FetchContent_Declare( + nlohmann_json + URL https://github.com/nlohmann/json/archive/v3.11.3.tar.gz + URL_HASH SHA256=0d8ef5af7f9794e3263480193c491549b2ba6cc74bb018906202ada498a79406 + ) + FetchContent_MakeAvailable(nlohmann_json) else() - find_package(nlohmann_json CONFIG REQUIRED) + find_package(nlohmann_json CONFIG REQUIRED) endif() diff --git a/cmake/modules/rules.cmake b/cmake/modules/rules.cmake index 292b50aba80..566cf2aeb67 100644 --- a/cmake/modules/rules.cmake +++ b/cmake/modules/rules.cmake @@ -2,39 +2,46 @@ # # Copyright (C) 2024 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 +# 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. +# 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(GNUInstallDirs) include(ExternalProject) if(NOT DEFINED FALCOSECURITY_RULES_FALCO_PATH) -# falco_rules.yaml -set(FALCOSECURITY_RULES_FALCO_VERSION "falco-rules-3.2.0") -set(FALCOSECURITY_RULES_FALCO_CHECKSUM "SHA256=b3990bf0209cfbf6a903b361e458a1f5851a9a5aeee808ad26a5ddbe1377157d") -set(FALCOSECURITY_RULES_FALCO_PATH "${PROJECT_BINARY_DIR}/falcosecurity-rules-falco-prefix/src/falcosecurity-rules-falco/falco_rules.yaml") -ExternalProject_Add( - falcosecurity-rules-falco - URL "https://download.falco.org/rules/${FALCOSECURITY_RULES_FALCO_VERSION}.tar.gz" - URL_HASH "${FALCOSECURITY_RULES_FALCO_CHECKSUM}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" -) + # falco_rules.yaml + set(FALCOSECURITY_RULES_FALCO_VERSION "falco-rules-3.2.0") + set(FALCOSECURITY_RULES_FALCO_CHECKSUM + "SHA256=b3990bf0209cfbf6a903b361e458a1f5851a9a5aeee808ad26a5ddbe1377157d" + ) + set(FALCOSECURITY_RULES_FALCO_PATH + "${PROJECT_BINARY_DIR}/falcosecurity-rules-falco-prefix/src/falcosecurity-rules-falco/falco_rules.yaml" + ) + ExternalProject_Add( + falcosecurity-rules-falco + URL "https://download.falco.org/rules/${FALCOSECURITY_RULES_FALCO_VERSION}.tar.gz" + URL_HASH "${FALCOSECURITY_RULES_FALCO_CHECKSUM}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) endif() if(NOT DEFINED FALCOSECURITY_RULES_LOCAL_PATH) -# falco_rules.local.yaml -set(FALCOSECURITY_RULES_LOCAL_PATH "${PROJECT_BINARY_DIR}/falcosecurity-rules-local-prefix/falco_rules.local.yaml") -file(WRITE "${FALCOSECURITY_RULES_LOCAL_PATH}" "# Your custom rules!\n") + # falco_rules.local.yaml + set(FALCOSECURITY_RULES_LOCAL_PATH + "${PROJECT_BINARY_DIR}/falcosecurity-rules-local-prefix/falco_rules.local.yaml" + ) + file(WRITE "${FALCOSECURITY_RULES_LOCAL_PATH}" "# Your custom rules!\n") endif() if(NOT DEFINED FALCO_ETC_DIR) @@ -46,34 +53,43 @@ if(WIN32 OR APPLE) endif() if(NOT DEFINED FALCO_RULES_DEST_FILENAME) - set(FALCO_RULES_DEST_FILENAME "falco_rules.yaml") - set(FALCO_LOCAL_RULES_DEST_FILENAME "falco_rules.local.yaml") + set(FALCO_RULES_DEST_FILENAME "falco_rules.yaml") + set(FALCO_LOCAL_RULES_DEST_FILENAME "falco_rules.local.yaml") endif() -if(DEFINED FALCO_COMPONENT) # Allow a slim version of Falco to be embedded in other projects, intentionally *not* installing all rulesets. - install( - FILES "${FALCOSECURITY_RULES_FALCO_PATH}" - COMPONENT "${FALCO_COMPONENT}" - DESTINATION "${FALCO_ETC_DIR}" - RENAME "${FALCO_RULES_DEST_FILENAME}") +if(DEFINED FALCO_COMPONENT) # Allow a slim version of Falco to be embedded in other projects, + # intentionally *not* installing all rulesets. + install( + FILES "${FALCOSECURITY_RULES_FALCO_PATH}" + COMPONENT "${FALCO_COMPONENT}" + DESTINATION "${FALCO_ETC_DIR}" + RENAME "${FALCO_RULES_DEST_FILENAME}" + ) - install( - FILES "${FALCOSECURITY_RULES_LOCAL_PATH}" - COMPONENT "${FALCO_COMPONENT}" - DESTINATION "${FALCO_ETC_DIR}" - RENAME "${FALCO_LOCAL_RULES_DEST_FILENAME}") + install( + FILES "${FALCOSECURITY_RULES_LOCAL_PATH}" + COMPONENT "${FALCO_COMPONENT}" + DESTINATION "${FALCO_ETC_DIR}" + RENAME "${FALCO_LOCAL_RULES_DEST_FILENAME}" + ) else() # Default Falco installation - install( - FILES "${FALCOSECURITY_RULES_FALCO_PATH}" - DESTINATION "${FALCO_ETC_DIR}" - RENAME "${FALCO_RULES_DEST_FILENAME}" - COMPONENT "${FALCO_COMPONENT_NAME}") + install( + FILES "${FALCOSECURITY_RULES_FALCO_PATH}" + DESTINATION "${FALCO_ETC_DIR}" + RENAME "${FALCO_RULES_DEST_FILENAME}" + COMPONENT "${FALCO_COMPONENT_NAME}" + ) - install( - FILES "${FALCOSECURITY_RULES_LOCAL_PATH}" - DESTINATION "${FALCO_ETC_DIR}" - RENAME "${FALCO_LOCAL_RULES_DEST_FILENAME}" - COMPONENT "${FALCO_COMPONENT_NAME}") + install( + FILES "${FALCOSECURITY_RULES_LOCAL_PATH}" + DESTINATION "${FALCO_ETC_DIR}" + RENAME "${FALCO_LOCAL_RULES_DEST_FILENAME}" + COMPONENT "${FALCO_COMPONENT_NAME}" + ) - install(DIRECTORY DESTINATION "${FALCO_ETC_DIR}/rules.d" COMPONENT "${FALCO_COMPONENT_NAME}") + install( + DIRECTORY + DESTINATION "${FALCO_ETC_DIR}/rules.d" + COMPONENT "${FALCO_COMPONENT_NAME}" + ) endif() diff --git a/cmake/modules/static-analysis.cmake b/cmake/modules/static-analysis.cmake index 8ecf6f2771d..0340b44a87b 100644 --- a/cmake/modules/static-analysis.cmake +++ b/cmake/modules/static-analysis.cmake @@ -2,14 +2,15 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # # create the reports folder @@ -22,35 +23,42 @@ find_program(CPPCHECK cppcheck) find_program(CPPCHECK_HTMLREPORT cppcheck-htmlreport) if(NOT CPPCHECK) - message(STATUS "cppcheck command not found, static code analysis using cppcheck will not be available.") + message( + STATUS + "cppcheck command not found, static code analysis using cppcheck will not be available." + ) else() - message(STATUS "cppcheck found at: ${CPPCHECK}") - # we are aware that cppcheck can be run - # along with the software compilation in a single step - # using the CMAKE_CXX_CPPCHECK variables. - # However, for practical needs we want to keep the - # two things separated and have a specific target for it. - # Our cppcheck target reads the compilation database produced by CMake - set(CMAKE_EXPORT_COMPILE_COMMANDS On) - add_custom_target( - cppcheck - COMMAND ${CPPCHECK} - "--enable=all" - "--force" - "--inconclusive" - "--inline-suppr" # allows to specify suppressions directly in source code - "--xml" # we want to generate a report - "--output-file=${CMAKE_CURRENT_BINARY_DIR}/static-analysis-reports/cppcheck/cppcheck.xml" # generate the report under the reports folder in the build folder - "-i${CMAKE_CURRENT_BINARY_DIR}"# exclude the build folder - "${CMAKE_SOURCE_DIR}" - ) + message(STATUS "cppcheck found at: ${CPPCHECK}") + # we are aware that cppcheck can be run along with the software compilation in a single step + # using the CMAKE_CXX_CPPCHECK variables. However, for practical needs we want to keep the two + # things separated and have a specific target for it. Our cppcheck target reads the compilation + # database produced by CMake + set(CMAKE_EXPORT_COMPILE_COMMANDS On) + add_custom_target( + cppcheck + COMMAND + ${CPPCHECK} "--enable=all" "--force" "--inconclusive" "--inline-suppr" # allows to + # specify suppressions directly in source code + "--xml" # we want to generate a report + "--output-file=${CMAKE_CURRENT_BINARY_DIR}/static-analysis-reports/cppcheck/cppcheck.xml" # generate + # the report under the reports folder in the build folder + "-i${CMAKE_CURRENT_BINARY_DIR}" # exclude the build folder + "${CMAKE_SOURCE_DIR}" + ) endif() # CPPCHECK if(NOT CPPCHECK_HTMLREPORT) - message(STATUS "cppcheck-htmlreport command not found, will not be able to produce html reports for cppcheck results") + message( + STATUS + "cppcheck-htmlreport command not found, will not be able to produce html reports for cppcheck results" + ) else() - message(STATUS "cppcheck-htmlreport found at: ${CPPCHECK_HTMLREPORT}") - add_custom_target( - cppcheck_htmlreport - COMMAND ${CPPCHECK_HTMLREPORT} --title=${CMAKE_PROJECT_NAME} --report-dir=${CMAKE_CURRENT_BINARY_DIR}/static-analysis-reports/cppcheck --file=static-analysis-reports/cppcheck/cppcheck.xml) + message(STATUS "cppcheck-htmlreport found at: ${CPPCHECK_HTMLREPORT}") + add_custom_target( + cppcheck_htmlreport + COMMAND + ${CPPCHECK_HTMLREPORT} --title=${CMAKE_PROJECT_NAME} + --report-dir=${CMAKE_CURRENT_BINARY_DIR}/static-analysis-reports/cppcheck + --file=static-analysis-reports/cppcheck/cppcheck.xml + ) endif() # CPPCHECK_HTMLREPORT diff --git a/cmake/modules/yaml-cpp.cmake b/cmake/modules/yaml-cpp.cmake index 92a2e9c07af..6795e58b388 100644 --- a/cmake/modules/yaml-cpp.cmake +++ b/cmake/modules/yaml-cpp.cmake @@ -2,25 +2,27 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # option(USE_BUNDLED_YAMLCPP "Enable building of the bundled yamlcpp" ${USE_BUNDLED_DEPS}) if(USE_BUNDLED_YAMLCPP) - include(FetchContent) - FetchContent_Declare(yamlcpp - URL https://github.com/jbeder/yaml-cpp/archive/refs/tags/0.8.0.tar.gz - URL_HASH SHA256=fbe74bbdcee21d656715688706da3c8becfd946d92cd44705cc6098bb23b3a16 - ) - FetchContent_MakeAvailable(yamlcpp) + include(FetchContent) + FetchContent_Declare( + yamlcpp + URL https://github.com/jbeder/yaml-cpp/archive/refs/tags/0.8.0.tar.gz + URL_HASH SHA256=fbe74bbdcee21d656715688706da3c8becfd946d92cd44705cc6098bb23b3a16 + ) + FetchContent_MakeAvailable(yamlcpp) else() - find_package(yaml-cpp CONFIG REQUIRED) + find_package(yaml-cpp CONFIG REQUIRED) endif() diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 004f7148e3f..109cbae87a4 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -2,35 +2,44 @@ # # Copyright (C) 2023 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 # -# 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 # -# 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. +# 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. # if(CMAKE_SYSTEM_NAME MATCHES "Linux") # Systemd file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/scripts/systemd) - configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod-inject.service" - "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY) - configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod.service" - "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY) - configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-bpf.service" - "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY) - configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-modern-bpf.service" - "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY) - configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-custom.service" - "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY) - configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falcoctl-artifact-follow.service" - "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY) + configure_file( + "${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod-inject.service" + "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY + ) + configure_file( + "${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod.service" + "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY + ) + configure_file( + "${PROJECT_SOURCE_DIR}/scripts/systemd/falco-bpf.service" + "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY + ) + configure_file( + "${PROJECT_SOURCE_DIR}/scripts/systemd/falco-modern-bpf.service" + "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY + ) + configure_file( + "${PROJECT_SOURCE_DIR}/scripts/systemd/falco-custom.service" + "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY + ) + configure_file( + "${PROJECT_SOURCE_DIR}/scripts/systemd/falcoctl-artifact-follow.service" + "${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY + ) # Debian configure_file(debian/postinst.in debian/postinst COPYONLY) @@ -44,21 +53,32 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") endif() # Install Falcoctl config file -if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT MUSL_OPTIMIZED_BUILD) +if(NOT WIN32 + AND NOT APPLE + AND NOT EMSCRIPTEN + AND NOT MUSL_OPTIMIZED_BUILD +) if(NOT DEFINED FALCOCTL_ETC_DIR) set(FALCOCTL_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falcoctl") - endif() - set(FALCOCTL_DRIVER_TYPES_LIST "") - if (BUILD_FALCO_MODERN_BPF) + endif() + set(FALCOCTL_DRIVER_TYPES_LIST "") + if(BUILD_FALCO_MODERN_BPF) list(APPEND FALCOCTL_DRIVER_TYPES_LIST "modern_ebpf") endif() - if (BUILD_DRIVER) + if(BUILD_DRIVER) list(APPEND FALCOCTL_DRIVER_TYPES_LIST "kmod") endif() - if (BUILD_BPF) + if(BUILD_BPF) list(APPEND FALCOCTL_DRIVER_TYPES_LIST "ebpf") endif() string(REPLACE ";" ", " FALCOCTL_DRIVER_TYPES "${FALCOCTL_DRIVER_TYPES_LIST}") - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/falcoctl/falcoctl.yaml.in ${PROJECT_BINARY_DIR}/scripts/falcoctl/falcoctl.yaml) - install(FILES ${PROJECT_BINARY_DIR}/scripts/falcoctl/falcoctl.yaml DESTINATION "${FALCOCTL_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}") + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/falcoctl/falcoctl.yaml.in + ${PROJECT_BINARY_DIR}/scripts/falcoctl/falcoctl.yaml + ) + install( + FILES ${PROJECT_BINARY_DIR}/scripts/falcoctl/falcoctl.yaml + DESTINATION "${FALCOCTL_ETC_DIR}" + COMPONENT "${FALCO_COMPONENT_NAME}" + ) endif() diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index 7c7ce65f5e8..dc96ca3ae21 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -2,14 +2,15 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # message(STATUS "Falco unit tests build enabled") @@ -17,72 +18,72 @@ message(STATUS "Falco unit tests build enabled") include(FetchContent) FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.14.0 + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.14.0 ) FetchContent_MakeAvailable(googletest) -# Create a libscap_test_var.h file with some variables used by our tests -# for example the kmod path or the bpf path. -configure_file ( - ${CMAKE_CURRENT_SOURCE_DIR}/falco_test_var.h.in - ${CMAKE_CURRENT_BINARY_DIR}/falco_test_var.h +# Create a libscap_test_var.h file with some variables used by our tests for example the kmod path +# or the bpf path. +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/falco_test_var.h.in ${CMAKE_CURRENT_BINARY_DIR}/falco_test_var.h ) -add_executable(falco_unit_tests - test_falco_engine.cpp - engine/test_add_source.cpp - engine/test_alt_rule_loader.cpp - engine/test_enable_rule.cpp - engine/test_extra_output.cpp - engine/test_falco_utils.cpp - engine/test_filter_details_resolver.cpp - engine/test_filter_macro_resolver.cpp - engine/test_filter_warning_resolver.cpp - engine/test_plugin_requirements.cpp - engine/test_rule_loader.cpp - engine/test_rulesets.cpp - falco/test_configuration.cpp - falco/test_configuration_rule_selection.cpp - falco/test_configuration_config_files.cpp - falco/test_configuration_env_vars.cpp - falco/test_configuration_output_options.cpp - falco/test_configuration_schema.cpp - falco/app/actions/test_select_event_sources.cpp - falco/app/actions/test_load_config.cpp +add_executable( + falco_unit_tests + test_falco_engine.cpp + engine/test_add_source.cpp + engine/test_alt_rule_loader.cpp + engine/test_enable_rule.cpp + engine/test_extra_output.cpp + engine/test_falco_utils.cpp + engine/test_filter_details_resolver.cpp + engine/test_filter_macro_resolver.cpp + engine/test_filter_warning_resolver.cpp + engine/test_plugin_requirements.cpp + engine/test_rule_loader.cpp + engine/test_rulesets.cpp + falco/test_configuration.cpp + falco/test_configuration_rule_selection.cpp + falco/test_configuration_config_files.cpp + falco/test_configuration_env_vars.cpp + falco/test_configuration_output_options.cpp + falco/test_configuration_schema.cpp + falco/app/actions/test_select_event_sources.cpp + falco/app/actions/test_load_config.cpp ) -if (CMAKE_SYSTEM_NAME MATCHES "Linux") - target_sources(falco_unit_tests - PRIVATE - falco/test_atomic_signal_handler.cpp - falco/app/actions/test_configure_interesting_sets.cpp - falco/app/actions/test_configure_syscall_buffer_num.cpp - ) +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + target_sources( + falco_unit_tests + PRIVATE falco/test_atomic_signal_handler.cpp + falco/app/actions/test_configure_interesting_sets.cpp + falco/app/actions/test_configure_syscall_buffer_num.cpp + ) endif() -target_include_directories(falco_unit_tests -PRIVATE - ${CMAKE_SOURCE_DIR}/userspace - ${CMAKE_BINARY_DIR}/userspace/falco # we need it to include indirectly `config_falco.h` file - ${CMAKE_SOURCE_DIR}/userspace/engine # we need it to include indirectly `falco_common.h` file - ${CMAKE_CURRENT_BINARY_DIR} # we need it to include `falco_test_var.h` +target_include_directories( + falco_unit_tests + PRIVATE ${CMAKE_SOURCE_DIR}/userspace + ${CMAKE_BINARY_DIR}/userspace/falco # we need it to include indirectly `config_falco.h` + # file + ${CMAKE_SOURCE_DIR}/userspace/engine # we need it to include indirectly `falco_common.h` + # file + ${CMAKE_CURRENT_BINARY_DIR} # we need it to include `falco_test_var.h` ) get_target_property(FALCO_APPLICATION_LIBRARIES falco_application LINK_LIBRARIES) -target_link_libraries(falco_unit_tests - falco_application - GTest::gtest - GTest::gtest_main - ${FALCO_APPLICATION_LIBRARIES} +target_link_libraries( + falco_unit_tests falco_application GTest::gtest GTest::gtest_main + ${FALCO_APPLICATION_LIBRARIES} ) -if (EMSCRIPTEN) +if(EMSCRIPTEN) target_compile_options(falco_unit_tests PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0") target_link_options(falco_unit_tests PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0") - target_link_options(falco_unit_tests PRIVATE "-sALLOW_MEMORY_GROWTH=1") + target_link_options(falco_unit_tests PRIVATE "-sALLOW_MEMORY_GROWTH=1") target_link_options(falco_unit_tests PRIVATE "-sEXPORTED_FUNCTIONS=['_main','_htons','_ntohs']") endif() diff --git a/unit_tests/engine/test_add_source.cpp b/unit_tests/engine/test_add_source.cpp index 88a77a562cb..74c82d240ed 100644 --- a/unit_tests/engine/test_add_source.cpp +++ b/unit_tests/engine/test_add_source.cpp @@ -26,36 +26,30 @@ static std::string syscall_source_name = "syscall"; // for the underlying ruleset. This allows testing of // ruleset_for_source -namespace -{ -class test_ruleset_factory : public evttype_index_ruleset_factory -{ +namespace { +class test_ruleset_factory : public evttype_index_ruleset_factory { public: explicit test_ruleset_factory(std::shared_ptr factory): - evttype_index_ruleset_factory(factory) - { + evttype_index_ruleset_factory(factory) { ruleset = evttype_index_ruleset_factory::new_ruleset(); } virtual ~test_ruleset_factory() = default; - inline std::shared_ptr new_ruleset() override - { - return ruleset; - } + inline std::shared_ptr new_ruleset() override { return ruleset; } std::shared_ptr ruleset; }; -}; // namespace +}; // namespace -TEST(AddSource, basic) -{ +TEST(AddSource, basic) { falco_engine engine; sinsp inspector; sinsp_filter_check_list filterchecks; auto filter_factory = std::make_shared(&inspector, filterchecks); - auto formatter_factory = std::make_shared(&inspector, filterchecks); + auto formatter_factory = + std::make_shared(&inspector, filterchecks); auto ruleset_factory = std::make_shared(filter_factory); falco_source syscall_source; @@ -66,9 +60,9 @@ TEST(AddSource, basic) syscall_source.formatter_factory = formatter_factory; size_t source_idx = engine.add_source(syscall_source_name, - filter_factory, - formatter_factory, - ruleset_factory); + filter_factory, + formatter_factory, + ruleset_factory); ASSERT_TRUE(engine.is_source_valid(syscall_source_name)); diff --git a/unit_tests/engine/test_alt_rule_loader.cpp b/unit_tests/engine/test_alt_rule_loader.cpp index 38f3d72544d..a6eae9e89cb 100644 --- a/unit_tests/engine/test_alt_rule_loader.cpp +++ b/unit_tests/engine/test_alt_rule_loader.cpp @@ -32,42 +32,35 @@ limitations under the License. #include "rule_loader_collector.h" #include "rule_loader_compiler.h" -namespace -{ +namespace { -struct test_object_info -{ +struct test_object_info { std::string name; std::string property; }; -struct test_compile_output : public rule_loader::compile_output -{ +struct test_compile_output : public rule_loader::compile_output { test_compile_output() = default; ~test_compile_output() = default; std::set defined_test_properties; }; -class test_compiler : public rule_loader::compiler -{ +class test_compiler : public rule_loader::compiler { public: test_compiler() = default; virtual ~test_compiler() = default; - std::unique_ptr new_compile_output() override - { + std::unique_ptr new_compile_output() override { return std::make_unique(); } - void compile( - rule_loader::configuration& cfg, - const rule_loader::collector& col, - rule_loader::compile_output& out) const override; + void compile(rule_loader::configuration& cfg, + const rule_loader::collector& col, + rule_loader::compile_output& out) const override; }; -class test_collector : public rule_loader::collector -{ +class test_collector : public rule_loader::collector { public: test_collector() = default; virtual ~test_collector() = default; @@ -75,32 +68,27 @@ class test_collector : public rule_loader::collector indexed_vector test_object_infos; }; -class test_reader : public rule_loader::reader -{ +class test_reader : public rule_loader::reader { public: test_reader() = default; virtual ~test_reader() = default; protected: rule_loader::context create_context(const YAML::Node& item, - const rule_loader::context& parent) - { + const rule_loader::context& parent) { return rule_loader::context(item, - rule_loader::context::EXTENSION_ITEM, - "test object", - parent); + rule_loader::context::EXTENSION_ITEM, + "test object", + parent); }; void read_item(rule_loader::configuration& cfg, - rule_loader::collector& collector, - const YAML::Node& item, - const rule_loader::context& parent) override - { - test_collector& test_col = - dynamic_cast(collector); - - if(item["test_object"].IsDefined()) - { + rule_loader::collector& collector, + const YAML::Node& item, + const rule_loader::context& parent) override { + test_collector& test_col = dynamic_cast(collector); + + if(item["test_object"].IsDefined()) { rule_loader::context tmp = create_context(item, parent); test_object_info obj; std::string name; @@ -113,37 +101,29 @@ class test_reader : public rule_loader::reader obj.property = property; test_col.test_object_infos.insert(obj, obj.name); - } - else - { + } else { rule_loader::reader::read_item(cfg, collector, item, parent); } }; }; -class test_ruleset : public evttype_index_ruleset -{ +class test_ruleset : public evttype_index_ruleset { public: explicit test_ruleset(std::shared_ptr factory): - evttype_index_ruleset(factory){}; + evttype_index_ruleset(factory) {}; virtual ~test_ruleset() = default; - void add_compile_output( - const rule_loader::compile_output& compile_output, - falco_common::priority_type min_priority, - const std::string& source) - { - - evttype_index_ruleset::add_compile_output(compile_output, - min_priority, - source); + void add_compile_output(const rule_loader::compile_output& compile_output, + falco_common::priority_type min_priority, + const std::string& source) { + evttype_index_ruleset::add_compile_output(compile_output, min_priority, source); std::shared_ptr ruleset; get_engine_state().get_ruleset(source, ruleset); EXPECT_EQ(this, ruleset.get()); const test_compile_output& test_output = - dynamic_cast(compile_output); + dynamic_cast(compile_output); defined_properties = test_output.defined_test_properties; }; @@ -151,40 +131,31 @@ class test_ruleset : public evttype_index_ruleset std::set defined_properties; }; -class test_ruleset_factory : public filter_ruleset_factory -{ +class test_ruleset_factory : public filter_ruleset_factory { public: explicit test_ruleset_factory(std::shared_ptr factory): - m_filter_factory(factory) - { - } + m_filter_factory(factory) {} virtual ~test_ruleset_factory() = default; - inline std::shared_ptr new_ruleset() override - { + inline std::shared_ptr new_ruleset() override { return std::make_shared(m_filter_factory); } std::shared_ptr m_filter_factory; }; -}; // namespace +}; // namespace -void test_compiler::compile( - rule_loader::configuration& cfg, - const rule_loader::collector& col, - rule_loader::compile_output& out) const -{ +void test_compiler::compile(rule_loader::configuration& cfg, + const rule_loader::collector& col, + rule_loader::compile_output& out) const { rule_loader::compiler::compile(cfg, col, out); - const test_collector& test_col = - dynamic_cast(col); + const test_collector& test_col = dynamic_cast(col); - test_compile_output& test_output = - dynamic_cast(out); + test_compile_output& test_output = dynamic_cast(out); - for(auto& test_obj : test_col.test_object_infos) - { + for(auto& test_obj : test_col.test_object_infos) { test_output.defined_test_properties.insert(test_obj.property); } } @@ -230,12 +201,13 @@ static std::string content = R"END( static std::string syscall_source_name = "syscall"; -static std::shared_ptr create_configuration(sinsp& inspector, - sinsp_filter_check_list& filterchecks, - indexed_vector& sources) -{ +static std::shared_ptr create_configuration( + sinsp& inspector, + sinsp_filter_check_list& filterchecks, + indexed_vector& sources) { auto filter_factory = std::make_shared(&inspector, filterchecks); - auto formatter_factory = std::make_shared(&inspector, filterchecks); + auto formatter_factory = + std::make_shared(&inspector, filterchecks); auto ruleset_factory = std::make_shared(filter_factory); falco_source syscall_source; @@ -247,17 +219,15 @@ static std::shared_ptr create_configuration(sinsp& i sources.insert(syscall_source, syscall_source_name); - return std::make_shared(content, - sources, - "test configuration"); + return std::make_shared(content, sources, "test configuration"); } static void load_rules(sinsp& inspector, - sinsp_filter_check_list& filterchecks, - std::unique_ptr& compile_output, - indexed_vector& sources) -{ - std::shared_ptr cfg = create_configuration(inspector, filterchecks, sources); + sinsp_filter_check_list& filterchecks, + std::unique_ptr& compile_output, + indexed_vector& sources) { + std::shared_ptr cfg = + create_configuration(inspector, filterchecks, sources); rule_loader::reader reader; rule_loader::collector collector; @@ -270,8 +240,7 @@ static void load_rules(sinsp& inspector, compiler.compile(*cfg, collector, *compile_output); } -TEST(engine_loader_alt_loader, load_rules) -{ +TEST(engine_loader_alt_loader, load_rules) { sinsp inspector; sinsp_filter_check_list filterchecks; std::unique_ptr compile_output; @@ -292,8 +261,7 @@ TEST(engine_loader_alt_loader, load_rules) EXPECT_TRUE(compile_output->rules.at("test debug rule") != nullptr); } -TEST(engine_loader_alt_loader, pass_compile_output_to_ruleset) -{ +TEST(engine_loader_alt_loader, pass_compile_output_to_ruleset) { sinsp inspector; sinsp_filter_check_list filterchecks; std::unique_ptr compile_output; @@ -304,8 +272,8 @@ TEST(engine_loader_alt_loader, pass_compile_output_to_ruleset) std::shared_ptr ruleset = sources.at(syscall_source_name)->ruleset; ruleset->add_compile_output(*compile_output, - falco_common::PRIORITY_INFORMATIONAL, - syscall_source_name); + falco_common::PRIORITY_INFORMATIONAL, + syscall_source_name); // Enable all rules for a ruleset id. Because the compile // output contained one rule with priority >= INFO, that rule @@ -316,14 +284,14 @@ TEST(engine_loader_alt_loader, pass_compile_output_to_ruleset) EXPECT_EQ(ruleset->enabled_count(ruleset_id), 1); } -TEST(engine_loader_alt_loader, falco_engine_alternate_loader) -{ +TEST(engine_loader_alt_loader, falco_engine_alternate_loader) { falco_engine engine; sinsp inspector; sinsp_filter_check_list filterchecks; auto filter_factory = std::make_shared(&inspector, filterchecks); - auto formatter_factory = std::make_shared(&inspector, filterchecks); + auto formatter_factory = + std::make_shared(&inspector, filterchecks); auto ruleset_factory = std::make_shared(filter_factory); engine.add_source(syscall_source_name, filter_factory, formatter_factory, ruleset_factory); @@ -345,7 +313,8 @@ TEST(engine_loader_alt_loader, falco_engine_alternate_loader) EXPECT_EQ(collector->test_object_infos.size(), 2); std::shared_ptr ruleset = engine.ruleset_for_source(syscall_source_name); - std::set& defined_properties = std::dynamic_pointer_cast(ruleset)->defined_properties; + std::set& defined_properties = + std::dynamic_pointer_cast(ruleset)->defined_properties; EXPECT_TRUE(defined_properties.find("my-value") != defined_properties.end()); EXPECT_TRUE(defined_properties.find("other-value") != defined_properties.end()); diff --git a/unit_tests/engine/test_enable_rule.cpp b/unit_tests/engine/test_enable_rule.cpp index d28f53101dd..4d6f8c6f5b9 100644 --- a/unit_tests/engine/test_enable_rule.cpp +++ b/unit_tests/engine/test_enable_rule.cpp @@ -72,8 +72,6 @@ static std::string multi_rule = R"END( tags: [exec] )END"; - - // This must be kept in line with the (private) falco_engine::s_default_ruleset static const std::string default_ruleset = "falco-default-ruleset"; @@ -82,8 +80,7 @@ static const std::string ruleset_2 = "ruleset-2"; static const std::string ruleset_3 = "ruleset-3"; static const std::string ruleset_4 = "ruleset-4"; -TEST_F(test_falco_engine, enable_rule_name) -{ +TEST_F(test_falco_engine, enable_rule_name) { load_rules(single_rule, "single_rule.yaml"); // No rules should be enabled yet for any custom rulesets @@ -119,8 +116,7 @@ TEST_F(test_falco_engine, enable_rule_name) EXPECT_EQ(2, m_engine->num_rules_for_ruleset(ruleset_3)); } -TEST_F(test_falco_engine, enable_rule_tags) -{ +TEST_F(test_falco_engine, enable_rule_tags) { std::set process_tags = {"process"}; load_rules(single_rule, "single_rule.yaml"); @@ -147,8 +143,7 @@ TEST_F(test_falco_engine, enable_rule_tags) EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2)); } -TEST_F(test_falco_engine, enable_disabled_rule_by_tag) -{ +TEST_F(test_falco_engine, enable_disabled_rule_by_tag) { std::set exec_process_tags = {"exec process"}; load_rules(single_rule, "single_rule.yaml"); @@ -163,8 +158,7 @@ TEST_F(test_falco_engine, enable_disabled_rule_by_tag) EXPECT_EQ(2, m_engine->num_rules_for_ruleset(default_ruleset)); } -TEST_F(test_falco_engine, enable_rule_id) -{ +TEST_F(test_falco_engine, enable_rule_id) { uint16_t ruleset_1_id; uint16_t ruleset_2_id; uint16_t ruleset_3_id; @@ -204,8 +198,7 @@ TEST_F(test_falco_engine, enable_rule_id) EXPECT_EQ(2, m_engine->num_rules_for_ruleset(ruleset_3)); } -TEST_F(test_falco_engine, enable_rule_name_exact) -{ +TEST_F(test_falco_engine, enable_rule_name_exact) { load_rules(single_rule, "single_rule.yaml"); EXPECT_EQ(1, m_engine->num_rules_for_ruleset(default_ruleset)); @@ -247,8 +240,7 @@ TEST_F(test_falco_engine, enable_rule_name_exact) EXPECT_EQ(2, m_engine->num_rules_for_ruleset(ruleset_4)); } -TEST_F(test_falco_engine, enable_rule_name_wildcard) -{ +TEST_F(test_falco_engine, enable_rule_name_wildcard) { load_rules(multi_rule, "multi_rule.yaml"); EXPECT_EQ(1, m_engine->num_rules_for_ruleset(default_ruleset)); @@ -283,4 +275,3 @@ TEST_F(test_falco_engine, enable_rule_name_wildcard) EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_3)); EXPECT_EQ(3, m_engine->num_rules_for_ruleset(ruleset_4)); } - diff --git a/unit_tests/engine/test_extra_output.cpp b/unit_tests/engine/test_extra_output.cpp index a2480a6a706..e62d29473de 100644 --- a/unit_tests/engine/test_extra_output.cpp +++ b/unit_tests/engine/test_extra_output.cpp @@ -19,8 +19,7 @@ limitations under the License. #include "../test_falco_engine.h" -TEST_F(test_falco_engine, extra_format_all) -{ +TEST_F(test_falco_engine, extra_format_all) { std::string rules_content = R"END( - rule: legit_rule desc: legit rule description @@ -32,11 +31,11 @@ TEST_F(test_falco_engine, extra_format_all) m_engine->add_extra_output_format("evt.type=%evt.type", "", {}, "", false); ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; - EXPECT_EQ(get_compiled_rule_output("legit_rule"),"user=%user.name command=%proc.cmdline file=%fd.name evt.type=%evt.type"); + EXPECT_EQ(get_compiled_rule_output("legit_rule"), + "user=%user.name command=%proc.cmdline file=%fd.name evt.type=%evt.type"); } -TEST_F(test_falco_engine, extra_format_by_rule) -{ +TEST_F(test_falco_engine, extra_format_by_rule) { std::string rules_content = R"END( - rule: legit_rule desc: legit rule description @@ -54,12 +53,11 @@ TEST_F(test_falco_engine, extra_format_by_rule) m_engine->add_extra_output_format("evt.type=%evt.type", "", {}, "legit_rule", false); ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; - EXPECT_EQ(get_compiled_rule_output("legit_rule"),"out 1 evt.type=%evt.type"); - EXPECT_EQ(get_compiled_rule_output("another_rule"),"out 2"); + EXPECT_EQ(get_compiled_rule_output("legit_rule"), "out 1 evt.type=%evt.type"); + EXPECT_EQ(get_compiled_rule_output("another_rule"), "out 2"); } -TEST_F(test_falco_engine, extra_format_by_tag_rule) -{ +TEST_F(test_falco_engine, extra_format_by_tag_rule) { std::string rules_content = R"END( - rule: legit_rule desc: legit rule description @@ -89,13 +87,12 @@ TEST_F(test_falco_engine, extra_format_by_tag_rule) ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; - EXPECT_EQ(get_compiled_rule_output("legit_rule"),"out 1 extra 1"); - EXPECT_EQ(get_compiled_rule_output("another_rule"),"out 2 extra 1 extra 2"); - EXPECT_EQ(get_compiled_rule_output("a_third_rule"),"out 3 extra 1 extra 3"); + EXPECT_EQ(get_compiled_rule_output("legit_rule"), "out 1 extra 1"); + EXPECT_EQ(get_compiled_rule_output("another_rule"), "out 2 extra 1 extra 2"); + EXPECT_EQ(get_compiled_rule_output("a_third_rule"), "out 3 extra 1 extra 3"); } -TEST_F(test_falco_engine, extra_format_replace_container_info) -{ +TEST_F(test_falco_engine, extra_format_replace_container_info) { std::string rules_content = R"END( - rule: legit_rule desc: legit rule description @@ -120,8 +117,7 @@ TEST_F(test_falco_engine, extra_format_replace_container_info) EXPECT_EQ(get_compiled_rule_output("another_rule"), "out 2 extra 1"); } -TEST_F(test_falco_engine, extra_format_do_not_replace_container_info) -{ +TEST_F(test_falco_engine, extra_format_do_not_replace_container_info) { std::string rules_content = R"END( - rule: legit_rule desc: legit rule description @@ -130,15 +126,14 @@ TEST_F(test_falco_engine, extra_format_do_not_replace_container_info) priority: INFO tags: [tag1] )END"; - + ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; auto output = get_compiled_rule_output("legit_rule"); EXPECT_TRUE(output.find("%container.info") == output.npos); } -TEST_F(test_falco_engine, extra_fields_all) -{ +TEST_F(test_falco_engine, extra_fields_all) { std::string rules_content = R"END( - rule: legit_rule desc: legit rule description @@ -147,11 +142,11 @@ TEST_F(test_falco_engine, extra_fields_all) priority: INFO )END"; - std::unordered_map extra_formatted_fields = {{"my_field", "hello %evt.num"}}; - for (auto const& f : extra_formatted_fields) - { - m_engine->add_extra_output_formatted_field(f.first, f.second, "", {}, ""); - } + std::unordered_map extra_formatted_fields = { + {"my_field", "hello %evt.num"}}; + for(auto const& f : extra_formatted_fields) { + m_engine->add_extra_output_formatted_field(f.first, f.second, "", {}, ""); + } ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; diff --git a/unit_tests/engine/test_falco_utils.cpp b/unit_tests/engine/test_falco_utils.cpp index 0fcfe5d64cd..50a9dedc2cf 100644 --- a/unit_tests/engine/test_falco_utils.cpp +++ b/unit_tests/engine/test_falco_utils.cpp @@ -18,8 +18,7 @@ limitations under the License. #include #include -TEST(FalcoUtils, is_unix_scheme) -{ +TEST(FalcoUtils, is_unix_scheme) { /* Wrong prefix */ ASSERT_EQ(falco::utils::network::is_unix_scheme("something:///run/falco/falco.sock"), false); @@ -38,15 +37,14 @@ TEST(FalcoUtils, is_unix_scheme) ASSERT_EQ(falco::utils::network::is_unix_scheme(url_char), true); } -TEST(FalcoUtils, parse_prometheus_interval) -{ +TEST(FalcoUtils, parse_prometheus_interval) { /* Test matrix around correct time conversions. */ ASSERT_EQ(falco::utils::parse_prometheus_interval("1ms"), 1UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1s"), 1000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1m"), 60000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1h"), 3600000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1d"), 86400000UL); - ASSERT_EQ(falco::utils::parse_prometheus_interval("1w"), 604800000UL); + ASSERT_EQ(falco::utils::parse_prometheus_interval("1w"), 604800000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1y"), (unsigned long)31536000000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("300ms"), 300UL); @@ -57,8 +55,11 @@ TEST(FalcoUtils, parse_prometheus_interval) ASSERT_EQ(falco::utils::parse_prometheus_interval("60m"), 3600000UL); /* Test matrix for concatenated time interval examples. */ - ASSERT_EQ(falco::utils::parse_prometheus_interval("1h3m2s1ms"), 3600000UL + 3 * 60000UL + 2 * 1000UL + 1UL); - ASSERT_EQ(falco::utils::parse_prometheus_interval("1y1w1d1h1m1s1ms"),(unsigned long) 31536000000UL + 604800000UL + 86400000UL + 3600000UL + 60000UL + 1000UL + 1UL); + ASSERT_EQ(falco::utils::parse_prometheus_interval("1h3m2s1ms"), + 3600000UL + 3 * 60000UL + 2 * 1000UL + 1UL); + ASSERT_EQ(falco::utils::parse_prometheus_interval("1y1w1d1h1m1s1ms"), + (unsigned long)31536000000UL + 604800000UL + 86400000UL + 3600000UL + 60000UL + + 1000UL + 1UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("2h5m"), 2 * 3600000UL + 5 * 60000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("2h 5m"), 2 * 3600000UL + 5 * 60000UL); @@ -73,16 +74,16 @@ TEST(FalcoUtils, parse_prometheus_interval) ASSERT_EQ(falco::utils::parse_prometheus_interval("200"), 0UL); } -TEST(FalcoUtils, sanitize_rule_name) -{ - ASSERT_EQ(falco::utils::sanitize_rule_name("Testing rule 2 (CVE-2244)"), "Testing_rule_2_CVE_2244"); +TEST(FalcoUtils, sanitize_rule_name) { + ASSERT_EQ(falco::utils::sanitize_rule_name("Testing rule 2 (CVE-2244)"), + "Testing_rule_2_CVE_2244"); ASSERT_EQ(falco::utils::sanitize_rule_name("Testing rule__:2)"), "Testing_rule_:2"); ASSERT_EQ(falco::utils::sanitize_rule_name("This@is_a$test rule123"), "This_is_a_test_rule123"); - ASSERT_EQ(falco::utils::sanitize_rule_name("RULEwith:special#characters"), "RULEwith:special_characters"); + ASSERT_EQ(falco::utils::sanitize_rule_name("RULEwith:special#characters"), + "RULEwith:special_characters"); } -TEST(FalcoUtils, matches_wildcard) -{ +TEST(FalcoUtils, matches_wildcard) { ASSERT_TRUE(falco::utils::matches_wildcard("*", "anything")); ASSERT_TRUE(falco::utils::matches_wildcard("**", "anything")); ASSERT_TRUE(falco::utils::matches_wildcard("*", "")); diff --git a/unit_tests/engine/test_filter_details_resolver.cpp b/unit_tests/engine/test_filter_details_resolver.cpp index 28366ded0e6..40b8d5d7a99 100644 --- a/unit_tests/engine/test_filter_details_resolver.cpp +++ b/unit_tests/engine/test_filter_details_resolver.cpp @@ -18,33 +18,33 @@ limitations under the License. #include #include - -TEST(DetailsResolver, resolve_ast) -{ - std::string cond = "(spawned_process or evt.type = open) and (proc.name icontains cat or proc.name in (known_procs, ps))"; - auto ast = libsinsp::filter::parser(cond).parse(); - filter_details details; - details.known_macros.insert("spawned_process"); - details.known_lists.insert("known_procs"); - filter_details_resolver resolver; - resolver.run(ast.get(), details); - - // Assert fields - ASSERT_EQ(details.fields.size(), 2); - ASSERT_NE(details.fields.find("evt.type"), details.fields.end()); - ASSERT_NE(details.fields.find("proc.name"), details.fields.end()); - - // Assert macros - ASSERT_EQ(details.macros.size(), 1); - ASSERT_NE(details.macros.find("spawned_process"), details.macros.end()); - - // Assert operators - ASSERT_EQ(details.operators.size(), 3); - ASSERT_NE(details.operators.find("="), details.operators.end()); - ASSERT_NE(details.operators.find("icontains"), details.operators.end()); - ASSERT_NE(details.operators.find("in"), details.operators.end()); - - // Assert lists - ASSERT_EQ(details.lists.size(), 1); - ASSERT_NE(details.lists.find("known_procs"), details.lists.end()); +TEST(DetailsResolver, resolve_ast) { + std::string cond = + "(spawned_process or evt.type = open) and (proc.name icontains cat or proc.name in " + "(known_procs, ps))"; + auto ast = libsinsp::filter::parser(cond).parse(); + filter_details details; + details.known_macros.insert("spawned_process"); + details.known_lists.insert("known_procs"); + filter_details_resolver resolver; + resolver.run(ast.get(), details); + + // Assert fields + ASSERT_EQ(details.fields.size(), 2); + ASSERT_NE(details.fields.find("evt.type"), details.fields.end()); + ASSERT_NE(details.fields.find("proc.name"), details.fields.end()); + + // Assert macros + ASSERT_EQ(details.macros.size(), 1); + ASSERT_NE(details.macros.find("spawned_process"), details.macros.end()); + + // Assert operators + ASSERT_EQ(details.operators.size(), 3); + ASSERT_NE(details.operators.find("="), details.operators.end()); + ASSERT_NE(details.operators.find("icontains"), details.operators.end()); + ASSERT_NE(details.operators.find("in"), details.operators.end()); + + // Assert lists + ASSERT_EQ(details.lists.size(), 1); + ASSERT_NE(details.lists.find("known_procs"), details.lists.end()); } diff --git a/unit_tests/engine/test_filter_macro_resolver.cpp b/unit_tests/engine/test_filter_macro_resolver.cpp index 3e2a1880b04..85692de2659 100644 --- a/unit_tests/engine/test_filter_macro_resolver.cpp +++ b/unit_tests/engine/test_filter_macro_resolver.cpp @@ -21,33 +21,37 @@ limitations under the License. namespace filter_ast = libsinsp::filter::ast; static std::vector::const_iterator find_value( - const std::vector& values, - const std::string& ref) -{ + const std::vector& values, + const std::string& ref) { return std::find_if( - values.begin(), - values.end(), - [&ref](const filter_macro_resolver::value_info& v) - { return v.first == ref; }); + values.begin(), + values.end(), + [&ref](const filter_macro_resolver::value_info& v) { return v.first == ref; }); } #define MACRO_NAME "test_macro" #define MACRO_A_NAME "test_macro_1" #define MACRO_B_NAME "test_macro_2" -TEST(MacroResolver, should_resolve_macros_on_a_filter_AST) -{ +TEST(MacroResolver, should_resolve_macros_on_a_filter_AST) { filter_ast::pos_info macro_pos(12, 85, 27); - std::shared_ptr macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), "exists"); + std::shared_ptr macro = + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), + "exists"); std::vector> filter_and; - filter_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("evt.name", ""), "exists")); - filter_and.push_back(filter_ast::not_expr::create(filter_ast::identifier_expr::create(MACRO_NAME, macro_pos))); + filter_and.push_back( + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("evt.name", ""), + "exists")); + filter_and.push_back(filter_ast::not_expr::create( + filter_ast::identifier_expr::create(MACRO_NAME, macro_pos))); std::shared_ptr filter = filter_ast::and_expr::create(filter_and); std::vector> expected_and; - expected_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("evt.name", ""), "exists")); + expected_and.push_back( + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("evt.name", ""), + "exists")); expected_and.push_back(filter_ast::not_expr::create(clone(macro.get()))); std::shared_ptr expected = filter_ast::and_expr::create(expected_and); @@ -69,13 +73,15 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST) ASSERT_TRUE(filter->is_equal(expected.get())); } -TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_single_node) -{ +TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_single_node) { filter_ast::pos_info macro_pos(12, 85, 27); - std::shared_ptr macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), "exists"); + std::shared_ptr macro = + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), + "exists"); - std::shared_ptr filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos); + std::shared_ptr filter = + filter_ast::identifier_expr::create(MACRO_NAME, macro_pos); filter_macro_resolver resolver; resolver.set_macro(MACRO_NAME, macro); @@ -99,13 +105,16 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_single_node) ASSERT_TRUE(filter->is_equal(macro.get())); } -TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_multiple_macros) -{ +TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_multiple_macros) { filter_ast::pos_info a_macro_pos(11, 75, 43); filter_ast::pos_info b_macro_pos(91, 21, 9); - std::shared_ptr a_macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), "exists"); - std::shared_ptr b_macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("another.field", ""), "exists"); + std::shared_ptr a_macro = + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), + "exists"); + std::shared_ptr b_macro = filter_ast::unary_check_expr::create( + filter_ast::field_expr::create("another.field", ""), + "exists"); std::vector> filter_or; filter_or.push_back(filter_ast::identifier_expr::create(MACRO_A_NAME, a_macro_pos)); @@ -143,24 +152,31 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_multiple_macros) ASSERT_TRUE(filter->is_equal(expected_filter.get())); } -TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_nested_macros) -{ +TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_nested_macros) { filter_ast::pos_info a_macro_pos(47, 1, 76); filter_ast::pos_info b_macro_pos(111, 65, 2); std::vector> a_macro_and; - a_macro_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), "exists")); + a_macro_and.push_back( + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), + "exists")); a_macro_and.push_back(filter_ast::identifier_expr::create(MACRO_B_NAME, b_macro_pos)); std::shared_ptr a_macro = filter_ast::and_expr::create(a_macro_and); - std::shared_ptr b_macro = - filter_ast::unary_check_expr::create(filter_ast::field_expr::create("another.field", ""), "exists"); + std::shared_ptr b_macro = filter_ast::unary_check_expr::create( + filter_ast::field_expr::create("another.field", ""), + "exists"); - std::shared_ptr filter = filter_ast::identifier_expr::create(MACRO_A_NAME, a_macro_pos); + std::shared_ptr filter = + filter_ast::identifier_expr::create(MACRO_A_NAME, a_macro_pos); std::vector> expected_and; - expected_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), "exists")); - expected_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("another.field", ""), "exists")); + expected_and.push_back( + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), + "exists")); + expected_and.push_back(filter_ast::unary_check_expr::create( + filter_ast::field_expr::create("another.field", ""), + "exists")); std::shared_ptr expected_filter = filter_ast::and_expr::create(expected_and); filter_macro_resolver resolver; @@ -191,13 +207,15 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_nested_macros) ASSERT_TRUE(filter->is_equal(expected_filter.get())); } -TEST(MacroResolver, should_find_unknown_macros) -{ +TEST(MacroResolver, should_find_unknown_macros) { filter_ast::pos_info macro_pos(9, 4, 2); std::vector> filter_and; - filter_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("evt.name", ""), "exists")); - filter_and.push_back(filter_ast::not_expr::create(filter_ast::identifier_expr::create(MACRO_NAME, macro_pos))); + filter_and.push_back( + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("evt.name", ""), + "exists")); + filter_and.push_back(filter_ast::not_expr::create( + filter_ast::identifier_expr::create(MACRO_NAME, macro_pos))); std::shared_ptr filter = filter_ast::and_expr::create(filter_and); filter_macro_resolver resolver; @@ -208,17 +226,19 @@ TEST(MacroResolver, should_find_unknown_macros) ASSERT_TRUE(resolver.get_resolved_macros().empty()); } -TEST(MacroResolver, should_find_unknown_nested_macros) -{ +TEST(MacroResolver, should_find_unknown_nested_macros) { filter_ast::pos_info a_macro_pos(32, 84, 9); filter_ast::pos_info b_macro_pos(1, 0, 5); std::vector> a_macro_and; - a_macro_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), "exists")); + a_macro_and.push_back( + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), + "exists")); a_macro_and.push_back(filter_ast::identifier_expr::create(MACRO_B_NAME, b_macro_pos)); std::shared_ptr a_macro = filter_ast::and_expr::create(a_macro_and); - std::shared_ptr filter = filter_ast::identifier_expr::create(MACRO_A_NAME, a_macro_pos); + std::shared_ptr filter = + filter_ast::identifier_expr::create(MACRO_A_NAME, a_macro_pos); auto expected_filter = clone(a_macro.get()); filter_macro_resolver resolver; @@ -234,14 +254,17 @@ TEST(MacroResolver, should_find_unknown_nested_macros) ASSERT_TRUE(filter->is_equal(expected_filter.get())); } -TEST(MacroResolver, should_undefine_macro) -{ +TEST(MacroResolver, should_undefine_macro) { filter_ast::pos_info macro_pos_1(12, 9, 3); filter_ast::pos_info macro_pos_2(9, 6, 3); - std::shared_ptr macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), "exists"); - std::shared_ptr a_filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos_1); - std::shared_ptr b_filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos_2); + std::shared_ptr macro = + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), + "exists"); + std::shared_ptr a_filter = + filter_ast::identifier_expr::create(MACRO_NAME, macro_pos_1); + std::shared_ptr b_filter = + filter_ast::identifier_expr::create(MACRO_NAME, macro_pos_2); filter_macro_resolver resolver; resolver.set_macro(MACRO_NAME, macro); @@ -261,11 +284,13 @@ TEST(MacroResolver, should_undefine_macro) } /* checks that the macro AST is cloned and not shared across resolved filters */ -TEST(MacroResolver, should_clone_macro_AST) -{ +TEST(MacroResolver, should_clone_macro_AST) { filter_ast::pos_info macro_pos(5, 2, 8888); - std::shared_ptr macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), "exists"); - std::shared_ptr filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos); + std::shared_ptr macro = + filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), + "exists"); + std::shared_ptr filter = + filter_ast::identifier_expr::create(MACRO_NAME, macro_pos); filter_macro_resolver resolver; resolver.set_macro(MACRO_NAME, macro); diff --git a/unit_tests/engine/test_filter_warning_resolver.cpp b/unit_tests/engine/test_filter_warning_resolver.cpp index 8ebe331c9df..ece4af4de26 100644 --- a/unit_tests/engine/test_filter_warning_resolver.cpp +++ b/unit_tests/engine/test_filter_warning_resolver.cpp @@ -18,16 +18,14 @@ limitations under the License. #include #include -static bool warns(const std::string& condition) -{ +static bool warns(const std::string& condition) { std::set w; auto ast = libsinsp::filter::parser(condition).parse(); filter_warning_resolver().run(ast.get(), w); return !w.empty(); } -TEST(WarningResolver, warnings_in_filtering_conditions) -{ +TEST(WarningResolver, warnings_in_filtering_conditions) { ASSERT_FALSE(warns("ka.field exists")); ASSERT_FALSE(warns("some.field = ")); ASSERT_TRUE(warns("jevt.field = ")); diff --git a/unit_tests/engine/test_plugin_requirements.cpp b/unit_tests/engine/test_plugin_requirements.cpp index 3fcde665893..c477e459dd2 100644 --- a/unit_tests/engine/test_plugin_requirements.cpp +++ b/unit_tests/engine/test_plugin_requirements.cpp @@ -20,22 +20,19 @@ limitations under the License. #include static bool check_requirements(std::string& err, - const std::vector& plugins, - const std::string& ruleset_content) -{ + const std::vector& plugins, + const std::string& ruleset_content) { falco_engine e; falco::load_result::rules_contents_t c = {{"test", ruleset_content}}; auto res = e.load_rules(c.begin()->second, c.begin()->first); - if(!res->successful()) - { + if(!res->successful()) { return false; } return e.check_plugin_requirements(plugins, err); } -TEST(PluginRequirements, check_plugin_requirements_success) -{ +TEST(PluginRequirements, check_plugin_requirements_success) { std::string error; /* No requirement */ @@ -47,7 +44,7 @@ TEST(PluginRequirements, check_plugin_requirements_success) - name: k8saudit version: 0.1.0 )")) << error - << std::endl; + << std::endl; /* Single plugin newer version */ ASSERT_TRUE(check_requirements(error, {{"k8saudit", "0.2.0"}}, R"( @@ -55,7 +52,7 @@ TEST(PluginRequirements, check_plugin_requirements_success) - name: k8saudit version: 0.1.0 )")) << error - << std::endl; + << std::endl; /* Multiple plugins */ ASSERT_TRUE(check_requirements(error, {{"k8saudit", "0.1.0"}, {"json", "0.3.0"}}, R"( @@ -65,7 +62,7 @@ TEST(PluginRequirements, check_plugin_requirements_success) - name: json version: 0.3.0 )")) << error - << std::endl; + << std::endl; /* Single plugin multiple versions */ ASSERT_TRUE(check_requirements(error, {{"k8saudit", "0.2.0"}}, R"( @@ -76,7 +73,7 @@ TEST(PluginRequirements, check_plugin_requirements_success) - name: k8saudit version: 0.2.0 )")) << error - << std::endl; + << std::endl; /* Single plugin with alternatives */ ASSERT_TRUE(check_requirements(error, {{"k8saudit-other", "0.5.0"}}, R"( @@ -87,7 +84,7 @@ TEST(PluginRequirements, check_plugin_requirements_success) - name: k8saudit-other version: 0.4.0 )")) << error - << std::endl; + << std::endl; /* Multiple plugins with alternatives */ ASSERT_TRUE(check_requirements(error, {{"k8saudit-other", "0.5.0"}, {"json2", "0.5.0"}}, R"( @@ -103,7 +100,7 @@ TEST(PluginRequirements, check_plugin_requirements_success) - name: json2 version: 0.1.0 )")) << error - << std::endl; + << std::endl; /* Multiple plugins with alternatives with multiple versions */ ASSERT_TRUE(check_requirements(error, {{"k8saudit-other", "0.7.0"}, {"json2", "0.5.0"}}, R"( @@ -125,11 +122,10 @@ TEST(PluginRequirements, check_plugin_requirements_success) - name: k8saudit-other version: 0.7.0 )")) << error - << std::endl; + << std::endl; } -TEST(PluginRequirements, check_plugin_requirements_reject) -{ +TEST(PluginRequirements, check_plugin_requirements_reject) { std::string error; /* No plugin loaded */ @@ -138,7 +134,7 @@ TEST(PluginRequirements, check_plugin_requirements_reject) - name: k8saudit version: 0.1.0 )")) << error - << std::endl; + << std::endl; /* Single plugin wrong name */ ASSERT_FALSE(check_requirements(error, {{"k8saudit", "0.1.0"}}, R"( @@ -146,7 +142,7 @@ TEST(PluginRequirements, check_plugin_requirements_reject) - name: k8saudit2 version: 0.1.0 )")) << error - << std::endl; + << std::endl; /* Single plugin wrong version */ ASSERT_FALSE(check_requirements(error, {{"k8saudit", "0.1.0"}}, R"( @@ -154,7 +150,7 @@ TEST(PluginRequirements, check_plugin_requirements_reject) - name: k8saudit version: 0.2.0 )")) << error - << std::endl; + << std::endl; /* Multiple plugins */ ASSERT_FALSE(check_requirements(error, {{"k8saudit", "0.1.0"}}, R"( @@ -164,7 +160,7 @@ TEST(PluginRequirements, check_plugin_requirements_reject) - name: json version: 0.3.0 )")) << error - << std::endl; + << std::endl; /* Single plugin multiple versions */ ASSERT_FALSE(check_requirements(error, {{"k8saudit", "0.1.0"}}, R"( @@ -175,7 +171,7 @@ TEST(PluginRequirements, check_plugin_requirements_reject) - name: k8saudit version: 0.2.0 )")) << error - << std::endl; + << std::endl; /* Single plugin with alternatives */ ASSERT_FALSE(check_requirements(error, {{"k8saudit2", "0.5.0"}}, R"( @@ -186,7 +182,7 @@ TEST(PluginRequirements, check_plugin_requirements_reject) - name: k8saudit-other version: 0.4.0 )")) << error - << std::endl; + << std::endl; /* Single plugin with overlapping alternatives */ ASSERT_FALSE(check_requirements(error, {{"k8saudit", "0.5.0"}}, R"( @@ -197,7 +193,7 @@ TEST(PluginRequirements, check_plugin_requirements_reject) - name: k8saudit version: 0.4.0 )")) << error - << std::endl; + << std::endl; /* Multiple plugins with alternatives */ ASSERT_FALSE(check_requirements(error, {{"k8saudit-other", "0.5.0"}, {"json3", "0.5.0"}}, R"( @@ -213,7 +209,7 @@ TEST(PluginRequirements, check_plugin_requirements_reject) - name: json2 version: 0.1.0 )")) << error - << std::endl; + << std::endl; /* Multiple plugins with alternatives with multiple versions */ ASSERT_FALSE(check_requirements(error, {{"k8saudit", "0.7.0"}, {"json2", "0.5.0"}}, R"( @@ -235,5 +231,5 @@ TEST(PluginRequirements, check_plugin_requirements_reject) - name: k8saudit-other version: 0.7.0 )")) << error - << std::endl; + << std::endl; } diff --git a/unit_tests/engine/test_rule_loader.cpp b/unit_tests/engine/test_rule_loader.cpp index ae680cd6cd7..8feadd2c592 100644 --- a/unit_tests/engine/test_rule_loader.cpp +++ b/unit_tests/engine/test_rule_loader.cpp @@ -3,14 +3,14 @@ #include "../test_falco_engine.h" #include "yaml_helper.h" -#define ASSERT_VALIDATION_STATUS(status) ASSERT_TRUE(sinsp_utils::startswith(m_load_result->schema_validation(), status)) +#define ASSERT_VALIDATION_STATUS(status) \ + ASSERT_TRUE(sinsp_utils::startswith(m_load_result->schema_validation(), status)) std::string s_sample_ruleset = "sample-ruleset"; std::string s_sample_source = falco_common::syscall_source; -TEST_F(test_falco_engine, list_append) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, list_append) { + std::string rules_content = R"END( - list: shell_binaries items: [ash, bash, csh, ksh, sh, tcsh, zsh, dash] @@ -28,12 +28,13 @@ TEST_F(test_falco_engine, list_append) ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("legit_rule"),"(evt.type = open and proc.name in (ash, bash, csh, ksh, sh, tcsh, zsh, dash, pwsh))"); + ASSERT_EQ( + get_compiled_rule_condition("legit_rule"), + "(evt.type = open and proc.name in (ash, bash, csh, ksh, sh, tcsh, zsh, dash, pwsh))"); } -TEST_F(test_falco_engine, condition_append) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, condition_append) { + std::string rules_content = R"END( - macro: interactive condition: > ((proc.aname=sshd and proc.name != sshd) or @@ -53,12 +54,13 @@ TEST_F(test_falco_engine, condition_append) ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string; ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("legit_rule"),"(evt.type = open and (((proc.aname = sshd and proc.name != sshd) or proc.name = systemd-logind or proc.name = login) or proc.name = ssh))"); + ASSERT_EQ(get_compiled_rule_condition("legit_rule"), + "(evt.type = open and (((proc.aname = sshd and proc.name != sshd) or proc.name = " + "systemd-logind or proc.name = login) or proc.name = ssh))"); } -TEST_F(test_falco_engine, rule_override_append) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_override_append) { + std::string rules_content = R"END( - rule: legit_rule desc: legit rule description condition: evt.type=open @@ -84,18 +86,17 @@ TEST_F(test_falco_engine, rule_override_append) auto rule_description = m_engine->describe_rule(&rule_name, {}); ASSERT_EQ(rule_description["rules"][0]["info"]["condition"].template get(), - "evt.type=open and proc.name = cat"); + "evt.type=open and proc.name = cat"); ASSERT_EQ(rule_description["rules"][0]["info"]["output"].template get(), - "user=%user.name command=%proc.cmdline file=%fd.name proc=%proc.name"); + "user=%user.name command=%proc.cmdline file=%fd.name proc=%proc.name"); ASSERT_EQ(rule_description["rules"][0]["info"]["description"].template get(), - "legit rule description with append"); + "legit rule description with append"); } -TEST_F(test_falco_engine, rule_append) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_append) { + std::string rules_content = R"END( - rule: legit_rule desc: legit rule description condition: evt.type=open @@ -113,12 +114,11 @@ TEST_F(test_falco_engine, rule_append) // We should have at least one warning because the 'append' flag is deprecated. ASSERT_TRUE(check_warning_message(WARNING_APPEND)); - ASSERT_EQ(get_compiled_rule_condition("legit_rule"),"(evt.type = open and proc.name = cat)"); + ASSERT_EQ(get_compiled_rule_condition("legit_rule"), "(evt.type = open and proc.name = cat)"); } -TEST_F(test_falco_engine, rule_override_replace) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_override_replace) { + std::string rules_content = R"END( - rule: legit_rule desc: legit rule description condition: evt.type=open @@ -139,18 +139,17 @@ TEST_F(test_falco_engine, rule_override_replace) auto rule_description = m_engine->describe_rule(&rule_name, {}); ASSERT_EQ(rule_description["rules"][0]["info"]["condition"].template get(), - "evt.type = close"); + "evt.type = close"); ASSERT_EQ(rule_description["rules"][0]["info"]["output"].template get(), - "user=%user.name command=%proc.cmdline file=%fd.name"); + "user=%user.name command=%proc.cmdline file=%fd.name"); ASSERT_EQ(rule_description["rules"][0]["info"]["description"].template get(), - "a replaced legit description"); + "a replaced legit description"); } -TEST_F(test_falco_engine, rule_override_append_replace) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_override_append_replace) { + std::string rules_content = R"END( - rule: legit_rule desc: legit rule description condition: evt.type = close @@ -173,21 +172,20 @@ TEST_F(test_falco_engine, rule_override_append_replace) auto rule_description = m_engine->describe_rule(&rule_name, {}); ASSERT_EQ(rule_description["rules"][0]["info"]["condition"].template get(), - "evt.type = close and proc.name = cat"); + "evt.type = close and proc.name = cat"); ASSERT_EQ(rule_description["rules"][0]["info"]["output"].template get(), - "user=%user.name command=%proc.cmdline file=%fd.name"); + "user=%user.name command=%proc.cmdline file=%fd.name"); ASSERT_EQ(rule_description["rules"][0]["info"]["description"].template get(), - "a replaced legit description"); + "a replaced legit description"); ASSERT_EQ(rule_description["rules"][0]["info"]["priority"].template get(), - "Warning"); + "Warning"); } -TEST_F(test_falco_engine, rule_incorrect_override_type) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_incorrect_override_type) { + std::string rules_content = R"END( - rule: failing_rule desc: legit rule description condition: evt.type = close @@ -207,12 +205,12 @@ TEST_F(test_falco_engine, rule_incorrect_override_type) ASSERT_FALSE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); ASSERT_TRUE(check_error_message("Key 'priority' cannot be appended to, use 'replace' instead")); - ASSERT_TRUE(std::string(m_load_result_json["errors"][0]["context"]["snippet"]).find("priority: append") != std::string::npos); + ASSERT_TRUE(std::string(m_load_result_json["errors"][0]["context"]["snippet"]) + .find("priority: append") != std::string::npos); } -TEST_F(test_falco_engine, rule_incorrect_append_override) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_incorrect_append_override) { + std::string rules_content = R"END( - rule: failing_rule desc: legit rule description condition: evt.type = close @@ -230,16 +228,15 @@ TEST_F(test_falco_engine, rule_incorrect_append_override) ASSERT_FALSE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - + // We should have at least one warning because the 'append' flag is deprecated. ASSERT_TRUE(check_warning_message(WARNING_APPEND)); - + ASSERT_TRUE(check_error_message(ERROR_OVERRIDE_APPEND)); } -TEST_F(test_falco_engine, macro_override_append_before_macro_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, macro_override_append_before_macro_definition) { + std::string rules_content = R"END( - macro: open_simple condition: or evt.type = openat2 @@ -263,9 +260,8 @@ TEST_F(test_falco_engine, macro_override_append_before_macro_definition) ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_MACRO)); } -TEST_F(test_falco_engine, macro_override_replace_before_macro_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, macro_override_replace_before_macro_definition) { + std::string rules_content = R"END( - macro: open_simple condition: or evt.type = openat2 @@ -286,12 +282,11 @@ TEST_F(test_falco_engine, macro_override_replace_before_macro_definition) // The first override defines a macro that is overridden by the second macro definition ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"evt.type in (open, openat)"); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), "evt.type in (open, openat)"); } -TEST_F(test_falco_engine, macro_append_before_macro_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, macro_append_before_macro_definition) { + std::string rules_content = R"END( - macro: open_simple condition: or evt.type = openat2 @@ -314,9 +309,8 @@ TEST_F(test_falco_engine, macro_append_before_macro_definition) ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_MACRO)); } -TEST_F(test_falco_engine, macro_override_append_after_macro_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, macro_override_append_after_macro_definition) { + std::string rules_content = R"END( - macro: open_simple condition: evt.type in (open,openat) @@ -337,12 +331,12 @@ TEST_F(test_falco_engine, macro_override_append_after_macro_definition) // We cannot define a macro override before the macro definition. ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type in (open, openat) or evt.type = openat2)"); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type in (open, openat) or evt.type = openat2)"); } -TEST_F(test_falco_engine, macro_append_after_macro_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, macro_append_after_macro_definition) { + std::string rules_content = R"END( - macro: open_simple condition: evt.type in (open,openat) @@ -362,12 +356,12 @@ TEST_F(test_falco_engine, macro_append_after_macro_definition) // We cannot define a macro override before the macro definition. ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type in (open, openat) or evt.type = openat2)"); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type in (open, openat) or evt.type = openat2)"); } -TEST_F(test_falco_engine, rule_override_append_before_rule_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_override_append_before_rule_definition) { + std::string rules_content = R"END( - rule: test_rule condition: and proc.name = cat override: @@ -386,9 +380,8 @@ TEST_F(test_falco_engine, rule_override_append_before_rule_definition) ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE_APPEND)); } -TEST_F(test_falco_engine, rule_override_replace_before_rule_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_override_replace_before_rule_definition) { + std::string rules_content = R"END( - rule: test_rule condition: and proc.name = cat override: @@ -407,9 +400,8 @@ TEST_F(test_falco_engine, rule_override_replace_before_rule_definition) ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE_REPLACE)); } -TEST_F(test_falco_engine, rule_append_before_rule_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_append_before_rule_definition) { + std::string rules_content = R"END( - rule: test_rule condition: and proc.name = cat append: true @@ -427,9 +419,8 @@ TEST_F(test_falco_engine, rule_append_before_rule_definition) ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE_APPEND)); } -TEST_F(test_falco_engine, rule_override_append_after_rule_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_override_append_after_rule_definition) { + std::string rules_content = R"END( - rule: test_rule desc: simple rule condition: evt.type in (open,openat) @@ -444,12 +435,12 @@ TEST_F(test_falco_engine, rule_override_append_after_rule_definition) ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type in (open, openat) and proc.name = cat)"); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type in (open, openat) and proc.name = cat)"); } -TEST_F(test_falco_engine, rule_append_after_rule_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_append_after_rule_definition) { + std::string rules_content = R"END( - rule: test_rule desc: simple rule condition: evt.type in (open,openat) @@ -463,14 +454,14 @@ TEST_F(test_falco_engine, rule_append_after_rule_definition) ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type in (open, openat) and proc.name = cat)"); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type in (open, openat) and proc.name = cat)"); } -TEST_F(test_falco_engine, list_override_append_wrong_key) -{ +TEST_F(test_falco_engine, list_override_append_wrong_key) { // todo: maybe we want to manage some non-existent keys // Please note how the non-existent key 'non-existent keys' is ignored. - std::string rules_content = R"END( + std::string rules_content = R"END( - list: dev_creation_binaries items: ["csi-provisioner", "csi-attacher"] override_written_wrong: @@ -488,16 +479,16 @@ TEST_F(test_falco_engine, list_override_append_wrong_key) )END"; // Since there is a wrong key in the first list definition the `override` is not - // considered. so in this situation, we are defining the list 2 times. The + // considered. so in this situation, we are defining the list 2 times. The // second one overrides the first one. ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_failed) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type = execve and proc.name in (blkid))"); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = execve and proc.name in (blkid))"); } -TEST_F(test_falco_engine, list_override_append_before_list_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, list_override_append_before_list_definition) { + std::string rules_content = R"END( - list: dev_creation_binaries items: ["csi-provisioner", "csi-attacher"] override: @@ -520,9 +511,8 @@ TEST_F(test_falco_engine, list_override_append_before_list_definition) ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_LIST)); } -TEST_F(test_falco_engine, list_override_replace_before_list_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, list_override_replace_before_list_definition) { + std::string rules_content = R"END( - list: dev_creation_binaries items: ["csi-provisioner", "csi-attacher"] override: @@ -542,12 +532,12 @@ TEST_F(test_falco_engine, list_override_replace_before_list_definition) // With override replace we define a first list that then is overridden by the second one. ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type = execve and proc.name in (blkid))"); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = execve and proc.name in (blkid))"); } -TEST_F(test_falco_engine, list_append_before_list_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, list_append_before_list_definition) { + std::string rules_content = R"END( - list: dev_creation_binaries items: ["csi-provisioner", "csi-attacher"] append: true @@ -569,9 +559,8 @@ TEST_F(test_falco_engine, list_append_before_list_definition) ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_LIST)); } -TEST_F(test_falco_engine, list_override_append_after_list_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, list_override_append_after_list_definition) { + std::string rules_content = R"END( - list: dev_creation_binaries items: [blkid] @@ -590,12 +579,12 @@ TEST_F(test_falco_engine, list_override_append_after_list_definition) ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type = execve and proc.name in (blkid, csi-provisioner, csi-attacher))"); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = execve and proc.name in (blkid, csi-provisioner, csi-attacher))"); } -TEST_F(test_falco_engine, list_append_after_list_definition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, list_append_after_list_definition) { + std::string rules_content = R"END( - list: dev_creation_binaries items: [blkid] @@ -612,12 +601,12 @@ TEST_F(test_falco_engine, list_append_after_list_definition) ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type = execve and proc.name in (blkid, csi-provisioner, csi-attacher))"); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = execve and proc.name in (blkid, csi-provisioner, csi-attacher))"); } -TEST_F(test_falco_engine, rule_override_without_field) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_override_without_field) { + std::string rules_content = R"END( - rule: failing_rule desc: legit rule description condition: evt.type = close @@ -633,12 +622,12 @@ TEST_F(test_falco_engine, rule_override_without_field) ASSERT_FALSE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_TRUE(check_error_message("An append override for 'condition' was specified but 'condition' is not defined")); + ASSERT_TRUE(check_error_message( + "An append override for 'condition' was specified but 'condition' is not defined")); } -TEST_F(test_falco_engine, rule_override_extra_field) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_override_extra_field) { + std::string rules_content = R"END( - rule: failing_rule desc: legit rule description condition: evt.type = close @@ -659,9 +648,8 @@ TEST_F(test_falco_engine, rule_override_extra_field) ASSERT_TRUE(check_error_message("Unexpected key 'priority'")); } -TEST_F(test_falco_engine, missing_enabled_key_with_override) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, missing_enabled_key_with_override) { + std::string rules_content = R"END( - rule: test_rule desc: test rule description condition: evt.type = close @@ -684,9 +672,8 @@ TEST_F(test_falco_engine, missing_enabled_key_with_override) ASSERT_TRUE(check_error_message("'enabled' was specified but 'enabled' is not defined")); } -TEST_F(test_falco_engine, rule_override_with_enabled) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_override_with_enabled) { + std::string rules_content = R"END( - rule: test_rule desc: test rule description condition: evt.type = close @@ -711,9 +698,8 @@ TEST_F(test_falco_engine, rule_override_with_enabled) EXPECT_EQ(num_rules_for_ruleset(), 1); } -TEST_F(test_falco_engine, rule_override_exceptions_required_fields) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_override_exceptions_required_fields) { + std::string rules_content = R"END( - rule: test_rule desc: test rule description condition: evt.type = close @@ -745,12 +731,12 @@ TEST_F(test_falco_engine, rule_override_exceptions_required_fields) ASSERT_FALSE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); ASSERT_FALSE(has_warnings()); - ASSERT_TRUE(check_error_message("Item has no mapping for key 'fields'")) << m_load_result_json.dump(); + ASSERT_TRUE(check_error_message("Item has no mapping for key 'fields'")) + << m_load_result_json.dump(); } -TEST_F(test_falco_engine, rule_not_enabled) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_not_enabled) { + std::string rules_content = R"END( - rule: test_rule desc: rule not enabled condition: evt.type = close @@ -765,9 +751,8 @@ TEST_F(test_falco_engine, rule_not_enabled) EXPECT_EQ(num_rules_for_ruleset(), 0); } -TEST_F(test_falco_engine, rule_enabled_warning) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_enabled_warning) { + std::string rules_content = R"END( - rule: test_rule desc: test rule description condition: evt.type = close @@ -787,9 +772,8 @@ TEST_F(test_falco_engine, rule_enabled_warning) } // todo!: Probably we shouldn't allow this syntax -TEST_F(test_falco_engine, rule_enabled_is_ignored_by_append) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rule_enabled_is_ignored_by_append) { + std::string rules_content = R"END( - rule: test_rule desc: test rule description condition: evt.type = close @@ -811,9 +795,8 @@ TEST_F(test_falco_engine, rule_enabled_is_ignored_by_append) } // todo!: Probably we shouldn't allow this syntax -TEST_F(test_falco_engine, rewrite_rule) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, rewrite_rule) { + std::string rules_content = R"END( - rule: test_rule desc: test rule description condition: evt.type = close @@ -835,12 +818,11 @@ TEST_F(test_falco_engine, rewrite_rule) ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); // In this case the rule is completely overridden but this syntax is not supported. EXPECT_EQ(num_rules_for_ruleset(), 1); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"proc.name = cat"); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), "proc.name = cat"); } -TEST_F(test_falco_engine, required_engine_version_semver) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, required_engine_version_semver) { + std::string rules_content = R"END( - required_engine_version: 0.26.0 - rule: test_rule @@ -857,9 +839,8 @@ TEST_F(test_falco_engine, required_engine_version_semver) ASSERT_FALSE(has_warnings()); } -TEST_F(test_falco_engine, required_engine_version_not_semver) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, required_engine_version_not_semver) { + std::string rules_content = R"END( - required_engine_version: 26 - rule: test_rule @@ -876,9 +857,8 @@ TEST_F(test_falco_engine, required_engine_version_not_semver) ASSERT_FALSE(has_warnings()); } -TEST_F(test_falco_engine, required_engine_version_invalid) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, required_engine_version_invalid) { + std::string rules_content = R"END( - required_engine_version: seven - rule: test_rule @@ -896,9 +876,8 @@ TEST_F(test_falco_engine, required_engine_version_invalid) } // checks for issue described in https://github.com/falcosecurity/falco/pull/3028 -TEST_F(test_falco_engine, list_value_with_escaping) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, list_value_with_escaping) { + std::string rules_content = R"END( - list: my_list items: [non_escaped_val, "escaped val"] )END"; @@ -906,7 +885,7 @@ TEST_F(test_falco_engine, list_value_with_escaping) ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); ASSERT_TRUE(m_load_result->successful()); - ASSERT_TRUE(m_load_result->has_warnings()); // a warning for the unused list + ASSERT_TRUE(m_load_result->has_warnings()); // a warning for the unused list auto rule_description = m_engine->describe_rule(nullptr, {}); ASSERT_TRUE(m_load_result->successful()); @@ -919,13 +898,16 @@ TEST_F(test_falco_engine, list_value_with_escaping) // values should be escaped correctly ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"].size(), 2); - ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"][0].template get(), "non_escaped_val"); - ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"][1].template get(), "escaped val"); + ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"][0] + .template get(), + "non_escaped_val"); + ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"][1] + .template get(), + "escaped val"); } -TEST_F(test_falco_engine, exceptions_condition) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, exceptions_condition) { + std::string rules_content = R"END( - rule: test_rule desc: test rule condition: proc.cmdline contains curl or proc.cmdline contains wget @@ -939,26 +921,27 @@ TEST_F(test_falco_engine, exceptions_condition) - [curl 127.0.0.1] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_EQ(get_compiled_rule_condition("test_rule"),"((proc.cmdline contains curl or proc.cmdline contains wget) and not proc.cmdline contains \"curl 127.0.0.1\")"); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + ASSERT_EQ(get_compiled_rule_condition("test_rule"), + "((proc.cmdline contains curl or proc.cmdline contains wget) and not proc.cmdline " + "contains \"curl 127.0.0.1\")"); } -TEST_F(test_falco_engine, macro_name_invalid) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, macro_name_invalid) { + std::string rules_content = R"END( - macro: test-macro condition: evt.type = close )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_TRUE(check_warning_message("Macro has an invalid name. Macro names should match a regular expression")); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + ASSERT_TRUE(check_warning_message( + "Macro has an invalid name. Macro names should match a regular expression")); } -TEST_F(test_falco_engine, list_name_invalid) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, list_name_invalid) { + std::string rules_content = R"END( - list: test list items: [open, openat, openat2] @@ -971,16 +954,16 @@ TEST_F(test_falco_engine, list_name_invalid) )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_TRUE(check_warning_message("List has an invalid name. List names should match a regular expression")); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + ASSERT_TRUE(check_warning_message( + "List has an invalid name. List names should match a regular expression")); } // The appended exception has a purposely miswritten field (value), // simulating a typo or an incorrect usage. -TEST_F(test_falco_engine, exceptions_append_no_values) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, exceptions_append_no_values) { + std::string rules_content = R"END( - rule: test_rule desc: test rule condition: proc.cmdline contains curl @@ -1000,14 +983,13 @@ TEST_F(test_falco_engine, exceptions_append_no_values) append: true )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_failed) << m_load_result->schema_validation(); - ASSERT_TRUE(check_warning_message("Overriding/appending exception with no values")); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_failed) << m_load_result->schema_validation(); + ASSERT_TRUE(check_warning_message("Overriding/appending exception with no values")); } -TEST_F(test_falco_engine, exceptions_override_no_values) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, exceptions_override_no_values) { + std::string rules_content = R"END( - rule: test_rule desc: test rule condition: proc.cmdline contains curl @@ -1028,14 +1010,13 @@ TEST_F(test_falco_engine, exceptions_override_no_values) exceptions: append )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_failed) << m_load_result->schema_validation(); - ASSERT_TRUE(check_warning_message("Overriding/appending exception with no values")); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_failed) << m_load_result->schema_validation(); + ASSERT_TRUE(check_warning_message("Overriding/appending exception with no values")); } -TEST_F(test_falco_engine, exceptions_names_not_unique) -{ - std::string rules_content = R"END( +TEST_F(test_falco_engine, exceptions_names_not_unique) { + std::string rules_content = R"END( - rule: test_rule desc: test rule condition: proc.cmdline contains curl @@ -1054,9 +1035,9 @@ TEST_F(test_falco_engine, exceptions_names_not_unique) - [curl 127.0.0.1] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_TRUE(check_warning_message("Multiple definitions of exception")); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + ASSERT_TRUE(check_warning_message("Multiple definitions of exception")); } static std::string s_exception_values_rule_base = R"END( @@ -1067,9 +1048,8 @@ static std::string s_exception_values_rule_base = R"END( priority: INFO )END"; -TEST_F(test_falco_engine, exceptions_values_rhs_field_ambiguous) -{ - auto rules_content = s_exception_values_rule_base + R"END( +TEST_F(test_falco_engine, exceptions_values_rhs_field_ambiguous) { + auto rules_content = s_exception_values_rule_base + R"END( exceptions: - name: test_exception fields: [proc.name] @@ -1078,15 +1058,16 @@ TEST_F(test_falco_engine, exceptions_values_rhs_field_ambiguous) - [proc.pname] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = proc.pname)"); - EXPECT_TRUE(check_warning_message("'proc.pname' may be a valid field misused as a const string value")); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + EXPECT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = open and not proc.name = proc.pname)"); + EXPECT_TRUE(check_warning_message( + "'proc.pname' may be a valid field misused as a const string value")); } -TEST_F(test_falco_engine, exceptions_values_rhs_field_ambiguous_quoted) -{ - auto rules_content = s_exception_values_rule_base + R"END( +TEST_F(test_falco_engine, exceptions_values_rhs_field_ambiguous_quoted) { + auto rules_content = s_exception_values_rule_base + R"END( exceptions: - name: test_exception fields: [proc.name] @@ -1095,15 +1076,16 @@ TEST_F(test_falco_engine, exceptions_values_rhs_field_ambiguous_quoted) - ["proc.pname"] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = proc.pname)"); - EXPECT_TRUE(check_warning_message("'proc.pname' may be a valid field misused as a const string value")); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + EXPECT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = open and not proc.name = proc.pname)"); + EXPECT_TRUE(check_warning_message( + "'proc.pname' may be a valid field misused as a const string value")); } -TEST_F(test_falco_engine, exceptions_values_rhs_field_ambiguous_space_quoted) -{ - auto rules_content = s_exception_values_rule_base + R"END( +TEST_F(test_falco_engine, exceptions_values_rhs_field_ambiguous_space_quoted) { + auto rules_content = s_exception_values_rule_base + R"END( exceptions: - name: test_exception fields: [proc.name] @@ -1112,15 +1094,16 @@ TEST_F(test_falco_engine, exceptions_values_rhs_field_ambiguous_space_quoted) - ["proc.pname "] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = \"proc.pname \")"); - EXPECT_TRUE(check_warning_message("'proc.pname ' may be a valid field misused as a const string value")); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + EXPECT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = open and not proc.name = \"proc.pname \")"); + EXPECT_TRUE(check_warning_message( + "'proc.pname ' may be a valid field misused as a const string value")); } -TEST_F(test_falco_engine, exceptions_values_rhs_transformer) -{ - auto rules_content = s_exception_values_rule_base + R"END( +TEST_F(test_falco_engine, exceptions_values_rhs_transformer) { + auto rules_content = s_exception_values_rule_base + R"END( exceptions: - name: test_exception fields: [proc.name] @@ -1129,14 +1112,14 @@ TEST_F(test_falco_engine, exceptions_values_rhs_transformer) - [toupper(proc.pname)] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = toupper(proc.pname))"); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + EXPECT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = open and not proc.name = toupper(proc.pname))"); } -TEST_F(test_falco_engine, exceptions_values_transformer_value_quoted) -{ - auto rules_content = s_exception_values_rule_base + R"END( +TEST_F(test_falco_engine, exceptions_values_transformer_value_quoted) { + auto rules_content = s_exception_values_rule_base + R"END( exceptions: - name: test_exception fields: [proc.name] @@ -1145,14 +1128,14 @@ TEST_F(test_falco_engine, exceptions_values_transformer_value_quoted) - ["toupper(proc.pname)"] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = toupper(proc.pname))"); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + EXPECT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = open and not proc.name = toupper(proc.pname))"); } -TEST_F(test_falco_engine, exceptions_values_transformer_space) -{ - auto rules_content = s_exception_values_rule_base + R"END( +TEST_F(test_falco_engine, exceptions_values_transformer_space) { + auto rules_content = s_exception_values_rule_base + R"END( exceptions: - name: test_exception fields: [proc.name] @@ -1161,15 +1144,17 @@ TEST_F(test_falco_engine, exceptions_values_transformer_space) - [toupper( proc.pname)] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = \"toupper( proc.pname)\")"); - EXPECT_TRUE(check_warning_message("'toupper( proc.pname)' may be a valid field transformer misused as a const string value")); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + EXPECT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = open and not proc.name = \"toupper( proc.pname)\")"); + EXPECT_TRUE( + check_warning_message("'toupper( proc.pname)' may be a valid field transformer misused " + "as a const string value")); } -TEST_F(test_falco_engine, exceptions_values_transformer_space_quoted) -{ - auto rules_content = s_exception_values_rule_base + R"END( +TEST_F(test_falco_engine, exceptions_values_transformer_space_quoted) { + auto rules_content = s_exception_values_rule_base + R"END( exceptions: - name: test_exception fields: [proc.name] @@ -1178,15 +1163,17 @@ TEST_F(test_falco_engine, exceptions_values_transformer_space_quoted) - ["toupper( proc.pname)"] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = \"toupper( proc.pname)\")"); - EXPECT_TRUE(check_warning_message("'toupper( proc.pname)' may be a valid field transformer misused as a const string value")); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + EXPECT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = open and not proc.name = \"toupper( proc.pname)\")"); + EXPECT_TRUE( + check_warning_message("'toupper( proc.pname)' may be a valid field transformer misused " + "as a const string value")); } -TEST_F(test_falco_engine, exceptions_fields_transformer) -{ - auto rules_content = s_exception_values_rule_base + R"END( +TEST_F(test_falco_engine, exceptions_fields_transformer) { + auto rules_content = s_exception_values_rule_base + R"END( exceptions: - name: test_exception fields: [tolower(proc.name)] @@ -1195,15 +1182,15 @@ TEST_F(test_falco_engine, exceptions_fields_transformer) - [test] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - EXPECT_FALSE(has_warnings()); - EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not tolower(proc.name) = test)"); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + EXPECT_FALSE(has_warnings()); + EXPECT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = open and not tolower(proc.name) = test)"); } -TEST_F(test_falco_engine, exceptions_fields_transformer_quoted) -{ - auto rules_content = s_exception_values_rule_base + R"END( +TEST_F(test_falco_engine, exceptions_fields_transformer_quoted) { + auto rules_content = s_exception_values_rule_base + R"END( exceptions: - name: test_exception fields: ["tolower(proc.name)"] @@ -1212,15 +1199,15 @@ TEST_F(test_falco_engine, exceptions_fields_transformer_quoted) - [test] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_FALSE(has_warnings()); - EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not tolower(proc.name) = test)"); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + ASSERT_FALSE(has_warnings()); + EXPECT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = open and not tolower(proc.name) = test)"); } -TEST_F(test_falco_engine, exceptions_fields_transformer_space_quoted) -{ - auto rules_content = s_exception_values_rule_base + R"END( +TEST_F(test_falco_engine, exceptions_fields_transformer_space_quoted) { + auto rules_content = s_exception_values_rule_base + R"END( exceptions: - name: test_exception fields: ["tolower( proc.name)"] @@ -1229,8 +1216,9 @@ TEST_F(test_falco_engine, exceptions_fields_transformer_space_quoted) - [test] )END"; - ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); - ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); - ASSERT_FALSE(has_warnings()); - EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not tolower(proc.name) = test)"); + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + ASSERT_VALIDATION_STATUS(yaml_helper::validation_ok) << m_load_result->schema_validation(); + ASSERT_FALSE(has_warnings()); + EXPECT_EQ(get_compiled_rule_condition("test_rule"), + "(evt.type = open and not tolower(proc.name) = test)"); } diff --git a/unit_tests/engine/test_rulesets.cpp b/unit_tests/engine/test_rulesets.cpp index 9b5925d6e21..57dd1a33a93 100644 --- a/unit_tests/engine/test_rulesets.cpp +++ b/unit_tests/engine/test_rulesets.cpp @@ -23,32 +23,28 @@ limitations under the License. #define RULESET_2 2 /* Helpers methods */ -static std::shared_ptr create_factory(sinsp* inspector, filter_check_list& list) -{ +static std::shared_ptr create_factory(sinsp* inspector, + filter_check_list& list) { return std::make_shared(inspector, list); } -static std::shared_ptr create_ruleset(std::shared_ptr f) -{ +static std::shared_ptr create_ruleset(std::shared_ptr f) { return std::make_shared(f); } -static std::shared_ptr create_ast(std::shared_ptr f) -{ +static std::shared_ptr create_ast( + std::shared_ptr f) { libsinsp::filter::parser parser("evt.type=open"); return parser.parse(); } -static std::shared_ptr create_filter( - std::shared_ptr f, - libsinsp::filter::ast::expr* ast) -{ +static std::shared_ptr create_filter(std::shared_ptr f, + libsinsp::filter::ast::expr* ast) { sinsp_filter_compiler compiler(f, ast); return std::shared_ptr(compiler.compile()); } -TEST(Ruleset, enable_disable_rules_using_names) -{ +TEST(Ruleset, enable_disable_rules_using_names) { sinsp inspector; sinsp_filter_check_list filterlist; @@ -140,8 +136,7 @@ TEST(Ruleset, enable_disable_rules_using_names) ASSERT_EQ(r->enabled_count(RULESET_2), 0); } -TEST(Ruleset, enable_disable_rules_using_tags) -{ +TEST(Ruleset, enable_disable_rules_using_tags) { sinsp inspector; sinsp_filter_check_list filterlist; diff --git a/unit_tests/falco/app/actions/app_action_helpers.h b/unit_tests/falco/app/actions/app_action_helpers.h index cd79ffd0c8d..48ad36474c6 100644 --- a/unit_tests/falco/app/actions/app_action_helpers.h +++ b/unit_tests/falco/app/actions/app_action_helpers.h @@ -19,5 +19,17 @@ limitations under the License. #include #include -#define EXPECT_ACTION_OK(r) { auto result = r; EXPECT_TRUE(result.success); EXPECT_TRUE(result.proceed); EXPECT_EQ(result.errstr, ""); } -#define EXPECT_ACTION_FAIL(r) { auto result = r; EXPECT_FALSE(result.success); EXPECT_FALSE(result.proceed); EXPECT_NE(result.errstr, ""); } +#define EXPECT_ACTION_OK(r) \ + { \ + auto result = r; \ + EXPECT_TRUE(result.success); \ + EXPECT_TRUE(result.proceed); \ + EXPECT_EQ(result.errstr, ""); \ + } +#define EXPECT_ACTION_FAIL(r) \ + { \ + auto result = r; \ + EXPECT_FALSE(result.success); \ + EXPECT_FALSE(result.proceed); \ + EXPECT_NE(result.errstr, ""); \ + } diff --git a/unit_tests/falco/app/actions/test_configure_interesting_sets.cpp b/unit_tests/falco/app/actions/test_configure_interesting_sets.cpp index 1819fd1b1ad..40a6215283b 100644 --- a/unit_tests/falco/app/actions/test_configure_interesting_sets.cpp +++ b/unit_tests/falco/app/actions/test_configure_interesting_sets.cpp @@ -23,23 +23,21 @@ limitations under the License. #include #include "app_action_helpers.h" -#define ASSERT_NAMES_EQ(a, b) { \ - EXPECT_EQ(_order(a).size(), _order(b).size()); \ - ASSERT_EQ(_order(a), _order(b)); \ -} +#define ASSERT_NAMES_EQ(a, b) \ + { \ + EXPECT_EQ(_order(a).size(), _order(b).size()); \ + ASSERT_EQ(_order(a), _order(b)); \ + } -#define ASSERT_NAMES_CONTAIN(a, b) { \ - ASSERT_NAMES_EQ(unordered_set_intersection(a, b), b); \ -} +#define ASSERT_NAMES_CONTAIN(a, b) \ + { ASSERT_NAMES_EQ(unordered_set_intersection(a, b), b); } -#define ASSERT_NAMES_NOCONTAIN(a, b) { \ - ASSERT_NAMES_EQ(unordered_set_intersection(a, b), strset_t({})); \ -} +#define ASSERT_NAMES_NOCONTAIN(a, b) \ + { ASSERT_NAMES_EQ(unordered_set_intersection(a, b), strset_t({})); } using strset_t = std::unordered_set; -static std::set _order(const strset_t& s) -{ +static std::set _order(const strset_t& s) { return std::set(s.begin(), s.end()); } @@ -48,38 +46,31 @@ static std::string s_sample_ruleset = "sample-ruleset"; static std::string s_sample_source = falco_common::syscall_source; static strset_t s_sample_filters = { - "evt.type=connect or evt.type=accept or evt.type=accept4 or evt.type=umount2", - "evt.type in (open, ptrace, mmap, execve, read, container)", - "evt.type in (open, execve, mprotect) and not evt.type=mprotect"}; + "evt.type=connect or evt.type=accept or evt.type=accept4 or evt.type=umount2", + "evt.type in (open, ptrace, mmap, execve, read, container)", + "evt.type in (open, execve, mprotect) and not evt.type=mprotect"}; -static strset_t s_sample_generic_filters = { - "evt.type=syncfs or evt.type=fanotify_init"}; +static strset_t s_sample_generic_filters = {"evt.type=syncfs or evt.type=fanotify_init"}; static strset_t s_sample_nonsyscall_filters = { - "evt.type in (procexit, switch, pluginevent, container)"}; + "evt.type in (procexit, switch, pluginevent, container)"}; - -static std::string ruleset_from_filters(const strset_t& filters) -{ +static std::string ruleset_from_filters(const strset_t& filters) { std::string dummy_rules; falco::load_result::rules_contents_t content = {{"dummy_rules.yaml", dummy_rules}}; int n_rules = 0; - for (const auto& f : filters) - { + for(const auto& f : filters) { n_rules++; - dummy_rules += - "- rule: Dummy Rule " + std::to_string(n_rules) + "\n" - + " output: Dummy Output " + std::to_string(n_rules) + "\n" - + " condition: " + f + "\n" - + " desc: Dummy Desc " + std::to_string(n_rules) + "\n" - + " priority: CRITICAL\n\n"; + dummy_rules += "- rule: Dummy Rule " + std::to_string(n_rules) + "\n" + + " output: Dummy Output " + std::to_string(n_rules) + "\n" + + " condition: " + f + "\n" + " desc: Dummy Desc " + + std::to_string(n_rules) + "\n" + " priority: CRITICAL\n\n"; } return dummy_rules; } -TEST_F(test_falco_engine, engine_codes_syscalls_set) -{ +TEST_F(test_falco_engine, engine_codes_syscalls_set) { load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml"); auto enabled_count = m_engine->num_rules_for_ruleset(s_sample_ruleset); @@ -88,20 +79,37 @@ TEST_F(test_falco_engine, engine_codes_syscalls_set) // test if event code names were extracted from each rule in test ruleset. auto rules_event_set = m_engine->event_codes_for_ruleset(s_sample_source); auto rules_event_names = libsinsp::events::event_set_to_names(rules_event_set); - ASSERT_NAMES_EQ(rules_event_names, strset_t({ - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read", "container", "asyncevent"})); + ASSERT_NAMES_EQ(rules_event_names, + strset_t({"connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", + "read", + "container", + "asyncevent"})); // test if sc code names were extracted from each rule in test ruleset. // note, this is not supposed to contain "container", as that's an event // not mapped through the ppm_sc_code enumerative. auto rules_sc_set = m_engine->sc_codes_for_ruleset(s_sample_source); auto rules_sc_names = libsinsp::events::sc_set_to_event_names(rules_sc_set); - ASSERT_NAMES_EQ(rules_sc_names, strset_t({ - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read"})); + ASSERT_NAMES_EQ(rules_sc_names, + strset_t({"connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", + "read"})); } -TEST_F(test_falco_engine, preconditions_postconditions) -{ +TEST_F(test_falco_engine, preconditions_postconditions) { load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml"); falco::app::state s1; @@ -131,8 +139,7 @@ TEST_F(test_falco_engine, preconditions_postconditions) ASSERT_EQ(prev_selection_size, s1.selected_sc_set.size()); } -TEST_F(test_falco_engine, engine_codes_nonsyscalls_set) -{ +TEST_F(test_falco_engine, engine_codes_nonsyscalls_set) { auto filters = s_sample_filters; filters.insert(s_sample_generic_filters.begin(), s_sample_generic_filters.end()); filters.insert(s_sample_nonsyscall_filters.begin(), s_sample_nonsyscall_filters.end()); @@ -149,22 +156,44 @@ TEST_F(test_falco_engine, engine_codes_nonsyscalls_set) // PPME_GENERIC_E will cause all names of generic events to be added! // This is a good example of information loss from ppm_event_code <-> ppm_sc_code. auto generic_names = libsinsp::events::event_set_to_names({ppm_event_code::PPME_GENERIC_E}); - auto expected_names = strset_t({ - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read", "container", // ruleset - "procexit", "switch", "pluginevent", "asyncevent"}); // from non-syscall event filters + auto expected_names = strset_t({"connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", + "read", + "container", // ruleset + "procexit", + "switch", + "pluginevent", + "asyncevent"}); // from non-syscall event filters expected_names.insert(generic_names.begin(), generic_names.end()); ASSERT_NAMES_EQ(rules_event_names, expected_names); auto rules_sc_set = m_engine->sc_codes_for_ruleset(s_sample_source); auto rules_sc_names = libsinsp::events::sc_set_to_event_names(rules_sc_set); - ASSERT_NAMES_EQ(rules_sc_names, strset_t({ - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read", - "procexit", "switch", "syncfs", "fanotify_init", // from generic event filters - })); + ASSERT_NAMES_EQ(rules_sc_names, + strset_t({ + "connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", + "read", + "procexit", + "switch", + "syncfs", + "fanotify_init", // from generic event filters + })); } -TEST_F(test_falco_engine, selection_not_allevents) -{ +TEST_F(test_falco_engine, selection_not_allevents) { load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml"); falco::app::state s2; @@ -184,10 +213,22 @@ TEST_F(test_falco_engine, selection_not_allevents) ASSERT_GT(s2.selected_sc_set.size(), 1); auto selected_sc_names = libsinsp::events::sc_set_to_event_names(s2.selected_sc_set); auto expected_sc_names = strset_t({ - // note: we expect the "read" syscall to have been erased - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", // from ruleset - "clone", "clone3", "fork", "vfork", // from sinsp state set (spawned_process) - "socket", "bind", "close" // from sinsp state set (network, files) + // note: we expect the "read" syscall to have been erased + "connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", // from ruleset + "clone", + "clone3", + "fork", + "vfork", // from sinsp state set (spawned_process) + "socket", + "bind", + "close" // from sinsp state set (network, files) }); ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names); @@ -199,8 +240,7 @@ TEST_F(test_falco_engine, selection_not_allevents) // check that final selected set is exactly sinsp state + ruleset auto rule_set = s2.engine->sc_codes_for_ruleset(s_sample_source, s_sample_ruleset); auto state_set = libsinsp::events::sinsp_state_sc_set(); - for (const auto &erased : ignored_set) - { + for(const auto& erased : ignored_set) { rule_set.remove(erased); state_set.remove(erased); } @@ -210,8 +250,7 @@ TEST_F(test_falco_engine, selection_not_allevents) ASSERT_EQ(s2.selected_sc_set, union_set); } -TEST_F(test_falco_engine, selection_allevents) -{ +TEST_F(test_falco_engine, selection_allevents) { load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml"); falco::app::state s3; @@ -229,10 +268,23 @@ TEST_F(test_falco_engine, selection_allevents) ASSERT_GT(s3.selected_sc_set.size(), 1); auto selected_sc_names = libsinsp::events::sc_set_to_event_names(s3.selected_sc_set); auto expected_sc_names = strset_t({ - // note: we expect the "read" syscall to not be erased - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read", // from ruleset - "clone", "clone3", "fork", "vfork", // from sinsp state set (spawned_process) - "socket", "bind", "close" // from sinsp state set (network, files) + // note: we expect the "read" syscall to not be erased + "connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", + "read", // from ruleset + "clone", + "clone3", + "fork", + "vfork", // from sinsp state set (spawned_process) + "socket", + "bind", + "close" // from sinsp state set (network, files) }); ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names); @@ -245,8 +297,7 @@ TEST_F(test_falco_engine, selection_allevents) ASSERT_EQ(s3.selected_sc_set, union_set); } -TEST_F(test_falco_engine, selection_generic_evts) -{ +TEST_F(test_falco_engine, selection_generic_evts) { falco::app::state s4; // run app action with fake engine and without the `-A` option s4.options.all_events = false; @@ -262,14 +313,28 @@ TEST_F(test_falco_engine, selection_generic_evts) ASSERT_GT(s4.selected_sc_set.size(), 1); auto selected_sc_names = libsinsp::events::sc_set_to_event_names(s4.selected_sc_set); auto expected_sc_names = strset_t({ - // note: we expect the "read" syscall to not be erased - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", // from ruleset - "syncfs", "fanotify_init", // from ruleset (generic events) - "clone", "clone3", "fork", "vfork", // from sinsp state set (spawned_process) - "socket", "bind", "close" // from sinsp state set (network, files) + // note: we expect the "read" syscall to not be erased + "connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", // from ruleset + "syncfs", + "fanotify_init", // from ruleset (generic events) + "clone", + "clone3", + "fork", + "vfork", // from sinsp state set (spawned_process) + "socket", + "bind", + "close" // from sinsp state set (network, files) }); ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names); - auto unexpected_sc_names = libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set()); + auto unexpected_sc_names = + libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set()); ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names); } @@ -278,8 +343,7 @@ TEST_F(test_falco_engine, selection_generic_evts) // (either default or custom positive set) // - events in the custom negative set are removed from the selected set // - if `-A` is not set, events from the IO set are removed from the selected set -TEST_F(test_falco_engine, selection_custom_base_set) -{ +TEST_F(test_falco_engine, selection_custom_base_set) { load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml"); falco::app::state s5; @@ -295,17 +359,24 @@ TEST_F(test_falco_engine, selection_custom_base_set) ASSERT_TRUE(result.success); ASSERT_EQ(result.errstr, ""); auto selected_sc_names = libsinsp::events::sc_set_to_event_names(s5.selected_sc_set); - auto expected_sc_names = strset_t({ - // note: `syncfs` has been added due to the custom base set, and `accept` - // has been remove due to the negative base set. - // note: `read` is not ignored due to the "-A" option being set. - // note: `accept` is not included even though it is matched by the rules, - // which means that the custom negation base set has precedence over the - // final selection set as a whole - // note(jasondellaluce): "accept4" should be added, however old versions - // of the ACCEPT4 event are actually named "accept" in the event table - "connect", "umount2", "open", "ptrace", "mmap", "execve", "read", "syncfs", "procexit" - }); + auto expected_sc_names = + strset_t({// note: `syncfs` has been added due to the custom base set, and `accept` + // has been remove due to the negative base set. + // note: `read` is not ignored due to the "-A" option being set. + // note: `accept` is not included even though it is matched by the rules, + // which means that the custom negation base set has precedence over the + // final selection set as a whole + // note(jasondellaluce): "accept4" should be added, however old versions + // of the ACCEPT4 event are actually named "accept" in the event table + "connect", + "umount2", + "open", + "ptrace", + "mmap", + "execve", + "read", + "syncfs", + "procexit"}); ASSERT_NAMES_EQ(selected_sc_names, expected_sc_names); // non-empty custom base set (both positive and negative with collision) @@ -325,10 +396,18 @@ TEST_F(test_falco_engine, selection_custom_base_set) ASSERT_TRUE(result.success); ASSERT_EQ(result.errstr, ""); selected_sc_names = libsinsp::events::sc_set_to_event_names(s5.selected_sc_set); - expected_sc_names = strset_t({ - // note: accept is not negated anymore - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read", "syncfs", "procexit" - }); + expected_sc_names = strset_t({// note: accept is not negated anymore + "connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", + "read", + "syncfs", + "procexit"}); ASSERT_NAMES_EQ(selected_sc_names, expected_sc_names); // non-empty custom base set (only negative) @@ -338,8 +417,8 @@ TEST_F(test_falco_engine, selection_custom_base_set) ASSERT_EQ(result.errstr, ""); selected_sc_names = libsinsp::events::sc_set_to_event_names(s5.selected_sc_set); expected_sc_names = unordered_set_union( - libsinsp::events::sc_set_to_event_names(default_base_set), - strset_t({ "connect", "umount2", "open", "ptrace", "mmap", "execve", "read"})); + libsinsp::events::sc_set_to_event_names(default_base_set), + strset_t({"connect", "umount2", "open", "ptrace", "mmap", "execve", "read"})); expected_sc_names.erase("accept"); // note(jasondellaluce): "accept4" should be included, however old versions // of the ACCEPT4 event are actually named "accept" in the event table @@ -353,18 +432,24 @@ TEST_F(test_falco_engine, selection_custom_base_set) ASSERT_TRUE(result.success); ASSERT_EQ(result.errstr, ""); selected_sc_names = libsinsp::events::sc_set_to_event_names(s5.selected_sc_set); - expected_sc_names = strset_t({ - // note: read is both part of the custom base set and the rules set, - // but we expect the unset -A option to take precedence - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "procexit" - }); + expected_sc_names = strset_t({// note: read is both part of the custom base set and the rules + // set, but we expect the unset -A option to take precedence + "connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", + "procexit"}); ASSERT_NAMES_EQ(selected_sc_names, expected_sc_names); - auto unexpected_sc_names = libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set()); + auto unexpected_sc_names = + libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set()); ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names); } -TEST_F(test_falco_engine, selection_custom_base_set_repair) -{ +TEST_F(test_falco_engine, selection_custom_base_set_repair) { load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml"); falco::app::state s6; @@ -383,18 +468,29 @@ TEST_F(test_falco_engine, selection_custom_base_set_repair) ASSERT_TRUE(result.success); ASSERT_EQ(result.errstr, ""); auto selected_sc_names = libsinsp::events::sc_set_to_event_names(s6.selected_sc_set); - auto expected_sc_names = strset_t({ - // note: expecting syscalls from mock rules and `sinsp_repair_state_sc_set` enforced syscalls - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "procexit", \ - "bind", "socket", "clone3", "close", "setuid" - }); + auto expected_sc_names = strset_t({// note: expecting syscalls from mock rules and + // `sinsp_repair_state_sc_set` enforced syscalls + "connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", + "procexit", + "bind", + "socket", + "clone3", + "close", + "setuid"}); ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names); - auto unexpected_sc_names = libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set()); + auto unexpected_sc_names = + libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set()); ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names); } -TEST_F(test_falco_engine, selection_empty_custom_base_set_repair) -{ +TEST_F(test_falco_engine, selection_empty_custom_base_set_repair) { load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml"); falco::app::state s7; @@ -410,23 +506,34 @@ TEST_F(test_falco_engine, selection_empty_custom_base_set_repair) ASSERT_TRUE(result.success); ASSERT_EQ(result.errstr, ""); auto selected_sc_names = libsinsp::events::sc_set_to_event_names(s7.selected_sc_set); - auto expected_sc_names = strset_t({ - // note: expecting syscalls from mock rules and `sinsp_repair_state_sc_set` enforced syscalls - "connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "procexit", \ - "bind", "socket", "clone3", "close", "setuid" - }); + auto expected_sc_names = strset_t({// note: expecting syscalls from mock rules and + // `sinsp_repair_state_sc_set` enforced syscalls + "connect", + "accept", + "accept4", + "umount2", + "open", + "ptrace", + "mmap", + "execve", + "procexit", + "bind", + "socket", + "clone3", + "close", + "setuid"}); ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names); auto s7_state_set = libsinsp::events::sinsp_repair_state_sc_set(s7_rules_set); ASSERT_EQ(s7.selected_sc_set, s7_state_set); ASSERT_EQ(s7.selected_sc_set.size(), s7_state_set.size()); } -TEST(ConfigureInterestingSets, ignored_set_expected_size) -{ +TEST(ConfigureInterestingSets, ignored_set_expected_size) { // unit test fence to make sure we don't have unexpected regressions // in the ignored set, to be updated in the future ASSERT_EQ(falco::app::ignored_sc_set().size(), 14); // we don't expect to ignore any syscall in the default base set - ASSERT_EQ(falco::app::ignored_sc_set().intersect(libsinsp::events::sinsp_state_sc_set()).size(), 0); + ASSERT_EQ(falco::app::ignored_sc_set().intersect(libsinsp::events::sinsp_state_sc_set()).size(), + 0); } diff --git a/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp b/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp index 4e30f70a29c..1570eb8ca76 100644 --- a/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp +++ b/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp @@ -17,13 +17,11 @@ limitations under the License. #include "app_action_helpers.h" -TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs) -{ +TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs) { auto action = falco::app::actions::configure_syscall_buffer_num; ssize_t online_cpus = sysconf(_SC_NPROCESSORS_ONLN); - if(online_cpus <= 0) - { + if(online_cpus <= 0) { FAIL() << "cannot get the number of online CPUs from the system\n"; } diff --git a/unit_tests/falco/app/actions/test_load_config.cpp b/unit_tests/falco/app/actions/test_load_config.cpp index 39766ef70e5..fecfac7f199 100644 --- a/unit_tests/falco/app/actions/test_load_config.cpp +++ b/unit_tests/falco/app/actions/test_load_config.cpp @@ -19,8 +19,7 @@ limitations under the License. #include "falco_test_var.h" #ifndef __EMSCRIPTEN__ -TEST(ActionLoadConfig, check_kmod_engine_config) -{ +TEST(ActionLoadConfig, check_kmod_engine_config) { falco::app::state s = {}; s.options.conf_filename = TEST_ENGINE_KMOD_CONFIG; EXPECT_ACTION_OK(falco::app::actions::load_config(s)); @@ -47,8 +46,7 @@ TEST(ActionLoadConfig, check_kmod_engine_config) EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); } -TEST(ActionLoadConfig, check_modern_engine_config) -{ +TEST(ActionLoadConfig, check_modern_engine_config) { falco::app::state s = {}; s.options.conf_filename = TEST_ENGINE_MODERN_CONFIG; EXPECT_ACTION_OK(falco::app::actions::load_config(s)); diff --git a/unit_tests/falco/app/actions/test_select_event_sources.cpp b/unit_tests/falco/app/actions/test_select_event_sources.cpp index 79a51f1737b..1443c86994a 100644 --- a/unit_tests/falco/app/actions/test_select_event_sources.cpp +++ b/unit_tests/falco/app/actions/test_select_event_sources.cpp @@ -17,85 +17,82 @@ limitations under the License. #include "app_action_helpers.h" -TEST(ActionSelectEventSources, pre_post_conditions) -{ - auto action = falco::app::actions::select_event_sources; +TEST(ActionSelectEventSources, pre_post_conditions) { + auto action = falco::app::actions::select_event_sources; - // requires sources to be already loaded - { - falco::app::state s; - EXPECT_ACTION_FAIL(action(s)); - } + // requires sources to be already loaded + { + falco::app::state s; + EXPECT_ACTION_FAIL(action(s)); + } - // ignore source selection in capture mode - { - falco::app::state s; - s.config->m_engine_mode = engine_kind_t::REPLAY; - EXPECT_TRUE(s.is_capture_mode()); - EXPECT_ACTION_OK(action(s)); - } + // ignore source selection in capture mode + { + falco::app::state s; + s.config->m_engine_mode = engine_kind_t::REPLAY; + EXPECT_TRUE(s.is_capture_mode()); + EXPECT_ACTION_OK(action(s)); + } - // enable all loaded sources by default, even with multiple calls - { - falco::app::state s; - s.loaded_sources = {"syscall", "some_source"}; - EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.loaded_sources.size(), s.enabled_sources.size()); - for (const auto& v : s.loaded_sources) - { - ASSERT_TRUE(s.enabled_sources.find(v) != s.enabled_sources.end()); - } - s.loaded_sources.push_back("another_source"); - EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.loaded_sources.size(), s.enabled_sources.size()); - for (const auto& v : s.loaded_sources) - { - ASSERT_TRUE(s.enabled_sources.find(v) != s.enabled_sources.end()); - } - } + // enable all loaded sources by default, even with multiple calls + { + falco::app::state s; + s.loaded_sources = {"syscall", "some_source"}; + EXPECT_ACTION_OK(action(s)); + EXPECT_EQ(s.loaded_sources.size(), s.enabled_sources.size()); + for(const auto& v : s.loaded_sources) { + ASSERT_TRUE(s.enabled_sources.find(v) != s.enabled_sources.end()); + } + s.loaded_sources.push_back("another_source"); + EXPECT_ACTION_OK(action(s)); + EXPECT_EQ(s.loaded_sources.size(), s.enabled_sources.size()); + for(const auto& v : s.loaded_sources) { + ASSERT_TRUE(s.enabled_sources.find(v) != s.enabled_sources.end()); + } + } - // enable only selected sources - { - falco::app::state s; - s.loaded_sources = {"syscall", "some_source"}; - s.options.enable_sources = {"syscall"}; - EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.enabled_sources.size(), 1); - EXPECT_EQ(*s.enabled_sources.begin(), "syscall"); - } + // enable only selected sources + { + falco::app::state s; + s.loaded_sources = {"syscall", "some_source"}; + s.options.enable_sources = {"syscall"}; + EXPECT_ACTION_OK(action(s)); + EXPECT_EQ(s.enabled_sources.size(), 1); + EXPECT_EQ(*s.enabled_sources.begin(), "syscall"); + } - // enable all loaded sources expect the disabled ones - { - falco::app::state s; - s.loaded_sources = {"syscall", "some_source"}; - s.options.disable_sources = {"syscall"}; - EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.enabled_sources.size(), 1); - EXPECT_EQ(*s.enabled_sources.begin(), "some_source"); - } + // enable all loaded sources expect the disabled ones + { + falco::app::state s; + s.loaded_sources = {"syscall", "some_source"}; + s.options.disable_sources = {"syscall"}; + EXPECT_ACTION_OK(action(s)); + EXPECT_EQ(s.enabled_sources.size(), 1); + EXPECT_EQ(*s.enabled_sources.begin(), "some_source"); + } - // enable unknown sources - { - falco::app::state s; - s.loaded_sources = {"syscall", "some_source"}; - s.options.enable_sources = {"some_other_source"}; - EXPECT_ACTION_FAIL(action(s)); - } + // enable unknown sources + { + falco::app::state s; + s.loaded_sources = {"syscall", "some_source"}; + s.options.enable_sources = {"some_other_source"}; + EXPECT_ACTION_FAIL(action(s)); + } - // disable unknown sources - { - falco::app::state s; - s.loaded_sources = {"syscall", "some_source"}; - s.options.disable_sources = {"some_other_source"}; - EXPECT_ACTION_FAIL(action(s)); - } + // disable unknown sources + { + falco::app::state s; + s.loaded_sources = {"syscall", "some_source"}; + s.options.disable_sources = {"some_other_source"}; + EXPECT_ACTION_FAIL(action(s)); + } - // mix enable and disable sources options - { - falco::app::state s; - s.loaded_sources = {"syscall", "some_source"}; - s.options.disable_sources = {"syscall"}; - s.options.enable_sources = {"syscall"}; - EXPECT_ACTION_FAIL(action(s)); - } + // mix enable and disable sources options + { + falco::app::state s; + s.loaded_sources = {"syscall", "some_source"}; + s.options.disable_sources = {"syscall"}; + s.options.enable_sources = {"syscall"}; + EXPECT_ACTION_FAIL(action(s)); + } } diff --git a/unit_tests/falco/test_atomic_signal_handler.cpp b/unit_tests/falco/test_atomic_signal_handler.cpp index 9d2edbe6da3..2bc7afe43cf 100644 --- a/unit_tests/falco/test_atomic_signal_handler.cpp +++ b/unit_tests/falco/test_atomic_signal_handler.cpp @@ -25,13 +25,11 @@ limitations under the License. #include #include -TEST(AtomicSignalHandler, lock_free_implementation) -{ +TEST(AtomicSignalHandler, lock_free_implementation) { ASSERT_TRUE(falco::atomic_signal_handler().is_lock_free()); } -TEST(AtomicSignalHandler, handle_once_wait_consistency) -{ +TEST(AtomicSignalHandler, handle_once_wait_consistency) { constexpr const auto thread_num = 10; constexpr const std::chrono::seconds thread_wait_sec{2}; constexpr const std::chrono::seconds handler_wait_sec{1}; @@ -40,33 +38,27 @@ TEST(AtomicSignalHandler, handle_once_wait_consistency) falco::atomic_signal_handler handler; // launch a bunch of threads all syncing on the same handler - struct task_result_t - { + struct task_result_t { bool handled; std::chrono::seconds duration_secs; }; std::vector> futures; - for (int i = 0; i < thread_num; i++) - { - futures.emplace_back(std::async(std::launch::async, - [&handler, thread_wait_sec]() { - auto start = std::chrono::high_resolution_clock::now(); - task_result_t res; - res.handled = false; - while (!handler.handled()) - { - if (handler.triggered()) - { - res.handled = handler.handle([thread_wait_sec]() { - std::this_thread::sleep_for(thread_wait_sec); - }); - } + for(int i = 0; i < thread_num; i++) { + futures.emplace_back(std::async(std::launch::async, [&handler, thread_wait_sec]() { + auto start = std::chrono::high_resolution_clock::now(); + task_result_t res; + res.handled = false; + while(!handler.handled()) { + if(handler.triggered()) { + res.handled = handler.handle( + [thread_wait_sec]() { std::this_thread::sleep_for(thread_wait_sec); }); } - auto diff = std::chrono::high_resolution_clock::now() - start; - res.duration_secs = std::chrono::duration_cast(diff); - return res; - })); + } + auto diff = std::chrono::high_resolution_clock::now() - start; + res.duration_secs = std::chrono::duration_cast(diff); + return res; + })); } // wait a bit, then trigger the signal handler from the main thread @@ -74,12 +66,10 @@ TEST(AtomicSignalHandler, handle_once_wait_consistency) auto start = std::chrono::high_resolution_clock::now(); std::this_thread::sleep_for(handler_wait_sec); handler.trigger(); - for (int i = 0; i < thread_num; i++) - { + for(int i = 0; i < thread_num; i++) { // wait for all threads to finish and get the results from the futures auto res = futures[i].get(); - if (res.handled) - { + if(res.handled) { total_handled++; } ASSERT_GE(res.duration_secs, thread_wait_sec); @@ -94,9 +84,8 @@ TEST(AtomicSignalHandler, handle_once_wait_consistency) ASSERT_EQ(total_handled, 1); } -TEST(AtomicSignalHandler, handle_and_reset) -{ - auto do_nothing = []{}; +TEST(AtomicSignalHandler, handle_and_reset) { + auto do_nothing = [] {}; falco::atomic_signal_handler handler; ASSERT_FALSE(handler.triggered()); diff --git a/unit_tests/falco/test_configuration.cpp b/unit_tests/falco/test_configuration.cpp index 90c152aa4f9..5162a864053 100644 --- a/unit_tests/falco/test_configuration.cpp +++ b/unit_tests/falco/test_configuration.cpp @@ -19,20 +19,19 @@ limitations under the License. #include static std::string sample_yaml = - "base_value:\n" - " id: 1\n" - " name: 'sample_name'\n" - " subvalue:\n" - " subvalue2:\n" - " boolean: true\n" - "base_value_2:\n" - " sample_list:\n" - " - elem1\n" - " - elem2\n" - " - elem3\n"; - -TEST(Configuration, configuration_exceptions) -{ + "base_value:\n" + " id: 1\n" + " name: 'sample_name'\n" + " subvalue:\n" + " subvalue2:\n" + " boolean: true\n" + "base_value_2:\n" + " sample_list:\n" + " - elem1\n" + " - elem2\n" + " - elem3\n"; + +TEST(Configuration, configuration_exceptions) { yaml_helper conf; /* Broken YAML */ @@ -43,8 +42,7 @@ TEST(Configuration, configuration_exceptions) EXPECT_NO_THROW(conf.load_from_string(sample_yaml)); } -TEST(Configuration, configuration_reload) -{ +TEST(Configuration, configuration_reload) { yaml_helper conf; /* Clear and reload config */ @@ -56,8 +54,7 @@ TEST(Configuration, configuration_reload) ASSERT_TRUE(conf.is_defined("base_value")); } -TEST(Configuration, read_yaml_fields) -{ +TEST(Configuration, read_yaml_fields) { yaml_helper conf; conf.load_from_string(sample_yaml); @@ -72,9 +69,12 @@ TEST(Configuration, read_yaml_fields) ASSERT_EQ(conf.get_scalar("base_value.subvalue.subvalue2.boolean", false), true); /* get list field elements */ - ASSERT_STREQ(conf.get_scalar("base_value_2.sample_list[0]", "none").c_str(), "elem1"); - ASSERT_STREQ(conf.get_scalar("base_value_2.sample_list[1]", "none").c_str(), "elem2"); - ASSERT_STREQ(conf.get_scalar("base_value_2.sample_list[2]", "none").c_str(), "elem3"); + ASSERT_STREQ(conf.get_scalar("base_value_2.sample_list[0]", "none").c_str(), + "elem1"); + ASSERT_STREQ(conf.get_scalar("base_value_2.sample_list[1]", "none").c_str(), + "elem2"); + ASSERT_STREQ(conf.get_scalar("base_value_2.sample_list[2]", "none").c_str(), + "elem3"); /* get sequence */ std::vector seq; @@ -85,100 +85,100 @@ TEST(Configuration, read_yaml_fields) ASSERT_STREQ(seq[2].c_str(), "elem3"); } -TEST(Configuration, modify_yaml_fields) -{ +TEST(Configuration, modify_yaml_fields) { std::string key = "base_value.subvalue.subvalue2.boolean"; yaml_helper conf; - /* Get original value */ - conf.load_from_string(sample_yaml); + /* Get original value */ + conf.load_from_string(sample_yaml); ASSERT_EQ(conf.get_scalar(key, false), true); - /* Modify the original value */ - conf.set_scalar(key, false); + /* Modify the original value */ + conf.set_scalar(key, false); ASSERT_EQ(conf.get_scalar(key, true), false); - /* Modify it again */ - conf.set_scalar(key, true); + /* Modify it again */ + conf.set_scalar(key, true); ASSERT_EQ(conf.get_scalar(key, false), true); } -TEST(Configuration, configuration_webserver_ip) -{ - falco_configuration falco_config; - - std::vector valid_addresses = {"127.0.0.1", - "1.127.0.1", - "1.1.127.1", - "1.1.1.127", - "::", - "::1", - "1200:0000:AB00:1234:0000:2552:7777:1313", - "1200::AB00:1234:0000:2552:7777:1313", - "1200:0000:AB00:1234::2552:7777:1313", - "21DA:D3:0:2F3B:2AA:FF:FE28:9C5A", - "FE80:0000:0000:0000:0202:B3FF:FE1E:8329", - "0.0.0.0", - "9.255.255.255", - "11.0.0.0", - "126.255.255.255", - "129.0.0.0", - "169.253.255.255", - "169.255.0.0", - "172.15.255.255", - "172.32.0.0", - "191.0.1.255", - "192.88.98.255", - "192.88.100.0", - "192.167.255.255", - "192.169.0.0", - "198.17.255.255", - "223.255.255.255"}; - - for (const std::string &address: valid_addresses) { - std::string option = "webserver.listen_address="; - option.append(address); - - std::vector cmdline_config_options; - cmdline_config_options.push_back(option); - - EXPECT_NO_THROW(falco_config.init_from_content("", cmdline_config_options)); - - ASSERT_EQ(falco_config.m_webserver_config.m_listen_address, address); - } - - std::vector invalid_addresses = {"327.0.0.1", - "1.327.0.1", - "1.1.327.1", - "1.1.1.327", - "12 7.0.0.1", - "127. 0.0.1", - "127.0. 0.1", - "127.0.0. 1", - "!27.0.0.1", - "1200: 0000:AB00:1234:0000:2552:7777:1313", - "1200:0000: AB00:1234:0000:2552:7777:1313", - "1200:0000:AB00: 1234:0000:2552:7777:1313", - "1200:0000:AB00:1234: 0000:2552:7777:1313", - "1200:0000:AB00:1234:0000: 2552:7777:1313", - "1200:0000:AB00:1234:0000:2552: 7777:1313", - "1200:0000:AB00:1234:0000:2552:7777: 1313", - "1200:0000:AB00:1234:0000:2552:7777:131G", - "1200:0000:AB00:1234:0000:2552:77Z7:1313", - "1200:0000:AB00:1234:0000:2G52:7777:1313", - "1200:0000:AB00:1234:0O00:2552:7777:1313", - "1200:0000:AB00:H234:0000:2552:7777:1313", - "1200:0000:IB00:1234:0000:2552:7777:1313", - "1200:0O00:AB00:1234:0000:2552:7777:1313", - "12O0:0000:AB00:1234:0000:2552:7777:1313",}; - - for (const std::string &address: invalid_addresses) { - std::string option = "webserver.listen_address="; - option.append(address); - - std::vector cmdline_config_options; - cmdline_config_options.push_back(option); - - EXPECT_ANY_THROW(falco_config.init_from_content("", cmdline_config_options)); - } +TEST(Configuration, configuration_webserver_ip) { + falco_configuration falco_config; + + std::vector valid_addresses = {"127.0.0.1", + "1.127.0.1", + "1.1.127.1", + "1.1.1.127", + "::", + "::1", + "1200:0000:AB00:1234:0000:2552:7777:1313", + "1200::AB00:1234:0000:2552:7777:1313", + "1200:0000:AB00:1234::2552:7777:1313", + "21DA:D3:0:2F3B:2AA:FF:FE28:9C5A", + "FE80:0000:0000:0000:0202:B3FF:FE1E:8329", + "0.0.0.0", + "9.255.255.255", + "11.0.0.0", + "126.255.255.255", + "129.0.0.0", + "169.253.255.255", + "169.255.0.0", + "172.15.255.255", + "172.32.0.0", + "191.0.1.255", + "192.88.98.255", + "192.88.100.0", + "192.167.255.255", + "192.169.0.0", + "198.17.255.255", + "223.255.255.255"}; + + for(const std::string &address : valid_addresses) { + std::string option = "webserver.listen_address="; + option.append(address); + + std::vector cmdline_config_options; + cmdline_config_options.push_back(option); + + EXPECT_NO_THROW(falco_config.init_from_content("", cmdline_config_options)); + + ASSERT_EQ(falco_config.m_webserver_config.m_listen_address, address); + } + + std::vector invalid_addresses = { + "327.0.0.1", + "1.327.0.1", + "1.1.327.1", + "1.1.1.327", + "12 7.0.0.1", + "127. 0.0.1", + "127.0. 0.1", + "127.0.0. 1", + "!27.0.0.1", + "1200: 0000:AB00:1234:0000:2552:7777:1313", + "1200:0000: AB00:1234:0000:2552:7777:1313", + "1200:0000:AB00: 1234:0000:2552:7777:1313", + "1200:0000:AB00:1234: 0000:2552:7777:1313", + "1200:0000:AB00:1234:0000: 2552:7777:1313", + "1200:0000:AB00:1234:0000:2552: 7777:1313", + "1200:0000:AB00:1234:0000:2552:7777: 1313", + "1200:0000:AB00:1234:0000:2552:7777:131G", + "1200:0000:AB00:1234:0000:2552:77Z7:1313", + "1200:0000:AB00:1234:0000:2G52:7777:1313", + "1200:0000:AB00:1234:0O00:2552:7777:1313", + "1200:0000:AB00:H234:0000:2552:7777:1313", + "1200:0000:IB00:1234:0000:2552:7777:1313", + "1200:0O00:AB00:1234:0000:2552:7777:1313", + "12O0:0000:AB00:1234:0000:2552:7777:1313", + }; + + for(const std::string &address : invalid_addresses) { + std::string option = "webserver.listen_address="; + option.append(address); + + std::vector cmdline_config_options; + cmdline_config_options.push_back(option); + + EXPECT_ANY_THROW(falco_config.init_from_content("", cmdline_config_options)); + } } diff --git a/unit_tests/falco/test_configuration_config_files.cpp b/unit_tests/falco/test_configuration_config_files.cpp index 364e91b73ce..bf4a5ed00f9 100644 --- a/unit_tests/falco/test_configuration_config_files.cpp +++ b/unit_tests/falco/test_configuration_config_files.cpp @@ -18,23 +18,23 @@ limitations under the License. #include #include -TEST(Configuration, configuration_config_files_secondary_fail) -{ - /* Test that a secondary config file is not able to include anything, triggering an exception. */ - const std::string main_conf_yaml = - yaml_helper::configs_key + ":\n" - " - conf_2.yaml\n" - " - conf_3.yaml\n" - "foo: bar\n" - "base_value:\n" - " id: 1\n" - " name: foo\n"; - const std::string conf_yaml_2 = - yaml_helper::configs_key + ":\n" - " - conf_4.yaml\n" - "foo2: bar2\n" - "base_value_2:\n" - " id: 2\n"; +TEST(Configuration, configuration_config_files_secondary_fail) { + /* Test that a secondary config file is not able to include anything, triggering an exception. + */ + const std::string main_conf_yaml = yaml_helper::configs_key + + ":\n" + " - conf_2.yaml\n" + " - conf_3.yaml\n" + "foo: bar\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; + const std::string conf_yaml_2 = yaml_helper::configs_key + + ":\n" + " - conf_4.yaml\n" + "foo2: bar2\n" + "base_value_2:\n" + " id: 2\n"; std::ofstream outfile("main.yaml"); outfile << main_conf_yaml; @@ -52,29 +52,28 @@ TEST(Configuration, configuration_config_files_secondary_fail) std::filesystem::remove("conf_2.yaml"); } -TEST(Configuration, configuration_config_files_ok) -{ +TEST(Configuration, configuration_config_files_ok) { /* Test that every included config file was correctly parsed */ - const std::string main_conf_yaml = - yaml_helper::configs_key + ":\n" - " - conf_2.yaml\n" - " - conf_3.yaml\n" - "foo: bar\n" - "base_value:\n" - " id: 1\n" - " name: foo\n"; + const std::string main_conf_yaml = yaml_helper::configs_key + + ":\n" + " - conf_2.yaml\n" + " - conf_3.yaml\n" + "foo: bar\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; const std::string conf_yaml_2 = - "foo2: bar2\n" - "base_value_2:\n" - " id: 2\n"; + "foo2: bar2\n" + "base_value_2:\n" + " id: 2\n"; const std::string conf_yaml_3 = - "foo3: bar3\n" - "base_value_3:\n" - " id: 3\n" - " name: foo3\n"; + "foo3: bar3\n" + "base_value_3:\n" + " id: 3\n" + " name: foo3\n"; const std::string conf_yaml_4 = - "base_value_4:\n" - " id: 4\n"; + "base_value_4:\n" + " id: 4\n"; std::ofstream outfile("main.yaml"); outfile << main_conf_yaml; @@ -117,7 +116,7 @@ TEST(Configuration, configuration_config_files_ok) ASSERT_EQ(falco_config.m_config.get_scalar("base_value_3.id", 0), 3); ASSERT_TRUE(falco_config.m_config.is_defined("base_value_3.name")); ASSERT_EQ(falco_config.m_config.get_scalar("base_value_3.name", ""), "foo3"); - ASSERT_FALSE(falco_config.m_config.is_defined("base_value_4.id")); // conf_4 is not included + ASSERT_FALSE(falco_config.m_config.is_defined("base_value_4.id")); // conf_4 is not included std::filesystem::remove("main.yaml"); std::filesystem::remove("conf_2.yaml"); @@ -125,9 +124,7 @@ TEST(Configuration, configuration_config_files_ok) std::filesystem::remove("conf_4.yaml"); } - -TEST(Configuration, configuration_config_files_relative_main) -{ +TEST(Configuration, configuration_config_files_relative_main) { /* * Test that relative path are treated as relative to cwd and not to main config folder, * and that absolute includes are ok too. @@ -135,24 +132,25 @@ TEST(Configuration, configuration_config_files_relative_main) const auto temp_main = std::filesystem::temp_directory_path() / "main.yaml"; // So, conf_2 will be looked up in the same folder as main config file, // while conf_3, since is absolute, will be looked up in the absolute path (and found!). - const std::string main_conf_yaml = - yaml_helper::configs_key + ":\n" - " - conf_2.yaml\n" - " - " + - std::filesystem::current_path().string() + "/conf_3.yaml\n" - "foo: bar\n" - "base_value:\n" - " id: 1\n" - " name: foo\n"; + const std::string main_conf_yaml = yaml_helper::configs_key + + ":\n" + " - conf_2.yaml\n" + " - " + + std::filesystem::current_path().string() + + "/conf_3.yaml\n" + "foo: bar\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; const std::string conf_yaml_2 = - "foo2: bar2\n" - "base_value_2:\n" - " id: 2\n"; + "foo2: bar2\n" + "base_value_2:\n" + " id: 2\n"; const std::string conf_yaml_3 = - "foo3: bar3\n" - "base_value_3:\n" - " id: 3\n" - " name: foo3\n"; + "foo3: bar3\n" + "base_value_3:\n" + " id: 3\n" + " name: foo3\n"; std::ofstream outfile(temp_main.string()); outfile << main_conf_yaml; @@ -192,24 +190,23 @@ TEST(Configuration, configuration_config_files_relative_main) std::filesystem::remove("conf_3.yaml"); } -TEST(Configuration, configuration_config_files_override) -{ +TEST(Configuration, configuration_config_files_override) { /* Test that included config files are able to override configs from main file */ - const std::string main_conf_yaml = - yaml_helper::configs_key + ":\n" - " - conf_2.yaml\n" - " - conf_3.yaml\n" - "foo: bar\n" - "base_value:\n" - " id: 1\n" - " name: foo\n"; + const std::string main_conf_yaml = yaml_helper::configs_key + + ":\n" + " - conf_2.yaml\n" + " - conf_3.yaml\n" + "foo: bar\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; const std::string conf_yaml_2 = - "foo2: bar2\n" - "base_value_2:\n" - " id: 2\n"; + "foo2: bar2\n" + "base_value_2:\n" + " id: 2\n"; const std::string conf_yaml_3 = - "base_value:\n" - " id: 3\n"; + "base_value:\n" + " id: 3\n"; std::ofstream outfile("main.yaml"); outfile << main_conf_yaml; @@ -234,28 +231,28 @@ TEST(Configuration, configuration_config_files_override) ASSERT_TRUE(falco_config.m_config.is_defined("foo")); ASSERT_EQ(falco_config.m_config.get_scalar("foo", ""), "bar"); ASSERT_TRUE(falco_config.m_config.is_defined("base_value.id")); - ASSERT_EQ(falco_config.m_config.get_scalar("base_value.id", 0), 3); // overridden! - ASSERT_FALSE(falco_config.m_config.is_defined("base_value.name")); // no more present since entire `base_value` block was overridden + ASSERT_EQ(falco_config.m_config.get_scalar("base_value.id", 0), 3); // overridden! + ASSERT_FALSE(falco_config.m_config.is_defined( + "base_value.name")); // no more present since entire `base_value` block was overridden ASSERT_TRUE(falco_config.m_config.is_defined("foo2")); ASSERT_EQ(falco_config.m_config.get_scalar("foo2", ""), "bar2"); ASSERT_TRUE(falco_config.m_config.is_defined("base_value_2.id")); ASSERT_EQ(falco_config.m_config.get_scalar("base_value_2.id", 0), 2); - ASSERT_FALSE(falco_config.m_config.is_defined("base_value_3.id")); // not defined + ASSERT_FALSE(falco_config.m_config.is_defined("base_value_3.id")); // not defined std::filesystem::remove("main.yaml"); std::filesystem::remove("conf_2.yaml"); std::filesystem::remove("conf_3.yaml"); } -TEST(Configuration, configuration_config_files_unexistent) -{ +TEST(Configuration, configuration_config_files_unexistent) { /* Test that including an unexistent file just skips it */ - const std::string main_conf_yaml = - yaml_helper::configs_key + ":\n" - " - conf_5.yaml\n" - "base_value:\n" - " id: 1\n" - " name: foo\n"; + const std::string main_conf_yaml = yaml_helper::configs_key + + ":\n" + " - conf_5.yaml\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; std::ofstream outfile("main.yaml"); outfile << main_conf_yaml; @@ -277,19 +274,19 @@ TEST(Configuration, configuration_config_files_unexistent) std::filesystem::remove("main.yaml"); } -TEST(Configuration, configuration_config_files_scalar_config_files) -{ - /* Test that a single file can be included as a scalar (thanks to get_sequence_from_node magic) */ - const std::string main_conf_yaml = - yaml_helper::configs_key + ": conf_2.yaml\n" - "foo: bar\n" - "base_value:\n" - " id: 1\n" - " name: foo\n"; +TEST(Configuration, configuration_config_files_scalar_config_files) { + /* Test that a single file can be included as a scalar (thanks to get_sequence_from_node magic) + */ + const std::string main_conf_yaml = yaml_helper::configs_key + + ": conf_2.yaml\n" + "foo: bar\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; const std::string conf_yaml_2 = - "foo2: bar2\n" - "base_value_2:\n" - " id: 2\n"; + "foo2: bar2\n" + "base_value_2:\n" + " id: 2\n"; std::ofstream outfile("main.yaml"); outfile << main_conf_yaml; @@ -322,15 +319,14 @@ TEST(Configuration, configuration_config_files_scalar_config_files) std::filesystem::remove("conf_2.yaml"); } -TEST(Configuration, configuration_config_files_empty_config_files) -{ +TEST(Configuration, configuration_config_files_empty_config_files) { /* Test that empty includes list is accepted */ - const std::string main_conf_yaml = - yaml_helper::configs_key + ":\n" - "foo: bar\n" - "base_value:\n" - " id: 1\n" - " name: foo\n"; + const std::string main_conf_yaml = yaml_helper::configs_key + + ":\n" + "foo: bar\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; std::ofstream outfile("main.yaml"); outfile << main_conf_yaml; @@ -354,15 +350,14 @@ TEST(Configuration, configuration_config_files_empty_config_files) std::filesystem::remove("main.yaml"); } -TEST(Configuration, configuration_config_files_self) -{ +TEST(Configuration, configuration_config_files_self) { /* Test that main config file cannot include itself */ - const std::string main_conf_yaml = - yaml_helper::configs_key + ": main.yaml\n" - "foo: bar\n" - "base_value:\n" - " id: 1\n" - " name: foo\n"; + const std::string main_conf_yaml = yaml_helper::configs_key + + ": main.yaml\n" + "foo: bar\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; std::ofstream outfile("main.yaml"); outfile << main_conf_yaml; @@ -375,31 +370,30 @@ TEST(Configuration, configuration_config_files_self) std::filesystem::remove("main.yaml"); } -TEST(Configuration, configuration_config_files_directory) -{ +TEST(Configuration, configuration_config_files_directory) { /* * Test that when main config file includes a config directory, * the config directory is parsed in lexicographic order, * and only regular files are parsed. */ // Main config includes whole temp directory - const std::string main_conf_yaml = - yaml_helper::configs_key + ": " + std::filesystem::temp_directory_path().string() + "/test\n" - "foo: bar\n" - "base_value:\n" - " id: 1\n" - " name: foo\n"; + const std::string main_conf_yaml = yaml_helper::configs_key + ": " + + std::filesystem::temp_directory_path().string() + + "/test\n" + "foo: bar\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; const std::string conf_yaml_2 = - "foo2: bar2\n" - "base_value_2:\n" - " id: 2\n"; + "foo2: bar2\n" + "base_value_2:\n" + " id: 2\n"; const std::string conf_yaml_3 = - "foo2: bar3\n" - "base_value_3:\n" - " id: 3\n" - " name: foo3\n"; - const std::string conf_yaml_4 = - "foo4: bar4\n"; + "foo2: bar3\n" + "base_value_3:\n" + " id: 3\n" + " name: foo3\n"; + const std::string conf_yaml_4 = "foo4: bar4\n"; std::filesystem::create_directory(std::filesystem::temp_directory_path() / "test"); @@ -407,17 +401,17 @@ TEST(Configuration, configuration_config_files_directory) outfile << main_conf_yaml; outfile.close(); - outfile.open(std::filesystem::temp_directory_path()/"test/conf_2.yaml"); + outfile.open(std::filesystem::temp_directory_path() / "test/conf_2.yaml"); outfile << conf_yaml_2; outfile.close(); - outfile.open(std::filesystem::temp_directory_path()/"test/conf_3.yaml"); + outfile.open(std::filesystem::temp_directory_path() / "test/conf_3.yaml"); outfile << conf_yaml_3; outfile.close(); // Create a directory and create a config inside it. We will later check that it was not parsed std::filesystem::create_directory(std::filesystem::temp_directory_path() / "test" / "foo"); - outfile.open(std::filesystem::temp_directory_path()/"test/foo/conf_4.yaml"); + outfile.open(std::filesystem::temp_directory_path() / "test/foo/conf_4.yaml"); outfile << conf_yaml_4; outfile.close(); @@ -445,21 +439,20 @@ TEST(Configuration, configuration_config_files_directory) ASSERT_FALSE(falco_config.m_config.is_defined("foo4")); std::filesystem::remove("main"); - std::filesystem::remove_all(std::filesystem::temp_directory_path()/"test"); + std::filesystem::remove_all(std::filesystem::temp_directory_path() / "test"); } -TEST(Configuration, configuration_config_files_cmdline) -{ +TEST(Configuration, configuration_config_files_cmdline) { /* Test that we support including configs files from cmdline option */ const std::string main_conf_yaml = - "foo: bar\n" - "base_value:\n" - " id: 1\n" - " name: foo\n"; + "foo: bar\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; const std::string conf_yaml_2 = - "foo2: bar2\n" - "base_value_2:\n" - " id: 2\n"; + "foo2: bar2\n" + "base_value_2:\n" + " id: 2\n"; std::ofstream outfile("main.yaml"); outfile << main_conf_yaml; @@ -471,7 +464,7 @@ TEST(Configuration, configuration_config_files_cmdline) // Pass "config_files=..." cmdline option std::vector cmdline_config_options; - cmdline_config_options.push_back((yaml_helper::configs_key+"=conf_2.yaml")); + cmdline_config_options.push_back((yaml_helper::configs_key + "=conf_2.yaml")); falco_configuration falco_config; config_loaded_res res; @@ -493,4 +486,4 @@ TEST(Configuration, configuration_config_files_cmdline) std::filesystem::remove("main.yaml"); std::filesystem::remove("conf_2.yaml"); -} \ No newline at end of file +} diff --git a/unit_tests/falco/test_configuration_env_vars.cpp b/unit_tests/falco/test_configuration_env_vars.cpp index 8323f48373a..f923cf8bb1e 100644 --- a/unit_tests/falco/test_configuration_env_vars.cpp +++ b/unit_tests/falco/test_configuration_env_vars.cpp @@ -24,8 +24,7 @@ limitations under the License. #define SET_ENV_VAR(env_var_name, env_var_value) setenv(env_var_name, env_var_value, 1) #endif -TEST(Configuration, configuration_environment_variables) -{ +TEST(Configuration, configuration_environment_variables) { // Set an environment variable for testing purposes std::string env_var_value = "envVarValue"; std::string env_var_name = "ENV_VAR"; @@ -49,38 +48,38 @@ TEST(Configuration, configuration_environment_variables) std::string default_value = "default"; std::string env_var_sample_yaml = - "base_value:\n" - " id: $ENV_VAR\n" - " name: '${ENV_VAR}'\n" - " string: my_string\n" - " invalid: $${ENV_VAR}\n" - " invalid_env: $$ENV_VAR\n" - " invalid_double_env: $${ENV_VAR}$${ENV_VAR}\n" - " invalid_embedded_env: $${${ENV_VAR}}\n" - " invalid_valid_env: $${ENV_VAR}${ENV_VAR}\n" - " escaped: \"${ENV_VAR}\"\n" - " subvalue:\n" - " subvalue2:\n" - " boolean: ${UNSED_XX_X_X_VAR}\n" - "base_value_2:\n" - " sample_list:\n" - " - ${ENV_VAR}\n" - " - ' ${ENV_VAR}'\n" - " - '${ENV_VAR} '\n" - " - $UNSED_XX_X_X_VAR\n" - "paths:\n" - " - ${ENV_VAR}/foo\n" - " - $ENV_VAR/foo\n" - " - /foo/${ENV_VAR}/\n" - " - /${ENV_VAR}/${ENV_VAR}${ENV_VAR}/foo\n" - " - ${ENV_VAR_EMBEDDED}/foo\n" - "is_test: ${ENV_VAR_BOOL}\n" - "num_test: ${ENV_VAR_INT}\n" - "empty_test: ${ENV_VAR_EMPTY}\n" - "plugins:\n" - " - name: k8saudit\n" - " library_path: /foo/${ENV_VAR}/libk8saudit.so\n" - " open_params: ${ENV_VAR_INT}\n"; + "base_value:\n" + " id: $ENV_VAR\n" + " name: '${ENV_VAR}'\n" + " string: my_string\n" + " invalid: $${ENV_VAR}\n" + " invalid_env: $$ENV_VAR\n" + " invalid_double_env: $${ENV_VAR}$${ENV_VAR}\n" + " invalid_embedded_env: $${${ENV_VAR}}\n" + " invalid_valid_env: $${ENV_VAR}${ENV_VAR}\n" + " escaped: \"${ENV_VAR}\"\n" + " subvalue:\n" + " subvalue2:\n" + " boolean: ${UNSED_XX_X_X_VAR}\n" + "base_value_2:\n" + " sample_list:\n" + " - ${ENV_VAR}\n" + " - ' ${ENV_VAR}'\n" + " - '${ENV_VAR} '\n" + " - $UNSED_XX_X_X_VAR\n" + "paths:\n" + " - ${ENV_VAR}/foo\n" + " - $ENV_VAR/foo\n" + " - /foo/${ENV_VAR}/\n" + " - /${ENV_VAR}/${ENV_VAR}${ENV_VAR}/foo\n" + " - ${ENV_VAR_EMBEDDED}/foo\n" + "is_test: ${ENV_VAR_BOOL}\n" + "num_test: ${ENV_VAR_INT}\n" + "empty_test: ${ENV_VAR_EMPTY}\n" + "plugins:\n" + " - name: k8saudit\n" + " library_path: /foo/${ENV_VAR}/libk8saudit.so\n" + " open_params: ${ENV_VAR_INT}\n"; yaml_helper conf; conf.load_from_string(env_var_sample_yaml); @@ -95,84 +94,112 @@ TEST(Configuration, configuration_environment_variables) auto base_value_string = conf.get_scalar("base_value.string", default_value); ASSERT_EQ(base_value_string, "my_string"); - /* Test fetching of escaped environment variable format. Should return the string as-is after stripping the leading `$` */ + /* Test fetching of escaped environment variable format. Should return the string as-is after + * stripping the leading `$` */ auto base_value_invalid = conf.get_scalar("base_value.invalid", default_value); ASSERT_EQ(base_value_invalid, "${ENV_VAR}"); - /* Test fetching of invalid escaped environment variable format. Should return the string as-is */ - auto base_value_invalid_env = conf.get_scalar("base_value.invalid_env", default_value); + /* Test fetching of invalid escaped environment variable format. Should return the string as-is + */ + auto base_value_invalid_env = + conf.get_scalar("base_value.invalid_env", default_value); ASSERT_EQ(base_value_invalid_env, "$$ENV_VAR"); - /* Test fetching of 2 escaped environment variables side by side. Should return the string as-is after stripping the leading `$` */ - auto base_value_double_invalid = conf.get_scalar("base_value.invalid_double_env", default_value); + /* Test fetching of 2 escaped environment variables side by side. Should return the string as-is + * after stripping the leading `$` */ + auto base_value_double_invalid = + conf.get_scalar("base_value.invalid_double_env", default_value); ASSERT_EQ(base_value_double_invalid, "${ENV_VAR}${ENV_VAR}"); /* - * Test fetching of escaped environment variable format with inside an env variable. - * Should return the string as-is after stripping the leading `$` with the resolved env variable within + * Test fetching of escaped environment variable format with inside an env variable. + * Should return the string as-is after stripping the leading `$` with the resolved env variable + * within */ - auto base_value_embedded_invalid = conf.get_scalar("base_value.invalid_embedded_env", default_value); + auto base_value_embedded_invalid = + conf.get_scalar("base_value.invalid_embedded_env", default_value); ASSERT_EQ(base_value_embedded_invalid, "${" + env_var_value + "}"); /* - * Test fetching of an escaped env variable plus an env variable side by side. - * Should return the escaped one trimming the leading `$` plus the second one resolved. + * Test fetching of an escaped env variable plus an env variable side by side. + * Should return the escaped one trimming the leading `$` plus the second one resolved. */ - auto base_value_valid_invalid = conf.get_scalar("base_value.invalid_valid_env", default_value); + auto base_value_valid_invalid = + conf.get_scalar("base_value.invalid_valid_env", default_value); ASSERT_EQ(base_value_valid_invalid, "${ENV_VAR}" + env_var_value); /* Test fetching of strings that contain environment variables */ auto base_value_id = conf.get_scalar("base_value.id", default_value); - ASSERT_EQ(base_value_id, "$ENV_VAR"); // Does not follow the `${VAR}` format, so it should be treated as a regular string + ASSERT_EQ(base_value_id, "$ENV_VAR"); // Does not follow the `${VAR}` format, so it should be + // treated as a regular string auto base_value_name = conf.get_scalar("base_value.name", default_value); - ASSERT_EQ(base_value_name, env_var_value); // Proper environment variable format + ASSERT_EQ(base_value_name, env_var_value); // Proper environment variable format auto base_value_escaped = conf.get_scalar("base_value.escaped", default_value); - ASSERT_EQ(base_value_escaped, env_var_value); // Environment variable within quotes + ASSERT_EQ(base_value_escaped, env_var_value); // Environment variable within quotes /* Test fetching of an undefined environment variable. Resolves to empty string. */ - auto unknown_boolean = conf.get_scalar("base_value.subvalue.subvalue2.boolean", default_value); + auto unknown_boolean = + conf.get_scalar("base_value.subvalue.subvalue2.boolean", default_value); ASSERT_EQ(unknown_boolean, ""); /* Test fetching of environment variables from a list */ - auto base_value_2_list_0 = conf.get_scalar("base_value_2.sample_list[0]", default_value); - ASSERT_EQ(base_value_2_list_0, env_var_value); // Proper environment variable format - - auto base_value_2_list_1 = conf.get_scalar("base_value_2.sample_list[1]", default_value); - ASSERT_EQ(base_value_2_list_1, " " + env_var_value); // Environment variable preceded by a space, still extracted env var with leading space - - auto base_value_2_list_2 = conf.get_scalar("base_value_2.sample_list[2]", default_value); - ASSERT_EQ(base_value_2_list_2, env_var_value + " "); // Environment variable followed by a space, still extracted env var with trailing space - - auto base_value_2_list_3 = conf.get_scalar("base_value_2.sample_list[3]", default_value); - ASSERT_EQ(base_value_2_list_3, "$UNSED_XX_X_X_VAR"); // Does not follow the `${VAR}` format, so should be treated as a regular string + auto base_value_2_list_0 = + conf.get_scalar("base_value_2.sample_list[0]", default_value); + ASSERT_EQ(base_value_2_list_0, env_var_value); // Proper environment variable format + + auto base_value_2_list_1 = + conf.get_scalar("base_value_2.sample_list[1]", default_value); + ASSERT_EQ(base_value_2_list_1, + " " + env_var_value); // Environment variable preceded by a space, still extracted + // env var with leading space + + auto base_value_2_list_2 = + conf.get_scalar("base_value_2.sample_list[2]", default_value); + ASSERT_EQ(base_value_2_list_2, + env_var_value + " "); // Environment variable followed by a space, still extracted + // env var with trailing space + + auto base_value_2_list_3 = + conf.get_scalar("base_value_2.sample_list[3]", default_value); + ASSERT_EQ(base_value_2_list_3, "$UNSED_XX_X_X_VAR"); // Does not follow the `${VAR}` format, so + // should be treated as a regular string /* Test expansion of environment variables within strings */ auto path_list_0 = conf.get_scalar("paths[0]", default_value); - ASSERT_EQ(path_list_0, env_var_value + "/foo"); // Even if env var is part of bigger string, it gets expanded + ASSERT_EQ( + path_list_0, + env_var_value + "/foo"); // Even if env var is part of bigger string, it gets expanded auto path_list_1 = conf.get_scalar("paths[1]", default_value); - ASSERT_EQ(path_list_1, "$ENV_VAR/foo"); // Does not follow the `${VAR}` format, so should be treated as a regular string + ASSERT_EQ(path_list_1, "$ENV_VAR/foo"); // Does not follow the `${VAR}` format, so should be + // treated as a regular string auto path_list_2 = conf.get_scalar("paths[2]", default_value); - ASSERT_EQ(path_list_2, "/foo/" + env_var_value + "/"); // Even when env var is in the middle of a string. it gets expanded + ASSERT_EQ(path_list_2, + "/foo/" + env_var_value + + "/"); // Even when env var is in the middle of a string. it gets expanded auto path_list_3 = conf.get_scalar("paths[3]", default_value); - ASSERT_EQ(path_list_3, "/" + env_var_value + "/" + env_var_value + env_var_value + "/foo"); // Even when the string contains multiple env vars they are correctly expanded + ASSERT_EQ(path_list_3, + "/" + env_var_value + "/" + env_var_value + env_var_value + + "/foo"); // Even when the string contains multiple env vars they are + // correctly expanded auto path_list_4 = conf.get_scalar("paths[4]", default_value); - ASSERT_EQ(path_list_4, env_var_value + "/foo"); // Even when the env var contains another env var, it gets correctly double-expanded + ASSERT_EQ(path_list_4, env_var_value + "/foo"); // Even when the env var contains another env + // var, it gets correctly double-expanded /* Check that variable expansion is type-aware */ auto boolean = conf.get_scalar("is_test", false); - ASSERT_EQ(boolean, true); // `true` can be parsed to bool. + ASSERT_EQ(boolean, true); // `true` can be parsed to bool. auto boolean_as_str = conf.get_scalar("is_test", "false"); - ASSERT_EQ(boolean_as_str, "true"); // `true` can be parsed to string. + ASSERT_EQ(boolean_as_str, "true"); // `true` can be parsed to string. auto boolean_as_int = conf.get_scalar("is_test", 0); - ASSERT_EQ(boolean_as_int, 0); // `true` cannot be parsed to integer. + ASSERT_EQ(boolean_as_int, 0); // `true` cannot be parsed to integer. auto integer = conf.get_scalar("num_test", -1); ASSERT_EQ(integer, 12); @@ -182,9 +209,11 @@ TEST(Configuration, configuration_environment_variables) ASSERT_EQ(empty_default_str, ""); std::list plugins; - conf.get_sequence>(plugins, std::string("plugins")); - std::vector m_plugins{ std::make_move_iterator(std::begin(plugins)), - std::make_move_iterator(std::end(plugins)) }; + conf.get_sequence>(plugins, + std::string("plugins")); + std::vector m_plugins{ + std::make_move_iterator(std::begin(plugins)), + std::make_move_iterator(std::end(plugins))}; ASSERT_EQ(m_plugins[0].m_name, "k8saudit"); ASSERT_EQ(m_plugins[0].m_library_path, "/foo/" + env_var_value + "/libk8saudit.so"); ASSERT_EQ(m_plugins[0].m_open_params, "12"); diff --git a/unit_tests/falco/test_configuration_output_options.cpp b/unit_tests/falco/test_configuration_output_options.cpp index d579bc7c43e..a73872a184a 100644 --- a/unit_tests/falco/test_configuration_output_options.cpp +++ b/unit_tests/falco/test_configuration_output_options.cpp @@ -18,8 +18,7 @@ limitations under the License. #include #include -TEST(ConfigurationRuleOutputOptions, parse_yaml) -{ +TEST(ConfigurationRuleOutputOptions, parse_yaml) { falco_configuration falco_config; ASSERT_NO_THROW(falco_config.init_from_content(R"( append_output: @@ -44,7 +43,8 @@ TEST(ConfigurationRuleOutputOptions, parse_yaml) - ka.verb - static_field: "static content" - )", {})); + )", + {})); EXPECT_EQ(falco_config.m_append_output.size(), 3); @@ -53,17 +53,22 @@ TEST(ConfigurationRuleOutputOptions, parse_yaml) EXPECT_EQ(falco_config.m_append_output[0].m_tags.count("persistence"), 1); EXPECT_EQ(falco_config.m_append_output[0].m_rule, "some rule name"); EXPECT_EQ(falco_config.m_append_output[0].m_formatted_fields.size(), 0); - EXPECT_EQ(falco_config.m_append_output[0].m_format, "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); + EXPECT_EQ(falco_config.m_append_output[0].m_format, + "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); EXPECT_EQ(falco_config.m_append_output[1].m_tags.size(), 2); EXPECT_EQ(falco_config.m_append_output[1].m_tags.count("persistence"), 1); EXPECT_EQ(falco_config.m_append_output[1].m_tags.count("execution"), 1); - EXPECT_EQ(falco_config.m_append_output[1].m_format, "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); + EXPECT_EQ(falco_config.m_append_output[1].m_format, + "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields.size(), 3); - EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[2]"], "%proc.aname[2]"); - EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[3]"], "%proc.aname[3]"); - EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[4]"], "%proc.aname[4]"); + EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[2]"], + "%proc.aname[2]"); + EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[3]"], + "%proc.aname[3]"); + EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[4]"], + "%proc.aname[4]"); EXPECT_EQ(falco_config.m_append_output[2].m_source, "k8s_audit"); @@ -74,15 +79,15 @@ TEST(ConfigurationRuleOutputOptions, parse_yaml) EXPECT_EQ(falco_config.m_append_output[2].m_raw_fields.count("ka.verb"), 1); } -TEST(ConfigurationRuleOutputOptions, cli_options) -{ +TEST(ConfigurationRuleOutputOptions, cli_options) { falco_configuration falco_config; - ASSERT_NO_THROW(falco_config.init_from_content("", - std::vector{ - R"(append_output[]={"match": {"source": "syscall", "tags": ["persistence"], "rule": "some rule name"}, "extra_output": "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"})", - R"(append_output[]={"match": {"tags": ["persistence", "execution"]}, "extra_fields": [{"proc.aname[2]": "%proc.aname[2]"}, {"proc.aname[3]": "%proc.aname[3]"}, {"proc.aname[4]": "%proc.aname[4]"}], "extra_output": "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"})", - R"(append_output[]={"match": {"source": "k8s_audit"}, "extra_fields": ["ka.verb", {"static_field": "static content"}]})"})); + ASSERT_NO_THROW(falco_config.init_from_content( + "", + std::vector{ + R"(append_output[]={"match": {"source": "syscall", "tags": ["persistence"], "rule": "some rule name"}, "extra_output": "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"})", + R"(append_output[]={"match": {"tags": ["persistence", "execution"]}, "extra_fields": [{"proc.aname[2]": "%proc.aname[2]"}, {"proc.aname[3]": "%proc.aname[3]"}, {"proc.aname[4]": "%proc.aname[4]"}], "extra_output": "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"})", + R"(append_output[]={"match": {"source": "k8s_audit"}, "extra_fields": ["ka.verb", {"static_field": "static content"}]})"})); EXPECT_EQ(falco_config.m_append_output.size(), 3); @@ -91,17 +96,22 @@ TEST(ConfigurationRuleOutputOptions, cli_options) EXPECT_EQ(falco_config.m_append_output[0].m_tags.count("persistence"), 1); EXPECT_EQ(falco_config.m_append_output[0].m_rule, "some rule name"); EXPECT_EQ(falco_config.m_append_output[0].m_formatted_fields.size(), 0); - EXPECT_EQ(falco_config.m_append_output[0].m_format, "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); + EXPECT_EQ(falco_config.m_append_output[0].m_format, + "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); EXPECT_EQ(falco_config.m_append_output[1].m_tags.size(), 2); EXPECT_EQ(falco_config.m_append_output[1].m_tags.count("persistence"), 1); EXPECT_EQ(falco_config.m_append_output[1].m_tags.count("execution"), 1); - EXPECT_EQ(falco_config.m_append_output[1].m_format, "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); + EXPECT_EQ(falco_config.m_append_output[1].m_format, + "gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]"); EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields.size(), 3); - EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[2]"], "%proc.aname[2]"); - EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[3]"], "%proc.aname[3]"); - EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[4]"], "%proc.aname[4]"); + EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[2]"], + "%proc.aname[2]"); + EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[3]"], + "%proc.aname[3]"); + EXPECT_EQ(falco_config.m_append_output[1].m_formatted_fields["proc.aname[4]"], + "%proc.aname[4]"); EXPECT_EQ(falco_config.m_append_output[2].m_source, "k8s_audit"); diff --git a/unit_tests/falco/test_configuration_rule_selection.cpp b/unit_tests/falco/test_configuration_rule_selection.cpp index 01f944439ef..f4db34c928d 100644 --- a/unit_tests/falco/test_configuration_rule_selection.cpp +++ b/unit_tests/falco/test_configuration_rule_selection.cpp @@ -18,8 +18,7 @@ limitations under the License. #include #include -TEST(ConfigurationRuleSelection, parse_yaml) -{ +TEST(ConfigurationRuleSelection, parse_yaml) { falco_configuration falco_config; ASSERT_NO_THROW(falco_config.init_from_content(R"( rules: @@ -31,44 +30,57 @@ TEST(ConfigurationRuleSelection, parse_yaml) - enable: rule: 'hello*' - )", {})); + )", + {})); EXPECT_EQ(falco_config.m_rules_selection.size(), 3); - EXPECT_EQ(falco_config.m_rules_selection[0].m_op, falco_configuration::rule_selection_operation::enable); + EXPECT_EQ(falco_config.m_rules_selection[0].m_op, + falco_configuration::rule_selection_operation::enable); EXPECT_EQ(falco_config.m_rules_selection[0].m_rule, "Terminal Shell in Container"); - EXPECT_EQ(falco_config.m_rules_selection[1].m_op, falco_configuration::rule_selection_operation::disable); + EXPECT_EQ(falco_config.m_rules_selection[1].m_op, + falco_configuration::rule_selection_operation::disable); EXPECT_EQ(falco_config.m_rules_selection[1].m_tag, "experimental"); - EXPECT_EQ(falco_config.m_rules_selection[2].m_op, falco_configuration::rule_selection_operation::enable); + EXPECT_EQ(falco_config.m_rules_selection[2].m_op, + falco_configuration::rule_selection_operation::enable); EXPECT_EQ(falco_config.m_rules_selection[2].m_rule, "hello*"); } -TEST(ConfigurationRuleSelection, cli_options) -{ +TEST(ConfigurationRuleSelection, cli_options) { falco_configuration falco_config; - ASSERT_NO_THROW(falco_config.init_from_content("", std::vector{"rules[].disable.tag=maturity_incubating", "rules[].enable.rule=Adding ssh keys to authorized_keys"})); + ASSERT_NO_THROW(falco_config.init_from_content( + "", + std::vector{"rules[].disable.tag=maturity_incubating", + "rules[].enable.rule=Adding ssh keys to authorized_keys"})); EXPECT_EQ(falco_config.m_rules_selection.size(), 2); - EXPECT_EQ(falco_config.m_rules_selection[0].m_op, falco_configuration::rule_selection_operation::disable); + EXPECT_EQ(falco_config.m_rules_selection[0].m_op, + falco_configuration::rule_selection_operation::disable); EXPECT_EQ(falco_config.m_rules_selection[0].m_tag, "maturity_incubating"); - EXPECT_EQ(falco_config.m_rules_selection[1].m_op, falco_configuration::rule_selection_operation::enable); + EXPECT_EQ(falco_config.m_rules_selection[1].m_op, + falco_configuration::rule_selection_operation::enable); EXPECT_EQ(falco_config.m_rules_selection[1].m_rule, "Adding ssh keys to authorized_keys"); } -TEST(ConfigurationRuleSelection, cli_options_object) -{ +TEST(ConfigurationRuleSelection, cli_options_object) { falco_configuration falco_config; - ASSERT_NO_THROW(falco_config.init_from_content("", std::vector{R"(rules[]={"disable": {"tag": "maturity_incubating"}})", R"(rules[]={"enable": {"rule": "Adding ssh keys to authorized_keys"}})"})); + ASSERT_NO_THROW(falco_config.init_from_content( + "", + std::vector{ + R"(rules[]={"disable": {"tag": "maturity_incubating"}})", + R"(rules[]={"enable": {"rule": "Adding ssh keys to authorized_keys"}})"})); EXPECT_EQ(falco_config.m_rules_selection.size(), 2); - EXPECT_EQ(falco_config.m_rules_selection[0].m_op, falco_configuration::rule_selection_operation::disable); + EXPECT_EQ(falco_config.m_rules_selection[0].m_op, + falco_configuration::rule_selection_operation::disable); EXPECT_EQ(falco_config.m_rules_selection[0].m_tag, "maturity_incubating"); - EXPECT_EQ(falco_config.m_rules_selection[1].m_op, falco_configuration::rule_selection_operation::enable); + EXPECT_EQ(falco_config.m_rules_selection[1].m_op, + falco_configuration::rule_selection_operation::enable); EXPECT_EQ(falco_config.m_rules_selection[1].m_rule, "Adding ssh keys to authorized_keys"); } diff --git a/unit_tests/falco/test_configuration_schema.cpp b/unit_tests/falco/test_configuration_schema.cpp index ebb133613c8..2774fca2f52 100644 --- a/unit_tests/falco/test_configuration_schema.cpp +++ b/unit_tests/falco/test_configuration_schema.cpp @@ -19,86 +19,77 @@ limitations under the License. #include #include -#define EXPECT_VALIDATION_STATUS(res, status) \ - do { \ - for(const auto& pair : res) { \ - auto validation_status = pair.second; \ +#define EXPECT_VALIDATION_STATUS(res, status) \ + do { \ + for(const auto& pair : res) { \ + auto validation_status = pair.second; \ EXPECT_TRUE(sinsp_utils::startswith(validation_status, status)) << validation_status; \ - } \ - } \ - while (0) + } \ + } while(0) // Read Falco config from current repo-path -TEST(Configuration, schema_validate_config) -{ +TEST(Configuration, schema_validate_config) { falco_configuration falco_config; config_loaded_res res; - if (!std::filesystem::exists(TEST_FALCO_CONFIG)) - { + if(!std::filesystem::exists(TEST_FALCO_CONFIG)) { GTEST_SKIP() << "Falco config not present under " << TEST_FALCO_CONFIG; } EXPECT_NO_THROW(res = falco_config.init_from_file(TEST_FALCO_CONFIG, {})); EXPECT_VALIDATION_STATUS(res, yaml_helper::validation_ok); } -TEST(Configuration, schema_ok) -{ +TEST(Configuration, schema_ok) { falco_configuration falco_config; config_loaded_res res; /* OK YAML */ std::string config = - "falco_libs:\n" - " thread_table_size: 50\n"; + "falco_libs:\n" + " thread_table_size: 50\n"; EXPECT_NO_THROW(res = falco_config.init_from_content(config, {})); EXPECT_VALIDATION_STATUS(res, yaml_helper::validation_ok); } -TEST(Configuration, schema_wrong_key) -{ +TEST(Configuration, schema_wrong_key) { falco_configuration falco_config; config_loaded_res res; /* Miss-typed key YAML */ std::string config = - "falco_libss:\n" - " thread_table_size: 50\n"; + "falco_libss:\n" + " thread_table_size: 50\n"; EXPECT_NO_THROW(res = falco_config.init_from_content(config, {})); EXPECT_VALIDATION_STATUS(res, yaml_helper::validation_failed); } -TEST(Configuration, schema_wrong_type) -{ +TEST(Configuration, schema_wrong_type) { falco_configuration falco_config; /* Wrong value type YAML */ - std::string config = - "falco_libs: 512\n"; + std::string config = "falco_libs: 512\n"; // We expect an exception since `falco_configuration::load_yaml()` // will fail to parse `falco_libs` node. ASSERT_ANY_THROW(falco_config.init_from_content(config, {})); } -TEST(Configuration, schema_wrong_embedded_key) -{ +TEST(Configuration, schema_wrong_embedded_key) { falco_configuration falco_config; config_loaded_res res; /* Miss-typed sub-key YAML */ std::string config = - "falco_libs:\n" - " thread_table_sizeee: 50\n"; + "falco_libs:\n" + " thread_table_sizeee: 50\n"; EXPECT_NO_THROW(res = falco_config.init_from_content(config, {})); EXPECT_VALIDATION_STATUS(res, yaml_helper::validation_failed); } -TEST(Configuration, plugin_init_config) -{ +TEST(Configuration, plugin_init_config) { falco_configuration falco_config; config_loaded_res res; @@ -125,15 +116,14 @@ TEST(Configuration, plugin_init_config) EXPECT_VALIDATION_STATUS(res, yaml_helper::validation_ok); } -TEST(Configuration, schema_yaml_helper_validator) -{ +TEST(Configuration, schema_yaml_helper_validator) { yaml_helper conf; falco_configuration falco_config; /* Broken YAML */ std::string sample_yaml = - "falco_libs:\n" - " thread_table_size: 50\n"; + "falco_libs:\n" + " thread_table_size: 50\n"; // Ok, we don't ask for any validation EXPECT_NO_THROW(conf.load_from_string(sample_yaml)); @@ -149,4 +139,4 @@ TEST(Configuration, schema_yaml_helper_validator) // We pass everything EXPECT_NO_THROW(conf.load_from_string(sample_yaml, falco_config.m_config_schema, &validation)); EXPECT_EQ(validation[0], yaml_helper::validation_ok); -} \ No newline at end of file +} diff --git a/unit_tests/test_falco_engine.cpp b/unit_tests/test_falco_engine.cpp index 2124085eefc..38b7dcb6e84 100644 --- a/unit_tests/test_falco_engine.cpp +++ b/unit_tests/test_falco_engine.cpp @@ -1,7 +1,6 @@ #include "test_falco_engine.h" -test_falco_engine::test_falco_engine() -{ +test_falco_engine::test_falco_engine() { // create a falco engine ready to load the ruleset m_filter_factory = std::make_shared(&m_inspector, m_filterlist); m_formatter_factory = std::make_shared(&m_inspector, m_filterlist); @@ -9,8 +8,8 @@ test_falco_engine::test_falco_engine() m_engine->add_source(m_sample_source, m_filter_factory, m_formatter_factory); } -bool test_falco_engine::load_rules(const std::string& rules_content, const std::string& rules_filename) -{ +bool test_falco_engine::load_rules(const std::string& rules_content, + const std::string& rules_filename) { bool ret = false; falco::load_result::rules_contents_t rc = {{rules_filename, rules_content}}; m_load_result = m_engine->load_rules(rules_content, rules_filename); @@ -18,8 +17,7 @@ bool test_falco_engine::load_rules(const std::string& rules_content, const std:: m_load_result_json = m_load_result->as_json(rc); ret = m_load_result->successful(); - if (ret) - { + if(ret) { m_engine->enable_rule("", true, m_sample_ruleset); } @@ -27,30 +25,24 @@ bool test_falco_engine::load_rules(const std::string& rules_content, const std:: } // This must be kept in line with the (private) falco_engine::s_default_ruleset -uint64_t test_falco_engine::num_rules_for_ruleset(const std::string& ruleset) -{ +uint64_t test_falco_engine::num_rules_for_ruleset(const std::string& ruleset) { return m_engine->num_rules_for_ruleset(ruleset); } -bool test_falco_engine::has_warnings() const -{ +bool test_falco_engine::has_warnings() const { return m_load_result->has_warnings(); } -bool test_falco_engine::check_warning_message(const std::string& warning_msg) const -{ - if(!m_load_result->has_warnings()) - { +bool test_falco_engine::check_warning_message(const std::string& warning_msg) const { + if(!m_load_result->has_warnings()) { return false; } - for(const auto &warn : m_load_result_json["warnings"]) - { + for(const auto& warn : m_load_result_json["warnings"]) { std::string msg = warn["message"]; // Debug: // printf("msg: %s\n", msg.c_str()); - if(msg.find(warning_msg) != std::string::npos) - { + if(msg.find(warning_msg) != std::string::npos) { return true; } } @@ -58,21 +50,17 @@ bool test_falco_engine::check_warning_message(const std::string& warning_msg) co return false; } -bool test_falco_engine::check_error_message(const std::string& error_msg) const -{ +bool test_falco_engine::check_error_message(const std::string& error_msg) const { // if the loading is successful there are no errors - if(m_load_result->successful()) - { + if(m_load_result->successful()) { return false; } - for(const auto &err : m_load_result_json["errors"]) - { + for(const auto& err : m_load_result_json["errors"]) { std::string msg = err["message"]; // Debug: // printf("msg: %s\n", msg.c_str()); - if(msg.find(error_msg) != std::string::npos) - { + if(msg.find(error_msg) != std::string::npos) { return true; } } @@ -80,20 +68,20 @@ bool test_falco_engine::check_error_message(const std::string& error_msg) const return false; } -std::string test_falco_engine::get_compiled_rule_condition(std::string rule_name) const -{ +std::string test_falco_engine::get_compiled_rule_condition(std::string rule_name) const { auto rule_description = m_engine->describe_rule(&rule_name, {}); - return rule_description["rules"][0]["details"]["condition_compiled"].template get(); + return rule_description["rules"][0]["details"]["condition_compiled"] + .template get(); } -std::string test_falco_engine::get_compiled_rule_output(std::string rule_name) const -{ +std::string test_falco_engine::get_compiled_rule_output(std::string rule_name) const { auto rule_description = m_engine->describe_rule(&rule_name, {}); return rule_description["rules"][0]["details"]["output_compiled"].template get(); } -std::unordered_map test_falco_engine::get_compiled_rule_formatted_fields(std::string rule_name) const -{ +std::unordered_map test_falco_engine::get_compiled_rule_formatted_fields( + std::string rule_name) const { auto rule_description = m_engine->describe_rule(&rule_name, {}); - return rule_description["rules"][0]["details"]["extra_output_formatted_fields"].template get>(); + return rule_description["rules"][0]["details"]["extra_output_formatted_fields"] + .template get>(); } diff --git a/unit_tests/test_falco_engine.h b/unit_tests/test_falco_engine.h index 8fef3214c11..dd6e5d889c1 100644 --- a/unit_tests/test_falco_engine.h +++ b/unit_tests/test_falco_engine.h @@ -8,8 +8,7 @@ #include #include -class test_falco_engine : public testing::Test -{ +class test_falco_engine : public testing::Test { protected: test_falco_engine(); @@ -21,7 +20,8 @@ class test_falco_engine : public testing::Test bool check_error_message(const std::string& error_msg) const; std::string get_compiled_rule_condition(std::string rule_name = "") const; std::string get_compiled_rule_output(std::string rule_name = "") const; - std::unordered_map get_compiled_rule_formatted_fields(std::string rule_name) const; + std::unordered_map get_compiled_rule_formatted_fields( + std::string rule_name) const; std::string m_sample_ruleset = "sample-ruleset"; std::string m_sample_source = falco_common::syscall_source; diff --git a/userspace/engine/CMakeLists.txt b/userspace/engine/CMakeLists.txt index 3c6722bfb02..d0486652790 100644 --- a/userspace/engine/CMakeLists.txt +++ b/userspace/engine/CMakeLists.txt @@ -2,47 +2,40 @@ # # Copyright (C) 2023 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 +# 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. +# 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. -add_library(falco_engine STATIC - falco_common.cpp - falco_engine.cpp - falco_load_result.cpp - falco_utils.cpp - filter_ruleset.cpp - evttype_index_ruleset.cpp - formats.cpp - filter_details_resolver.cpp - filter_macro_resolver.cpp - filter_warning_resolver.cpp - logger.cpp - stats_manager.cpp - rule_loader.cpp - rule_loader_reader.cpp - rule_loader_collector.cpp - rule_loader_compiler.cpp +add_library( + falco_engine STATIC + falco_common.cpp + falco_engine.cpp + falco_load_result.cpp + falco_utils.cpp + filter_ruleset.cpp + evttype_index_ruleset.cpp + formats.cpp + filter_details_resolver.cpp + filter_macro_resolver.cpp + filter_warning_resolver.cpp + logger.cpp + stats_manager.cpp + rule_loader.cpp + rule_loader_reader.cpp + rule_loader_collector.cpp + rule_loader_compiler.cpp ) -if (EMSCRIPTEN) +if(EMSCRIPTEN) target_compile_options(falco_engine PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0") endif() -target_include_directories(falco_engine -PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${TBB_INCLUDE_DIR} -) +target_include_directories(falco_engine PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${TBB_INCLUDE_DIR}) -target_link_libraries(falco_engine -PUBLIC - sinsp - nlohmann_json::nlohmann_json - yaml-cpp -) +target_link_libraries(falco_engine PUBLIC sinsp nlohmann_json::nlohmann_json yaml-cpp) diff --git a/userspace/engine/evttype_index_ruleset.cpp b/userspace/engine/evttype_index_ruleset.cpp index c6386c6ed31..33e04943c16 100644 --- a/userspace/engine/evttype_index_ruleset.cpp +++ b/userspace/engine/evttype_index_ruleset.cpp @@ -21,57 +21,43 @@ limitations under the License. #include -evttype_index_ruleset::evttype_index_ruleset( - std::shared_ptr f): - m_filter_factory(f) -{ -} +evttype_index_ruleset::evttype_index_ruleset(std::shared_ptr f): + m_filter_factory(f) {} -evttype_index_ruleset::~evttype_index_ruleset() -{ -} +evttype_index_ruleset::~evttype_index_ruleset() {} -void evttype_index_ruleset::add( - const falco_rule& rule, - std::shared_ptr filter, - std::shared_ptr condition) -{ - try - { +void evttype_index_ruleset::add(const falco_rule &rule, + std::shared_ptr filter, + std::shared_ptr condition) { + try { auto wrap = std::make_shared(); wrap->m_rule = rule; wrap->m_filter = filter; - if(rule.source == falco_common::syscall_source) - { + if(rule.source == falco_common::syscall_source) { wrap->m_sc_codes = libsinsp::filter::ast::ppm_sc_codes(condition.get()); wrap->m_event_codes = libsinsp::filter::ast::ppm_event_codes(condition.get()); - } - else - { + } else { wrap->m_sc_codes = {}; wrap->m_event_codes = {ppm_event_code::PPME_PLUGINEVENT_E}; } wrap->m_event_codes.insert(ppm_event_code::PPME_ASYNCEVENT_E); add_wrapper(wrap); - } - catch (const sinsp_exception& e) - { + } catch(const sinsp_exception &e) { throw falco_exception(std::string(e.what())); } } -void evttype_index_ruleset::on_loading_complete() -{ +void evttype_index_ruleset::on_loading_complete() { print_enabled_rules_falco_logger(); } -bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, falco_rule &match) -{ - for(auto &wrap : wrappers) - { - if(wrap->m_filter->run(evt)) - { +bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt, + filter_wrapper_list &wrappers, + uint16_t ruleset_id, + falco_rule &match) { + for(auto &wrap : wrappers) { + if(wrap->m_filter->run(evt)) { match = wrap->m_rule; return true; } @@ -80,14 +66,14 @@ bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt, filter_wrapper_list &wr return false; } -bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, std::vector &matches) -{ +bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt, + filter_wrapper_list &wrappers, + uint16_t ruleset_id, + std::vector &matches) { bool match_found = false; - for(auto &wrap : wrappers) - { - if(wrap->m_filter->run(evt)) - { + for(auto &wrap : wrappers) { + if(wrap->m_filter->run(evt)) { matches.push_back(wrap->m_rule); match_found = true; } @@ -96,16 +82,15 @@ bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt, filter_wrapper_list &wr return match_found; } -void evttype_index_ruleset::print_enabled_rules_falco_logger() -{ +void evttype_index_ruleset::print_enabled_rules_falco_logger() { falco_logger::log(falco_logger::level::DEBUG, "Enabled rules:\n"); - auto logger = [](std::shared_ptr wrap) - { + auto logger = [](std::shared_ptr wrap) { falco_logger::log(falco_logger::level::DEBUG, std::string(" ") + wrap->name() + "\n"); }; uint64_t num_filters = iterate(logger); - falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(num_filters) + ") enabled rules in total\n"); + falco_logger::log(falco_logger::level::DEBUG, + "(" + std::to_string(num_filters) + ") enabled rules in total\n"); } diff --git a/userspace/engine/evttype_index_ruleset.h b/userspace/engine/evttype_index_ruleset.h index b721dd6427d..994599401df 100644 --- a/userspace/engine/evttype_index_ruleset.h +++ b/userspace/engine/evttype_index_ruleset.h @@ -24,12 +24,11 @@ limitations under the License. #include /*! - \brief A filter_ruleset that indexes enabled rules by event type, - and performs linear search on each event type bucket + \brief A filter_ruleset that indexes enabled rules by event type, + and performs linear search on each event type bucket */ -struct evttype_index_wrapper -{ +struct evttype_index_wrapper { const std::string &name() { return m_rule.name; } const std::set &tags() { return m_rule.tags; } const libsinsp::events::set &sc_codes() { return m_sc_codes; } @@ -41,23 +40,27 @@ struct evttype_index_wrapper std::shared_ptr m_filter; }; -class evttype_index_ruleset : public indexable_ruleset -{ +class evttype_index_ruleset : public indexable_ruleset { public: explicit evttype_index_ruleset(std::shared_ptr factory); virtual ~evttype_index_ruleset(); // From filter_ruleset - void add( - const falco_rule& rule, - std::shared_ptr filter, - std::shared_ptr condition) override; + void add(const falco_rule &rule, + std::shared_ptr filter, + std::shared_ptr condition) override; void on_loading_complete() override; // From indexable_ruleset - bool run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, falco_rule &match) override; - bool run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, std::vector &matches) override; + bool run_wrappers(sinsp_evt *evt, + filter_wrapper_list &wrappers, + uint16_t ruleset_id, + falco_rule &match) override; + bool run_wrappers(sinsp_evt *evt, + filter_wrapper_list &wrappers, + uint16_t ruleset_id, + std::vector &matches) override; // Print each enabled rule when running Falco with falco logger // log_level=debug; invoked within on_loading_complete() @@ -67,15 +70,12 @@ class evttype_index_ruleset : public indexable_ruleset std::shared_ptr m_filter_factory; }; -class evttype_index_ruleset_factory: public filter_ruleset_factory -{ +class evttype_index_ruleset_factory : public filter_ruleset_factory { public: - inline explicit evttype_index_ruleset_factory( - std::shared_ptr factory - ): m_filter_factory(factory) { } + inline explicit evttype_index_ruleset_factory(std::shared_ptr factory): + m_filter_factory(factory) {} - inline std::shared_ptr new_ruleset() override - { + inline std::shared_ptr new_ruleset() override { return std::make_shared(m_filter_factory); } diff --git a/userspace/engine/falco_common.cpp b/userspace/engine/falco_common.cpp index dac4233226b..c5a6604cd0b 100644 --- a/userspace/engine/falco_common.cpp +++ b/userspace/engine/falco_common.cpp @@ -17,83 +17,57 @@ limitations under the License. #include "falco_common.h" -static std::vector priority_names = { - "Emergency", - "Alert", - "Critical", - "Error", - "Warning", - "Notice", - "Informational", - "Debug" -}; +static std::vector priority_names = + {"Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Informational", "Debug"}; -static std::vector rule_matching_names = { - "first", - "all" -}; +static std::vector rule_matching_names = {"first", "all"}; -bool falco_common::parse_priority(const std::string& v, priority_type& out) -{ - for (size_t i = 0; i < priority_names.size(); i++) - { +bool falco_common::parse_priority(const std::string& v, priority_type& out) { + for(size_t i = 0; i < priority_names.size(); i++) { // note: for legacy reasons, "Info" and "Informational" has been used // interchangeably and ambiguously, so this is the only edge case for // which we can't apply strict equality check - if (!strcasecmp(v.c_str(), priority_names[i].c_str()) - || (i == PRIORITY_INFORMATIONAL && !strcasecmp(v.c_str(), "info"))) - { - out = (priority_type) i; + if(!strcasecmp(v.c_str(), priority_names[i].c_str()) || + (i == PRIORITY_INFORMATIONAL && !strcasecmp(v.c_str(), "info"))) { + out = (priority_type)i; return true; } } return false; } -falco_common::priority_type falco_common::parse_priority(const std::string& v) -{ +falco_common::priority_type falco_common::parse_priority(const std::string& v) { falco_common::priority_type out; - if (!parse_priority(v, out)) - { + if(!parse_priority(v, out)) { throw falco_exception("Unknown priority value: " + v); } return out; } -bool falco_common::format_priority(priority_type v, std::string& out, bool shortfmt) -{ - if ((size_t) v < priority_names.size()) - { - if (v == PRIORITY_INFORMATIONAL && shortfmt) - { +bool falco_common::format_priority(priority_type v, std::string& out, bool shortfmt) { + if((size_t)v < priority_names.size()) { + if(v == PRIORITY_INFORMATIONAL && shortfmt) { out = "Info"; - } - else - { - out = priority_names[(size_t) v]; + } else { + out = priority_names[(size_t)v]; } return true; } return false; } -std::string falco_common::format_priority(priority_type v, bool shortfmt) -{ +std::string falco_common::format_priority(priority_type v, bool shortfmt) { std::string out; - if(!format_priority(v, out, shortfmt)) - { + if(!format_priority(v, out, shortfmt)) { throw falco_exception("Unknown priority enum value: " + std::to_string(v)); } return out; } -bool falco_common::parse_rule_matching(const std::string& v, rule_matching& out) -{ - for (size_t i = 0; i < rule_matching_names.size(); i++) - { - if (!strcasecmp(v.c_str(), rule_matching_names[i].c_str())) - { - out = (rule_matching) i; +bool falco_common::parse_rule_matching(const std::string& v, rule_matching& out) { + for(size_t i = 0; i < rule_matching_names.size(); i++) { + if(!strcasecmp(v.c_str(), rule_matching_names[i].c_str())) { + out = (rule_matching)i; return true; } } diff --git a/userspace/engine/falco_common.h b/userspace/engine/falco_common.h index 95b2ef62efe..38fc55c09e9 100644 --- a/userspace/engine/falco_common.h +++ b/userspace/engine/falco_common.h @@ -36,41 +36,34 @@ limitations under the License. // be of this type. // -struct falco_exception : std::runtime_error -{ +struct falco_exception : std::runtime_error { using std::runtime_error::runtime_error; }; -namespace falco_common -{ - - const std::string syscall_source = sinsp_syscall_event_source_name; - - // Same as numbers/indices into the above vector - enum priority_type - { - PRIORITY_EMERGENCY = 0, - PRIORITY_ALERT = 1, - PRIORITY_CRITICAL = 2, - PRIORITY_ERROR = 3, - PRIORITY_WARNING = 4, - PRIORITY_NOTICE = 5, - PRIORITY_INFORMATIONAL = 6, - PRIORITY_DEBUG = 7 - }; - - bool parse_priority(const std::string& v, priority_type& out); - priority_type parse_priority(const std::string& v); - bool format_priority(priority_type v, std::string& out, bool shortfmt=false); - std::string format_priority(priority_type v, bool shortfmt=false); - - enum rule_matching - { - FIRST = 0, - ALL = 1 - }; - - bool parse_rule_matching(const std::string& v, rule_matching& out); +namespace falco_common { + +const std::string syscall_source = sinsp_syscall_event_source_name; + +// Same as numbers/indices into the above vector +enum priority_type { + PRIORITY_EMERGENCY = 0, + PRIORITY_ALERT = 1, + PRIORITY_CRITICAL = 2, + PRIORITY_ERROR = 3, + PRIORITY_WARNING = 4, + PRIORITY_NOTICE = 5, + PRIORITY_INFORMATIONAL = 6, + PRIORITY_DEBUG = 7 }; +bool parse_priority(const std::string& v, priority_type& out); +priority_type parse_priority(const std::string& v); +bool format_priority(priority_type v, std::string& out, bool shortfmt = false); +std::string format_priority(priority_type v, bool shortfmt = false); + +enum rule_matching { FIRST = 0, ALL = 1 }; + +bool parse_rule_matching(const std::string& v, rule_matching& out); +}; // namespace falco_common + typedef std::unordered_map> extra_output_field_t; diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index 10e6653b532..83d5faedcac 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -51,19 +51,18 @@ const std::string falco_engine::s_default_ruleset = "falco-default-ruleset"; using namespace falco; -falco_engine::falco_engine(bool seed_rng) - : m_syscall_source(NULL), - m_syscall_source_idx(SIZE_MAX), - m_rule_reader(std::make_shared()), - m_rule_collector(std::make_shared()), - m_rule_compiler(std::make_shared()), - m_next_ruleset_id(0), - m_min_priority(falco_common::PRIORITY_DEBUG), - m_sampling_ratio(1), m_sampling_multiplier(0) -{ - if(seed_rng) - { - srandom((unsigned) getpid()); +falco_engine::falco_engine(bool seed_rng): + m_syscall_source(NULL), + m_syscall_source_idx(SIZE_MAX), + m_rule_reader(std::make_shared()), + m_rule_collector(std::make_shared()), + m_rule_compiler(std::make_shared()), + m_next_ruleset_id(0), + m_min_priority(falco_common::PRIORITY_DEBUG), + m_sampling_ratio(1), + m_sampling_multiplier(0) { + if(seed_rng) { + srandom((unsigned)getpid()); } m_default_ruleset_id = find_ruleset_id(s_default_ruleset); @@ -73,8 +72,7 @@ falco_engine::falco_engine(bool seed_rng) m_rule_schema = nlohmann::json::parse(rule_schema_string); } -falco_engine::~falco_engine() -{ +falco_engine::~falco_engine() { m_rules.clear(); m_rule_collector->clear(); m_rule_stats_manager.clear(); @@ -82,65 +80,56 @@ falco_engine::~falco_engine() m_extra_output_format.clear(); } -sinsp_version falco_engine::engine_version() -{ +sinsp_version falco_engine::engine_version() { return sinsp_version(FALCO_ENGINE_VERSION); } -void falco_engine::set_rule_reader(std::shared_ptr reader) -{ +void falco_engine::set_rule_reader(std::shared_ptr reader) { m_rule_reader = reader; } -std::shared_ptr falco_engine::get_rule_reader() -{ +std::shared_ptr falco_engine::get_rule_reader() { return m_rule_reader; } -void falco_engine::set_rule_collector(std::shared_ptr collector) -{ +void falco_engine::set_rule_collector(std::shared_ptr collector) { m_rule_collector = collector; } -std::shared_ptr falco_engine::get_rule_collector() -{ +std::shared_ptr falco_engine::get_rule_collector() { return m_rule_collector; } -void falco_engine::set_rule_compiler(std::shared_ptr compiler) -{ +void falco_engine::set_rule_compiler(std::shared_ptr compiler) { m_rule_compiler = compiler; } -std::shared_ptr falco_engine::get_rule_compiler() -{ +std::shared_ptr falco_engine::get_rule_compiler() { return m_rule_compiler; } // Return a key that uniquely represents a field class. // For now, we assume name + shortdesc is unique. -static std::string fieldclass_key(const sinsp_filter_factory::filter_fieldclass_info &fld_info) -{ +static std::string fieldclass_key(const sinsp_filter_factory::filter_fieldclass_info &fld_info) { return fld_info.name + fld_info.shortdesc; } -void falco_engine::list_fields(const std::string &source, bool verbose, bool names_only, bool markdown) const -{ +void falco_engine::list_fields(const std::string &source, + bool verbose, + bool names_only, + bool markdown) const { // Maps from field class name + short desc to list of event // sources for which this field class can be used. - std::map> fieldclass_event_sources; + std::map> fieldclass_event_sources; // Do a first pass to group together classes that are // applicable to multiple event sources. - for(const auto &it : m_sources) - { - if(source != "" && source != it.name) - { + for(const auto &it : m_sources) { + if(source != "" && source != it.name) { continue; } - for(const auto &fld_class : it.filter_factory->get_fields()) - { + for(const auto &fld_class : it.filter_factory->get_fields()) { fieldclass_event_sources[fieldclass_key(fld_class)].insert(it.name); } } @@ -151,120 +140,104 @@ void falco_engine::list_fields(const std::string &source, bool verbose, bool nam // In the second pass, actually print info, skipping duplicate // field classes and also printing info on supported sources. - for(const auto &it : m_sources) - { - if(source != "" && source != it.name) - { + for(const auto &it : m_sources) { + if(source != "" && source != it.name) { continue; } - for(auto &fld_class : it.filter_factory->get_fields()) - { + for(auto &fld_class : it.filter_factory->get_fields()) { std::string key = fieldclass_key(fld_class); - if(seen_fieldclasses.find(key) != seen_fieldclasses.end()) - { + if(seen_fieldclasses.find(key) != seen_fieldclasses.end()) { continue; } seen_fieldclasses.insert(key); - if(names_only) - { - for(auto &field : fld_class.fields) - { - if(field.is_skippable() || field.is_deprecated()) - { + if(names_only) { + for(auto &field : fld_class.fields) { + if(field.is_skippable() || field.is_deprecated()) { continue; } printf("%s\n", field.name.c_str()); } - } - else if (markdown) - { - printf("%s\n", fld_class.as_markdown( - fieldclass_event_sources[fieldclass_key(fld_class)]).c_str()); - } - else - { - printf("%s\n", fld_class.as_string(verbose, - fieldclass_event_sources[fieldclass_key(fld_class)]).c_str()); + } else if(markdown) { + printf("%s\n", + fld_class.as_markdown(fieldclass_event_sources[fieldclass_key(fld_class)]) + .c_str()); + } else { + printf("%s\n", + fld_class + .as_string(verbose, + fieldclass_event_sources[fieldclass_key(fld_class)]) + .c_str()); } } } } -std::unique_ptr falco_engine::load_rules(const std::string &rules_content, const std::string &name) -{ +std::unique_ptr falco_engine::load_rules(const std::string &rules_content, + const std::string &name) { rule_loader::configuration cfg(rules_content, m_sources, name); cfg.extra_output_format = m_extra_output_format; cfg.extra_output_fields = m_extra_output_fields; // read rules YAML file and collect its definitions - if(m_rule_reader->read(cfg, *m_rule_collector, m_rule_schema)) - { + if(m_rule_reader->read(cfg, *m_rule_collector, m_rule_schema)) { // compile the definitions (resolve macro/list refs, exceptions, ...) m_last_compile_output = m_rule_compiler->new_compile_output(); m_rule_compiler->compile(cfg, *m_rule_collector, *m_last_compile_output); - if(!cfg.res->successful()) - { + if(!cfg.res->successful()) { return std::move(cfg.res); } // clear the rules known by the engine and each ruleset m_rules.clear(); - for (auto &src : m_sources) + for(auto &src : m_sources) // add rules to each ruleset { src.ruleset = create_ruleset(src.ruleset_factory); - src.ruleset->add_compile_output(*m_last_compile_output, - m_min_priority, - src.name); + src.ruleset->add_compile_output(*m_last_compile_output, m_min_priority, src.name); } // add rules to the engine and the rulesets - for (const auto& rule : m_last_compile_output->rules) - { + for(const auto &rule : m_last_compile_output->rules) { auto info = m_rule_collector->rules().at(rule.name); - if (!info) - { + if(!info) { // this is just defensive, it should never happen throw falco_exception("can't find internal rule info at name: " + name); } auto source = find_source(rule.source); auto rule_id = m_rules.insert(rule, rule.name); - if (rule_id != rule.id) - { + if(rule_id != rule.id) { throw falco_exception("Incompatible ID for rule: " + rule.name + - " | compiled ID: " + std::to_string(rule.id) + - " | stats_mgr ID: " + std::to_string(rule_id)); + " | compiled ID: " + std::to_string(rule.id) + + " | stats_mgr ID: " + std::to_string(rule_id)); } // By default rules are enabled/disabled for the default ruleset // skip the rule if below the minimum priority - if (rule.priority > m_min_priority) - { + if(rule.priority > m_min_priority) { continue; } - if(info->enabled) - { - source->ruleset->enable(rule.name, filter_ruleset::match_type::exact, m_default_ruleset_id); - } - else - { - source->ruleset->disable(rule.name, filter_ruleset::match_type::exact, m_default_ruleset_id); + if(info->enabled) { + source->ruleset->enable(rule.name, + filter_ruleset::match_type::exact, + m_default_ruleset_id); + } else { + source->ruleset->disable(rule.name, + filter_ruleset::match_type::exact, + m_default_ruleset_id); } } } - if (cfg.res->successful()) - { + if(cfg.res->successful()) { m_rule_stats_manager.clear(); - for (const auto &r : m_rules) - { + for(const auto &r : m_rules) { m_rule_stats_manager.on_rule_loaded(r); } } @@ -272,145 +245,135 @@ std::unique_ptr falco_engine::load_rules(const std::string &rules_c return std::move(cfg.res); } -void falco_engine::enable_rule(const std::string &substring, bool enabled, const std::string &ruleset) -{ +void falco_engine::enable_rule(const std::string &substring, + bool enabled, + const std::string &ruleset) { uint16_t ruleset_id = find_ruleset_id(ruleset); enable_rule(substring, enabled, ruleset_id); } -void falco_engine::enable_rule(const std::string &substring, bool enabled, const uint16_t ruleset_id) -{ - for(const auto &it : m_sources) - { - if(enabled) - { +void falco_engine::enable_rule(const std::string &substring, + bool enabled, + const uint16_t ruleset_id) { + for(const auto &it : m_sources) { + if(enabled) { it.ruleset->enable(substring, filter_ruleset::match_type::substring, ruleset_id); - } - else - { + } else { it.ruleset->disable(substring, filter_ruleset::match_type::substring, ruleset_id); } } } -void falco_engine::enable_rule_exact(const std::string &rule_name, bool enabled, const std::string &ruleset) -{ +void falco_engine::enable_rule_exact(const std::string &rule_name, + bool enabled, + const std::string &ruleset) { uint16_t ruleset_id = find_ruleset_id(ruleset); enable_rule_exact(rule_name, enabled, ruleset_id); } -void falco_engine::enable_rule_exact(const std::string &rule_name, bool enabled, const uint16_t ruleset_id) -{ - for(const auto &it : m_sources) - { - if(enabled) - { +void falco_engine::enable_rule_exact(const std::string &rule_name, + bool enabled, + const uint16_t ruleset_id) { + for(const auto &it : m_sources) { + if(enabled) { it.ruleset->enable(rule_name, filter_ruleset::match_type::exact, ruleset_id); - } - else - { + } else { it.ruleset->disable(rule_name, filter_ruleset::match_type::exact, ruleset_id); } } } -void falco_engine::enable_rule_wildcard(const std::string &rule_name, bool enabled, const std::string &ruleset) -{ +void falco_engine::enable_rule_wildcard(const std::string &rule_name, + bool enabled, + const std::string &ruleset) { uint16_t ruleset_id = find_ruleset_id(ruleset); enable_rule_wildcard(rule_name, enabled, ruleset_id); } -void falco_engine::enable_rule_wildcard(const std::string &rule_name, bool enabled, const uint16_t ruleset_id) -{ - for(const auto &it : m_sources) - { - if(enabled) - { +void falco_engine::enable_rule_wildcard(const std::string &rule_name, + bool enabled, + const uint16_t ruleset_id) { + for(const auto &it : m_sources) { + if(enabled) { it.ruleset->enable(rule_name, filter_ruleset::match_type::wildcard, ruleset_id); - } - else - { + } else { it.ruleset->disable(rule_name, filter_ruleset::match_type::wildcard, ruleset_id); } } } -void falco_engine::enable_rule_by_tag(const std::set &tags, bool enabled, const std::string &ruleset) -{ +void falco_engine::enable_rule_by_tag(const std::set &tags, + bool enabled, + const std::string &ruleset) { uint16_t ruleset_id = find_ruleset_id(ruleset); enable_rule_by_tag(tags, enabled, ruleset_id); } -void falco_engine::enable_rule_by_tag(const std::set &tags, bool enabled, const uint16_t ruleset_id) -{ - for(const auto &it : m_sources) - { - if(enabled) - { +void falco_engine::enable_rule_by_tag(const std::set &tags, + bool enabled, + const uint16_t ruleset_id) { + for(const auto &it : m_sources) { + if(enabled) { it.ruleset->enable_tags(tags, ruleset_id); - } - else - { + } else { it.ruleset->disable_tags(tags, ruleset_id); } } } -void falco_engine::set_min_priority(falco_common::priority_type priority) -{ +void falco_engine::set_min_priority(falco_common::priority_type priority) { m_min_priority = priority; } -uint16_t falco_engine::find_ruleset_id(const std::string &ruleset) -{ +uint16_t falco_engine::find_ruleset_id(const std::string &ruleset) { auto it = m_known_rulesets.lower_bound(ruleset); - if(it == m_known_rulesets.end() || it->first != ruleset) - { - it = m_known_rulesets.emplace_hint(it, - std::make_pair(ruleset, m_next_ruleset_id++)); + if(it == m_known_rulesets.end() || it->first != ruleset) { + it = m_known_rulesets.emplace_hint(it, std::make_pair(ruleset, m_next_ruleset_id++)); } return it->second; } -uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset) -{ +uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset) { uint16_t ruleset_id = find_ruleset_id(ruleset); uint64_t ret = 0; - for (const auto &src : m_sources) - { + for(const auto &src : m_sources) { ret += src.ruleset->enabled_count(ruleset_id); } return ret; } -void falco_engine::evttypes_for_ruleset(const std::string &source, std::set &evttypes, const std::string &ruleset) -{ +void falco_engine::evttypes_for_ruleset(const std::string &source, + std::set &evttypes, + const std::string &ruleset) { find_source(source)->ruleset->enabled_evttypes(evttypes, find_ruleset_id(ruleset)); } -libsinsp::events::set falco_engine::sc_codes_for_ruleset(const std::string &source, const std::string &ruleset) -{ +libsinsp::events::set falco_engine::sc_codes_for_ruleset(const std::string &source, + const std::string &ruleset) { return find_source(source)->ruleset->enabled_sc_codes(find_ruleset_id(ruleset)); } -libsinsp::events::set falco_engine::event_codes_for_ruleset(const std::string &source, const std::string &ruleset) -{ +libsinsp::events::set falco_engine::event_codes_for_ruleset( + const std::string &source, + const std::string &ruleset) { return find_source(source)->ruleset->enabled_event_codes(find_ruleset_id(ruleset)); } -std::shared_ptr falco_engine::create_formatter(const std::string &source, - const std::string &output) const -{ +std::shared_ptr falco_engine::create_formatter( + const std::string &source, + const std::string &output) const { return find_source(source)->formatter_factory->create_formatter(output); } -std::unique_ptr> falco_engine::process_event(std::size_t source_idx, - sinsp_evt *ev, uint16_t ruleset_id, falco_common::rule_matching strategy) -{ +std::unique_ptr> falco_engine::process_event( + std::size_t source_idx, + sinsp_evt *ev, + uint16_t ruleset_id, + falco_common::rule_matching strategy) { // note: there are no thread-safety guarantees on the filter_ruleset::run() // method, but the thread-safety assumptions of falco_engine::process_event() // imply that concurrent invokers use different and non-switchable values of @@ -419,38 +382,31 @@ std::unique_ptr> falco_engine::process_ev const falco_source *source = find_source(source_idx); - if(should_drop_evt() || !source) - { + if(should_drop_evt() || !source) { return nullptr; } - switch (strategy) - { + switch(strategy) { case falco_common::rule_matching::ALL: - if (source->m_rules.size() > 0) - { + if(source->m_rules.size() > 0) { source->m_rules.clear(); } - if (!source->ruleset->run(ev, source->m_rules, ruleset_id)) - { + if(!source->ruleset->run(ev, source->m_rules, ruleset_id)) { return nullptr; } break; case falco_common::rule_matching::FIRST: - if (source->m_rules.size() != 1) - { + if(source->m_rules.size() != 1) { source->m_rules.resize(1); } - if (!source->ruleset->run(ev, source->m_rules[0], ruleset_id)) - { + if(!source->ruleset->run(ev, source->m_rules[0], ruleset_id)) { return nullptr; } break; } auto res = std::make_unique>(); - for(const auto& rule : source->m_rules) - { + for(const auto &rule : source->m_rules) { rule_result rule_result; rule_result.evt = ev; rule_result.rule = rule.name; @@ -467,22 +423,24 @@ std::unique_ptr> falco_engine::process_ev return res; } -std::unique_ptr> falco_engine::process_event(std::size_t source_idx, - sinsp_evt *ev, falco_common::rule_matching strategy) -{ +std::unique_ptr> falco_engine::process_event( + std::size_t source_idx, + sinsp_evt *ev, + falco_common::rule_matching strategy) { return process_event(source_idx, ev, m_default_ruleset_id, strategy); } -std::size_t falco_engine::add_source(const std::string &source, - std::shared_ptr filter_factory, - std::shared_ptr formatter_factory) -{ +std::size_t falco_engine::add_source( + const std::string &source, + std::shared_ptr filter_factory, + std::shared_ptr formatter_factory) { // evttype_index_ruleset is the default ruleset implementation - size_t idx = add_source(source, filter_factory, formatter_factory, + size_t idx = add_source(source, + filter_factory, + formatter_factory, std::make_shared(filter_factory)); - if(source == falco_common::syscall_source) - { + if(source == falco_common::syscall_source) { m_syscall_source_idx = idx; } @@ -490,10 +448,9 @@ std::size_t falco_engine::add_source(const std::string &source, } std::size_t falco_engine::add_source(const std::string &source, - std::shared_ptr filter_factory, - std::shared_ptr formatter_factory, - std::shared_ptr ruleset_factory) -{ + std::shared_ptr filter_factory, + std::shared_ptr formatter_factory, + std::shared_ptr ruleset_factory) { falco_source src; src.name = source; src.filter_factory = filter_factory; @@ -503,29 +460,27 @@ std::size_t falco_engine::add_source(const std::string &source, return m_sources.insert(src, source); } -template inline nlohmann::json sequence_to_json_array(const T& seq) -{ +template +inline nlohmann::json sequence_to_json_array(const T &seq) { nlohmann::json ret = nlohmann::json::array(); - for (const auto& v : seq) - { + for(const auto &v : seq) { ret.push_back(v); } return ret; } -nlohmann::json falco_engine::describe_rule(std::string *rule_name, const std::vector>& plugins) const -{ +nlohmann::json falco_engine::describe_rule( + std::string *rule_name, + const std::vector> &plugins) const { // use previously-loaded collector definitions and the compiled // output of rules, macros, and lists. - if (m_last_compile_output == nullptr) - { + if(m_last_compile_output == nullptr) { throw falco_exception("rules must be loaded before describing them"); } // use collected and compiled info to print a json output nlohmann::json output; - if(!rule_name) - { + if(!rule_name) { // Store required engine version auto required_engine_version = m_rule_collector->required_engine_version(); output["required_engine_version"] = required_engine_version.version.as_string(); @@ -533,15 +488,13 @@ nlohmann::json falco_engine::describe_rule(std::string *rule_name, const std::ve // Store required plugin versions nlohmann::json plugin_versions = nlohmann::json::array(); auto required_plugin_versions = m_rule_collector->required_plugin_versions(); - for(const auto& req : required_plugin_versions) - { + for(const auto &req : required_plugin_versions) { nlohmann::json r; r["name"] = req.at(0).name; r["version"] = req.at(0).version; nlohmann::json alternatives = nlohmann::json::array(); - for(size_t i = 1; i < req.size(); i++) - { + for(size_t i = 1; i < req.size(); i++) { nlohmann::json alternative; alternative["name"] = req[i].name; alternative["version"] = req[i].version; @@ -555,8 +508,7 @@ nlohmann::json falco_engine::describe_rule(std::string *rule_name, const std::ve // Store information about rules nlohmann::json rules_array = nlohmann::json::array(); - for(const auto& rule : m_last_compile_output->rules) - { + for(const auto &rule : m_last_compile_output->rules) { auto info = m_rule_collector->rules().at(rule.name); nlohmann::json details; get_json_details(details, rule, *info, plugins); @@ -566,8 +518,7 @@ nlohmann::json falco_engine::describe_rule(std::string *rule_name, const std::ve // Store information about macros nlohmann::json macros_array = nlohmann::json::array(); - for(const auto ¯o : m_last_compile_output->macros) - { + for(const auto ¯o : m_last_compile_output->macros) { auto info = m_rule_collector->macros().at(macro.name); nlohmann::json details; get_json_details(details, macro, *info, plugins); @@ -577,21 +528,17 @@ nlohmann::json falco_engine::describe_rule(std::string *rule_name, const std::ve // Store information about lists nlohmann::json lists_array = nlohmann::json::array(); - for(const auto &list : m_last_compile_output->lists) - { + for(const auto &list : m_last_compile_output->lists) { auto info = m_rule_collector->lists().at(list.name); nlohmann::json details; get_json_details(details, list, *info, plugins); lists_array.push_back(std::move(details)); } output["lists"] = std::move(lists_array); - } - else - { + } else { // build json information for just the specified rule auto ri = m_rule_collector->rules().at(*rule_name); - if(ri == nullptr || ri->unknown_source) - { + if(ri == nullptr || ri->unknown_source) { throw falco_exception("Rule \"" + *rule_name + "\" is not loaded"); } auto rule = m_rules.at(ri->name); @@ -607,11 +554,10 @@ nlohmann::json falco_engine::describe_rule(std::string *rule_name, const std::ve } void falco_engine::get_json_details( - nlohmann::json &out, - const falco_rule &r, - const rule_loader::rule_info &info, - const std::vector>& plugins) const -{ + nlohmann::json &out, + const falco_rule &r, + const rule_loader::rule_info &info, + const std::vector> &plugins) const { nlohmann::json rule_info; // Fill general rule information @@ -633,13 +579,11 @@ void falco_engine::get_json_details( filter_details details; filter_details compiled_details; nlohmann::json json_details; - for(const auto &m : m_rule_collector->macros()) - { + for(const auto &m : m_rule_collector->macros()) { details.known_macros.insert(m.name); compiled_details.known_macros.insert(m.name); } - for(const auto &l : m_rule_collector->lists()) - { + for(const auto &l : m_rule_collector->lists()) { details.known_lists.insert(l.name); compiled_details.known_lists.insert(l.name); } @@ -654,12 +598,11 @@ void falco_engine::get_json_details( // Get extra requested fields std::vector out_fields; - for(auto const& f : r.extra_output_fields) - { + for(auto const &f : r.extra_output_fields) { // add all the field keys out_fields.emplace_back(f.second.first); - if (!f.second.second) // formatted field + if(!f.second.second) // formatted field { out["details"]["extra_output_formatted_fields"][f.first] = f.second.first; } @@ -676,29 +619,20 @@ void falco_engine::get_json_details( // Get names and operators from exceptions std::unordered_set exception_names; std::unordered_set exception_operators; - for(const auto &e : info.exceptions) - { + for(const auto &e : info.exceptions) { exception_names.insert(e.name); - if(e.comps.is_list) - { - for(const auto& c : e.comps.items) - { - if(c.is_list) - { + if(e.comps.is_list) { + for(const auto &c : e.comps.items) { + if(c.is_list) { // considering max two levels of lists - for(const auto& i : c.items) - { + for(const auto &i : c.items) { exception_operators.insert(i.item); } - } - else - { + } else { exception_operators.insert(c.item); } } - } - else - { + } else { exception_operators.insert(e.comps.item); } } @@ -723,16 +657,19 @@ void falco_engine::get_json_details( // note: making a union of conditions's and output's fields // note: the condition's AST accounts for all the resolved refs and exceptions compiled_details.fields.insert(out_fields.begin(), out_fields.end()); - get_json_used_plugins(used_plugins, info.source, compiled_details.evtnames, compiled_details.fields, plugins); + get_json_used_plugins(used_plugins, + info.source, + compiled_details.evtnames, + compiled_details.fields, + plugins); out["details"]["plugins"] = std::move(used_plugins); } void falco_engine::get_json_details( - nlohmann::json& out, - const falco_macro& macro, - const rule_loader::macro_info& info, - const std::vector>& plugins) const -{ + nlohmann::json &out, + const falco_macro ¯o, + const rule_loader::macro_info &info, + const std::vector> &plugins) const { nlohmann::json macro_info; macro_info["name"] = macro.name; @@ -747,13 +684,11 @@ void falco_engine::get_json_details( filter_details details; filter_details compiled_details; nlohmann::json json_details; - for(const auto &m : m_rule_collector->macros()) - { + for(const auto &m : m_rule_collector->macros()) { details.known_macros.insert(m.name); compiled_details.known_macros.insert(m.name); } - for(const auto &l : m_rule_collector->lists()) - { + for(const auto &l : m_rule_collector->lists()) { details.known_lists.insert(l.name); compiled_details.known_lists.insert(l.name); } @@ -784,24 +719,21 @@ void falco_engine::get_json_details( } void falco_engine::get_json_details( - nlohmann::json& out, - const falco_list& l, - const rule_loader::list_info& info, - const std::vector>& plugins) const -{ + nlohmann::json &out, + const falco_list &l, + const rule_loader::list_info &info, + const std::vector> &plugins) const { nlohmann::json list_info; list_info["name"] = l.name; // note: the syntactic definitions still has the list refs unresolved nlohmann::json items = nlohmann::json::array(); std::unordered_set lists; - for(const auto &i : info.items) - { + for(const auto &i : info.items) { // if an item is present in the syntactic def of a list, but not // on the compiled_items of the same list, then we can assume it // being a resolved list ref - if(std::find(l.items.begin(), l.items.end(), i) == l.items.end()) - { + if(std::find(l.items.begin(), l.items.end(), i) == l.items.end()) { lists.insert(i); continue; } @@ -813,84 +745,68 @@ void falco_engine::get_json_details( out["details"]["used"] = l.used; out["details"]["lists"] = sequence_to_json_array(lists); out["details"]["items_compiled"] = sequence_to_json_array(l.items); - out["details"]["plugins"] = nlohmann::json::array(); // always empty + out["details"]["plugins"] = nlohmann::json::array(); // always empty } -void falco_engine::get_json_evt_types( - nlohmann::json& out, - const std::string& source, - libsinsp::filter::ast::expr* ast) const -{ +void falco_engine::get_json_evt_types(nlohmann::json &out, + const std::string &source, + libsinsp::filter::ast::expr *ast) const { // note: this duplicates part of the logic of evttype_index_ruleset, // not good but it's our best option for now - if (source.empty() || source == falco_common::syscall_source) - { + if(source.empty() || source == falco_common::syscall_source) { auto evtcodes = libsinsp::filter::ast::ppm_event_codes(ast); evtcodes.insert(ppm_event_code::PPME_ASYNCEVENT_E); auto syscodes = libsinsp::filter::ast::ppm_sc_codes(ast); auto syscodes_to_evt_names = libsinsp::events::sc_set_to_event_names(syscodes); auto evtcodes_to_evt_names = libsinsp::events::event_set_to_names(evtcodes, false); - out = sequence_to_json_array(unordered_set_union(syscodes_to_evt_names, evtcodes_to_evt_names)); - } - else - { + out = sequence_to_json_array( + unordered_set_union(syscodes_to_evt_names, evtcodes_to_evt_names)); + } else { out = sequence_to_json_array(libsinsp::events::event_set_to_names( - {ppm_event_code::PPME_PLUGINEVENT_E, ppm_event_code::PPME_ASYNCEVENT_E})); + {ppm_event_code::PPME_PLUGINEVENT_E, ppm_event_code::PPME_ASYNCEVENT_E})); } } void falco_engine::get_json_used_plugins( - nlohmann::json& out, - const std::string& source, - const std::unordered_set& evtnames, - const std::unordered_set& fields, - const std::vector>& plugins) const -{ + nlohmann::json &out, + const std::string &source, + const std::unordered_set &evtnames, + const std::unordered_set &fields, + const std::vector> &plugins) const { // note: condition and output fields may have an argument, so // we need to isolate the field names std::unordered_set fieldnames; - for (const auto &f: fields) - { + for(const auto &f : fields) { auto argpos = f.find('['); - if (argpos != std::string::npos) - { + if(argpos != std::string::npos) { fieldnames.insert(f.substr(0, argpos)); - } - else - { + } else { fieldnames.insert(f); } } std::unordered_set used_plugins; - for (const auto& p : plugins) - { + for(const auto &p : plugins) { bool used = false; - if (p->caps() & CAP_SOURCING) - { + if(p->caps() & CAP_SOURCING) { // The rule's source is implemented by a plugin with event // sourcing capability. // Note: if Falco loads two plugins implementing the same source, // they will both be included in the list. - if (!used && p->event_source() == source) - { + if(!used && p->event_source() == source) { used_plugins.insert(p->name()); used = true; } } - if (!used && p->caps() & CAP_EXTRACTION) - { + if(!used && p->caps() & CAP_EXTRACTION) { // The rule uses a field implemented by a plugin with field // extraction capability that is compatible with the rule's source. // Note: here we're assuming that Falco will prevent loading // plugins implementing fields with the same name for the same // event source (implemented in init_inspectors app action). - if (sinsp_plugin::is_source_compatible(p->extract_event_sources(), source)) - { - for (const auto &f : p->fields()) - { - if (!used && fieldnames.find(f.m_name) != fieldnames.end()) - { + if(sinsp_plugin::is_source_compatible(p->extract_event_sources(), source)) { + for(const auto &f : p->fields()) { + if(!used && fieldnames.find(f.m_name) != fieldnames.end()) { used_plugins.insert(p->name()); used = true; break; @@ -898,18 +814,14 @@ void falco_engine::get_json_used_plugins( } } } - if (!used && p->caps() & CAP_ASYNC) - { + if(!used && p->caps() & CAP_ASYNC) { // The rule matches an event type implemented by a plugin with // async events capability that is compatible with the rule's source. // Note: if Falco loads two plugins implementing async events with // the same name, they will both be included in the list. - if (sinsp_plugin::is_source_compatible(p->async_event_sources(), source)) - { - for (const auto &n : p->async_event_names()) - { - if (!used && evtnames.find(n) != evtnames.end()) - { + if(sinsp_plugin::is_source_compatible(p->async_event_sources(), source)) { + for(const auto &n : p->async_event_names()) { + if(!used && evtnames.find(n) != evtnames.end()) { used_plugins.insert(p->name()); used = true; break; @@ -922,108 +834,91 @@ void falco_engine::get_json_used_plugins( out = sequence_to_json_array(used_plugins); } -void falco_engine::print_stats() const -{ +void falco_engine::print_stats() const { std::string out; m_rule_stats_manager.format(m_rules, out); // todo(jasondellaluce): introduce a logging callback in Falco fprintf(stdout, "%s", out.c_str()); } -const stats_manager& falco_engine::get_rule_stats_manager() const -{ - return m_rule_stats_manager; +const stats_manager &falco_engine::get_rule_stats_manager() const { + return m_rule_stats_manager; } -bool falco_engine::is_source_valid(const std::string &source) const -{ +bool falco_engine::is_source_valid(const std::string &source) const { return m_sources.at(source) != nullptr; } -std::shared_ptr falco_engine::filter_factory_for_source(const std::string& source) -{ +std::shared_ptr falco_engine::filter_factory_for_source( + const std::string &source) { return find_source(source)->filter_factory; } -std::shared_ptr falco_engine::filter_factory_for_source(std::size_t source_idx) -{ +std::shared_ptr falco_engine::filter_factory_for_source( + std::size_t source_idx) { return find_source(source_idx)->filter_factory; } -std::shared_ptr falco_engine::formatter_factory_for_source(const std::string& source) -{ +std::shared_ptr falco_engine::formatter_factory_for_source( + const std::string &source) { return find_source(source)->formatter_factory; } -std::shared_ptr falco_engine::formatter_factory_for_source(std::size_t source_idx) -{ +std::shared_ptr falco_engine::formatter_factory_for_source( + std::size_t source_idx) { return find_source(source_idx)->formatter_factory; } -std::shared_ptr falco_engine::ruleset_factory_for_source(const std::string& source) -{ +std::shared_ptr falco_engine::ruleset_factory_for_source( + const std::string &source) { return find_source(source)->ruleset_factory; } -std::shared_ptr falco_engine::ruleset_factory_for_source(std::size_t source_idx) -{ +std::shared_ptr falco_engine::ruleset_factory_for_source( + std::size_t source_idx) { return find_source(source_idx)->ruleset_factory; } -std::shared_ptr falco_engine::ruleset_for_source(const std::string& source_name) -{ +std::shared_ptr falco_engine::ruleset_for_source(const std::string &source_name) { const falco_source *source = find_source(source_name); return source->ruleset; } -std::shared_ptr falco_engine::ruleset_for_source(std::size_t source_idx) -{ +std::shared_ptr falco_engine::ruleset_for_source(std::size_t source_idx) { const falco_source *source = find_source(source_idx); return source->ruleset; } -void falco_engine::read_file(const std::string& filename, std::string& contents) -{ +void falco_engine::read_file(const std::string &filename, std::string &contents) { std::ifstream is; is.open(filename); - if (!is.is_open()) - { + if(!is.is_open()) { throw falco_exception("Could not open " + filename + " for reading"); } - contents.assign(std::istreambuf_iterator(is), - std::istreambuf_iterator()); + contents.assign(std::istreambuf_iterator(is), std::istreambuf_iterator()); } static bool check_plugin_requirement_alternatives( - const std::vector& plugins, - const rule_loader::plugin_version_info::requirement_alternatives& alternatives, - std::string& err) -{ - for (const auto &req : alternatives) - { - for (const auto &plugin : plugins) - { - if (req.name == plugin.name) - { + const std::vector &plugins, + const rule_loader::plugin_version_info::requirement_alternatives &alternatives, + std::string &err) { + for(const auto &req : alternatives) { + for(const auto &plugin : plugins) { + if(req.name == plugin.name) { sinsp_version req_version(req.version); sinsp_version plugin_version(plugin.version); - if(!plugin_version.is_valid()) - { - err = "Plugin '" + plugin.name - + "' has invalid version string '" - + plugin.version + "'"; + if(!plugin_version.is_valid()) { + err = "Plugin '" + plugin.name + "' has invalid version string '" + + plugin.version + "'"; return false; } - if (!plugin_version.compatible_with(req_version)) - { - err = "Plugin '" + plugin.name - + "' version '" + plugin.version - + "' is not compatible with required plugin version '" - + req.version + "'"; + if(!plugin_version.compatible_with(req_version)) { + err = "Plugin '" + plugin.name + "' version '" + plugin.version + + "' is not compatible with required plugin version '" + req.version + "'"; return false; } return true; @@ -1033,19 +928,13 @@ static bool check_plugin_requirement_alternatives( return false; } -bool falco_engine::check_plugin_requirements( - const std::vector& plugins, - std::string& err) const -{ +bool falco_engine::check_plugin_requirements(const std::vector &plugins, + std::string &err) const { err = ""; - for(const auto &alternatives : m_rule_collector->required_plugin_versions()) - { - if (!check_plugin_requirement_alternatives(plugins, alternatives, err)) - { - if (err.empty()) - { - for (const auto& req : alternatives) - { + for(const auto &alternatives : m_rule_collector->required_plugin_versions()) { + if(!check_plugin_requirement_alternatives(plugins, alternatives, err)) { + if(err.empty()) { + for(const auto &req : alternatives) { err += err.empty() ? "" : ", "; err += req.name + " (>= " + req.version + ")"; } @@ -1057,8 +946,8 @@ bool falco_engine::check_plugin_requirements( return true; } -std::shared_ptr falco_engine::create_ruleset(std::shared_ptr &ruleset_factory) -{ +std::shared_ptr falco_engine::create_ruleset( + std::shared_ptr &ruleset_factory) { auto ret = ruleset_factory->new_ruleset(); ret->set_engine_state(m_engine_state); @@ -1066,13 +955,11 @@ std::shared_ptr falco_engine::create_ruleset(std::shared_ptr &ruleset) -> bool - { +void falco_engine::fill_engine_state_funcs(filter_ruleset::engine_state_funcs &engine_state) { + engine_state.get_ruleset = [this](const std::string &source_name, + std::shared_ptr &ruleset) -> bool { const falco_source *src = m_sources.at(source_name); - if(src == nullptr) - { + if(src == nullptr) { return false; } @@ -1082,69 +969,53 @@ void falco_engine::fill_engine_state_funcs(filter_ruleset::engine_state_funcs &e }; }; -void falco_engine::complete_rule_loading() const -{ - for (const auto &src : m_sources) - { +void falco_engine::complete_rule_loading() const { + for(const auto &src : m_sources) { src.ruleset->on_loading_complete(); } } -void falco_engine::set_sampling_ratio(uint32_t sampling_ratio) -{ +void falco_engine::set_sampling_ratio(uint32_t sampling_ratio) { m_sampling_ratio = sampling_ratio; } -void falco_engine::set_sampling_multiplier(double sampling_multiplier) -{ +void falco_engine::set_sampling_multiplier(double sampling_multiplier) { m_sampling_multiplier = sampling_multiplier; } -void falco_engine::add_extra_output_format( - const std::string &format, - const std::string &source, - const std::set &tags, - const std::string &rule, - bool replace_container_info -) -{ +void falco_engine::add_extra_output_format(const std::string &format, + const std::string &source, + const std::set &tags, + const std::string &rule, + bool replace_container_info) { m_extra_output_format.push_back({format, source, tags, rule, replace_container_info}); } -void falco_engine::add_extra_output_formatted_field( - const std::string &key, - const std::string &format, - const std::string &source, - const std::set &tags, - const std::string &rule -) -{ +void falco_engine::add_extra_output_formatted_field(const std::string &key, + const std::string &format, + const std::string &source, + const std::set &tags, + const std::string &rule) { m_extra_output_fields.push_back({key, format, source, tags, rule, false}); } -void falco_engine::add_extra_output_raw_field( - const std::string &key, - const std::string &source, - const std::set &tags, - const std::string &rule -) -{ +void falco_engine::add_extra_output_raw_field(const std::string &key, + const std::string &source, + const std::set &tags, + const std::string &rule) { std::string format = "%" + key; m_extra_output_fields.push_back({key, format, source, tags, rule, true}); } -inline bool falco_engine::should_drop_evt() const -{ - if(m_sampling_multiplier == 0) - { +inline bool falco_engine::should_drop_evt() const { + if(m_sampling_multiplier == 0) { return false; } - if(m_sampling_ratio == 1) - { + if(m_sampling_ratio == 1) { return false; } - double coin = (random() * (1.0/RAND_MAX)); - return (coin >= (1.0/(m_sampling_multiplier * m_sampling_ratio))); + double coin = (random() * (1.0 / RAND_MAX)); + return (coin >= (1.0 / (m_sampling_multiplier * m_sampling_ratio))); } diff --git a/userspace/engine/falco_engine.h b/userspace/engine/falco_engine.h index d4d709821ee..a31f7cd6d8b 100644 --- a/userspace/engine/falco_engine.h +++ b/userspace/engine/falco_engine.h @@ -41,10 +41,9 @@ limitations under the License. // handled in a separate class falco_outputs. // -class falco_engine -{ +class falco_engine { public: - explicit falco_engine(bool seed_rng=true); + explicit falco_engine(bool seed_rng = true); virtual ~falco_engine(); // A given engine has a version which identifies the fields @@ -55,10 +54,9 @@ class falco_engine // Engine version used to be represented as a simple progressive // number. With the new semver schema, the number now represents - // the semver minor number. This function converts the legacy version + // the semver minor number. This function converts the legacy version // number to the new semver schema. - static inline sinsp_version get_implicit_version(uint32_t minor) - { + static inline sinsp_version get_implicit_version(uint32_t minor) { return rule_loader::reader::get_implicit_engine_version(minor); } @@ -80,7 +78,8 @@ class falco_engine // // Load rules and returns a result object. // - std::unique_ptr load_rules(const std::string &rules_content, const std::string &name); + std::unique_ptr load_rules(const std::string &rules_content, + const std::string &name); // // Enable/Disable any rules matching the provided substring. @@ -91,30 +90,42 @@ class falco_engine // for different sets of rules being active at once. // The rules are matched against the rulesets of all the defined sources. // - void enable_rule(const std::string &substring, bool enabled, const std::string &ruleset = s_default_ruleset); + void enable_rule(const std::string &substring, + bool enabled, + const std::string &ruleset = s_default_ruleset); // Same as above but providing a ruleset id instead void enable_rule(const std::string &substring, bool enabled, const uint16_t ruleset_id); // Like enable_rule, but the rule name must be an exact match. - void enable_rule_exact(const std::string &rule_name, bool enabled, const std::string &ruleset = s_default_ruleset); + void enable_rule_exact(const std::string &rule_name, + bool enabled, + const std::string &ruleset = s_default_ruleset); // Same as above but providing a ruleset id instead void enable_rule_exact(const std::string &rule_name, bool enabled, const uint16_t ruleset_id); // Like enable_rule, but wildcards are supported and substrings are not matched - void enable_rule_wildcard(const std::string &rule_name, bool enabled, const std::string &ruleset = s_default_ruleset); + void enable_rule_wildcard(const std::string &rule_name, + bool enabled, + const std::string &ruleset = s_default_ruleset); // Same as above but providing a ruleset id instead - void enable_rule_wildcard(const std::string &rule_name, bool enabled, const uint16_t ruleset_id); + void enable_rule_wildcard(const std::string &rule_name, + bool enabled, + const uint16_t ruleset_id); // // Enable/Disable any rules with any of the provided tags (set, exact matches only) // - void enable_rule_by_tag(const std::set &tags, bool enabled, const std::string &ruleset = s_default_ruleset); + void enable_rule_by_tag(const std::set &tags, + bool enabled, + const std::string &ruleset = s_default_ruleset); // Same as above but providing a ruleset id instead - void enable_rule_by_tag(const std::set &tags, bool enabled, const uint16_t ruleset_id); + void enable_rule_by_tag(const std::set &tags, + bool enabled, + const uint16_t ruleset_id); // // Must be called after the engine has been configured and all rulesets @@ -147,12 +158,13 @@ class falco_engine // Print details on the given rule. If rule is NULL, print // details on all rules. // - nlohmann::json describe_rule(std::string *rule_name, const std::vector>& plugins) const; + nlohmann::json describe_rule(std::string *rule_name, + const std::vector> &plugins) const; // // Return const /ref to rules stored in the Falco engine. // - inline const indexed_vector& get_rules() const { return m_rules; } + inline const indexed_vector &get_rules() const { return m_rules; } // // Print statistics on how many events matched each rule. @@ -160,9 +172,10 @@ class falco_engine void print_stats() const; // - // Return const /ref to stats_manager to access current rules stats (how many events matched each rule so far). + // Return const /ref to stats_manager to access current rules stats (how many events matched + // each rule so far). // - const stats_manager& get_rule_stats_manager() const; + const stats_manager &get_rule_stats_manager() const; // // Set the sampling ratio, which can affect which events are @@ -183,33 +196,27 @@ class falco_engine // add k8s/container information to outputs when // available. // - void add_extra_output_format( - const std::string &format, - const std::string &source, - const std::set &tags, - const std::string &rule, - bool replace_container_info - ); + void add_extra_output_format(const std::string &format, + const std::string &source, + const std::set &tags, + const std::string &rule, + bool replace_container_info); // You can optionally add fields that will only show up in the object // output (e.g. json, gRPC) alongside other output_fields // and not in the text message output. // You can add two types of fields: formatted which will act like // an additional output format that appears in the output field - void add_extra_output_formatted_field( - const std::string &key, - const std::string &format, - const std::string &source, - const std::set &tags, - const std::string &rule - ); - - void add_extra_output_raw_field( - const std::string &key, - const std::string &source, - const std::set &tags, - const std::string &rule - ); + void add_extra_output_formatted_field(const std::string &key, + const std::string &format, + const std::string &source, + const std::set &tags, + const std::string &rule); + + void add_extra_output_raw_field(const std::string &key, + const std::string &source, + const std::set &tags, + const std::string &rule); // Represents the result of matching an event against a set of // rules. @@ -249,7 +256,9 @@ class falco_engine // concurrently with the same source_idx would inherently cause data races // and lead to undefined behavior. std::unique_ptr> process_event(std::size_t source_idx, - sinsp_evt *ev, uint16_t ruleset_id, falco_common::rule_matching strategy); + sinsp_evt *ev, + uint16_t ruleset_id, + falco_common::rule_matching strategy); // // Wrapper assuming the default ruleset. @@ -257,7 +266,8 @@ class falco_engine // This inherits the same thread-safety guarantees. // std::unique_ptr> process_event(std::size_t source_idx, - sinsp_evt *ev, falco_common::rule_matching strategy); + sinsp_evt *ev, + falco_common::rule_matching strategy); // // Configure the engine to support events with the provided @@ -265,17 +275,17 @@ class falco_engine // Return source index for fast lookup. // std::size_t add_source(const std::string &source, - std::shared_ptr filter_factory, - std::shared_ptr formatter_factory); + std::shared_ptr filter_factory, + std::shared_ptr formatter_factory); // // Equivalent to above, but allows specifying a ruleset factory // for the newly added source. // std::size_t add_source(const std::string &source, - std::shared_ptr filter_factory, - std::shared_ptr formatter_factory, - std::shared_ptr ruleset_factory); + std::shared_ptr filter_factory, + std::shared_ptr formatter_factory, + std::shared_ptr ruleset_factory); // Return whether or not there is a valid filter/formatter // factory for this source. @@ -285,25 +295,27 @@ class falco_engine // Given a source, return a formatter factory that can create // filters for events of that source. // - std::shared_ptr filter_factory_for_source(const std::string& source); + std::shared_ptr filter_factory_for_source(const std::string &source); std::shared_ptr filter_factory_for_source(std::size_t source_idx); // // Given a source, return a formatter factory that can create // formatters for an event. // - std::shared_ptr formatter_factory_for_source(const std::string& source); - std::shared_ptr formatter_factory_for_source(std::size_t source_idx); + std::shared_ptr formatter_factory_for_source( + const std::string &source); + std::shared_ptr formatter_factory_for_source( + std::size_t source_idx); // // Given a source, return a ruleset factory that can create // rulesets for that source. // - std::shared_ptr ruleset_factory_for_source(const std::string& source); + std::shared_ptr ruleset_factory_for_source(const std::string &source); std::shared_ptr ruleset_factory_for_source(std::size_t source_idx); // Return the filter_ruleset used for a given source. - std::shared_ptr ruleset_for_source(const std::string& source); + std::shared_ptr ruleset_for_source(const std::string &source); std::shared_ptr ruleset_for_source(std::size_t source_idx); // @@ -314,24 +326,24 @@ class falco_engine // todo(jasondellaluce): remove this in future code refactors // void evttypes_for_ruleset(const std::string &source, - std::set &evttypes, - const std::string &ruleset = s_default_ruleset); + std::set &evttypes, + const std::string &ruleset = s_default_ruleset); // // Given an event source and ruleset, return the set of ppm_sc_codes // for which this ruleset can run and match events. // libsinsp::events::set sc_codes_for_ruleset( - const std::string &source, - const std::string &ruleset = s_default_ruleset); - + const std::string &source, + const std::string &ruleset = s_default_ruleset); + // // Given an event source and ruleset, return the set of ppm_event_codes // for which this ruleset can run and match events. // libsinsp::events::set event_codes_for_ruleset( - const std::string &source, - const std::string &ruleset = s_default_ruleset); + const std::string &source, + const std::string &ruleset = s_default_ruleset); // // Given a source and output string, return an @@ -339,7 +351,7 @@ class falco_engine // event. // std::shared_ptr create_formatter(const std::string &source, - const std::string &output) const; + const std::string &output) const; // The rule loader definition is aliased as it is exactly what we need typedef rule_loader::plugin_version_info::requirement plugin_version_requirement; @@ -351,49 +363,42 @@ class falco_engine // the name of the plugin and the second element is its version. // If false is returned, err is filled with error causing the check failure. // - bool check_plugin_requirements( - const std::vector& plugins, - std::string& err) const; + bool check_plugin_requirements(const std::vector &plugins, + std::string &err) const; nlohmann::json m_rule_schema; private: // Create a ruleset using the provided factory and set the // engine state funcs for it. - std::shared_ptr create_ruleset(std::shared_ptr& ruleset_factory); + std::shared_ptr create_ruleset( + std::shared_ptr &ruleset_factory); // Functions to retrieve state from this engine - void fill_engine_state_funcs(filter_ruleset::engine_state_funcs& engine_state); + void fill_engine_state_funcs(filter_ruleset::engine_state_funcs &engine_state); filter_ruleset::engine_state_funcs m_engine_state; // Throws falco_exception if the file can not be read - void read_file(const std::string& filename, std::string& contents); + void read_file(const std::string &filename, std::string &contents); indexed_vector m_sources; - inline const falco_source* find_source(std::size_t index) - { + inline const falco_source *find_source(std::size_t index) { const falco_source *source; - if(index == m_syscall_source_idx) - { - if(m_syscall_source == NULL) - { + if(index == m_syscall_source_idx) { + if(m_syscall_source == NULL) { m_syscall_source = m_sources.at(m_syscall_source_idx); - if(!m_syscall_source) - { + if(!m_syscall_source) { throw falco_exception("Unknown event source index " + std::to_string(index)); } } source = m_syscall_source; - } - else - { + } else { source = m_sources.at(index); - if(!source) - { + if(!source) { throw falco_exception("Unknown event source index " + std::to_string(index)); } } @@ -401,11 +406,9 @@ class falco_engine return source; } - inline const falco_source* find_source(const std::string& name) const - { + inline const falco_source *find_source(const std::string &name) const { auto ret = m_sources.at(name); - if(!ret) - { + if(!ret) { throw falco_exception("Unknown event source " + name); } return ret; @@ -414,7 +417,7 @@ class falco_engine // To allow the engine to be extremely fast for syscalls (can // be > 1M events/sec), we save the syscall source/source_idx // separately and check it explicitly in process_event() - const falco_source* m_syscall_source; + const falco_source *m_syscall_source; std::atomic m_syscall_source_idx; // @@ -425,31 +428,26 @@ class falco_engine inline bool should_drop_evt() const; // Retrieve json details from rules, macros, lists - void get_json_details( - nlohmann::json& out, - const falco_rule& r, - const rule_loader::rule_info& info, - const std::vector>& plugins) const; - void get_json_details( - nlohmann::json& out, - const falco_macro& m, - const rule_loader::macro_info& info, - const std::vector>& plugins) const; - void get_json_details( - nlohmann::json& out, - const falco_list& l, - const rule_loader::list_info& info, - const std::vector>& plugins) const; - void get_json_evt_types( - nlohmann::json& out, - const std::string& source, - libsinsp::filter::ast::expr* ast) const; - void get_json_used_plugins( - nlohmann::json& out, - const std::string& source, - const std::unordered_set& evttypes, - const std::unordered_set& fields, - const std::vector>& plugins) const; + void get_json_details(nlohmann::json &out, + const falco_rule &r, + const rule_loader::rule_info &info, + const std::vector> &plugins) const; + void get_json_details(nlohmann::json &out, + const falco_macro &m, + const rule_loader::macro_info &info, + const std::vector> &plugins) const; + void get_json_details(nlohmann::json &out, + const falco_list &l, + const rule_loader::list_info &info, + const std::vector> &plugins) const; + void get_json_evt_types(nlohmann::json &out, + const std::string &source, + libsinsp::filter::ast::expr *ast) const; + void get_json_used_plugins(nlohmann::json &out, + const std::string &source, + const std::unordered_set &evttypes, + const std::unordered_set &fields, + const std::vector> &plugins) const; indexed_vector m_rules; std::shared_ptr m_rule_reader; diff --git a/userspace/engine/falco_engine_version.h b/userspace/engine/falco_engine_version.h index 094a5fbdd0e..5ba61a73e68 100644 --- a/userspace/engine/falco_engine_version.h +++ b/userspace/engine/falco_engine_version.h @@ -23,14 +23,16 @@ limitations under the License. #define FALCO_ENGINE_VERSION_MINOR 43 #define FALCO_ENGINE_VERSION_PATCH 0 -#define FALCO_ENGINE_VERSION \ - __FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_MAJOR) "." \ - __FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_MINOR) "." \ - __FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_PATCH) +#define FALCO_ENGINE_VERSION \ + __FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_MAJOR) \ + "." __FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_MINOR) "." __FALCO_ENGINE_STRINGIFY( \ + FALCO_ENGINE_VERSION_PATCH) // This is the result of running the following command: // FALCO="falco -c ./falco.yaml" -// echo $($FALCO --version | grep 'Engine:' | awk '{print $2}') $(echo $($FALCO --version | grep 'Schema version:' | awk '{print $3}') $($FALCO --list --markdown | grep '^`' | sort) $($FALCO --list-events | sort) | sha256sum) +// echo $($FALCO --version | grep 'Engine:' | awk '{print $2}') $(echo $($FALCO --version | grep +// 'Schema version:' | awk '{print $3}') $($FALCO --list --markdown | grep '^`' | sort) $($FALCO +// --list-events | sort) | sha256sum) // It represents the fields supported by this version of Falco, // the event types, and the underlying driverevent schema. It's used to // detetect changes in engine version in our CI jobs. diff --git a/userspace/engine/falco_load_result.cpp b/userspace/engine/falco_load_result.cpp index 6bb0cacb172..5fc6d37bc26 100644 --- a/userspace/engine/falco_load_result.cpp +++ b/userspace/engine/falco_load_result.cpp @@ -17,113 +17,110 @@ limitations under the License. #include "falco_load_result.h" -static const std::string error_codes[] = { - "LOAD_ERR_FILE_READ", - "LOAD_ERR_YAML_PARSE", - "LOAD_ERR_YAML_VALIDATE", - "LOAD_ERR_COMPILE_CONDITION", - "LOAD_ERR_COMPILE_OUTPUT", - "LOAD_ERR_VALIDATE", - "LOAD_ERR_EXTENSION" -}; - -const std::string& falco::load_result::error_code_str(error_code ec) -{ +static const std::string error_codes[] = {"LOAD_ERR_FILE_READ", + "LOAD_ERR_YAML_PARSE", + "LOAD_ERR_YAML_VALIDATE", + "LOAD_ERR_COMPILE_CONDITION", + "LOAD_ERR_COMPILE_OUTPUT", + "LOAD_ERR_VALIDATE", + "LOAD_ERR_EXTENSION"}; + +const std::string& falco::load_result::error_code_str(error_code ec) { return error_codes[ec]; } -static const std::string error_strings[] = { - "File read error", - "YAML parse error", - "Error validating internal structure of YAML file", - "Error compiling condition", - "Error compiling output", - "Error validating rule/macro/list/exception objects", - "Error in extension item" -}; - -const std::string& falco::load_result::error_str(error_code ec) -{ +static const std::string error_strings[] = {"File read error", + "YAML parse error", + "Error validating internal structure of YAML file", + "Error compiling condition", + "Error compiling output", + "Error validating rule/macro/list/exception objects", + "Error in extension item"}; + +const std::string& falco::load_result::error_str(error_code ec) { return error_strings[ec]; } static const std::string error_descs[] = { - "This occurs when falco can not read a given file. Check permissions and whether the file exists.", - "This occurs when the rules content is not valid YAML.", - "This occurs when the internal structure of the YAML file is incorrect. Examples include not consisting of a sequence of maps, a given rule/macro/list item not having required keys, values not having the right type (e.g. the items property of a list not being a sequence), etc.", - "This occurs when a condition string can not be compiled to a filter object.", - "This occurs when an output string can not be compiled to an output object.", - "This occurs when a rule/macro/list item is incorrect. Examples include a condition field referring to an undefined macro, falco engine/plugin version mismatches, items with append without any existing item, exception fields/comps having different lengths, etc.", - "This occurs when there is an error in an extension item" -}; - -const std::string& falco::load_result::error_desc(error_code ec) -{ + "This occurs when falco can not read a given file. Check permissions and whether the file " + "exists.", + "This occurs when the rules content is not valid YAML.", + "This occurs when the internal structure of the YAML file is incorrect. Examples include " + "not consisting of a sequence of maps, a given rule/macro/list item not having required " + "keys, values not having the right type (e.g. the items property of a list not being a " + "sequence), etc.", + "This occurs when a condition string can not be compiled to a filter object.", + "This occurs when an output string can not be compiled to an output object.", + "This occurs when a rule/macro/list item is incorrect. Examples include a condition field " + "referring to an undefined macro, falco engine/plugin version mismatches, items with " + "append without any existing item, exception fields/comps having different lengths, etc.", + "This occurs when there is an error in an extension item"}; + +const std::string& falco::load_result::error_desc(error_code ec) { return error_strings[ec]; } -static const std::string warning_codes[] = { - "LOAD_UNKNOWN_SOURCE", - "LOAD_UNSAFE_NA_CHECK", - "LOAD_NO_EVTTYPE", - "LOAD_UNKNOWN_FILTER", - "LOAD_UNUSED_MACRO", - "LOAD_UNUSED_LIST", - "LOAD_UNKNOWN_ITEM", - "LOAD_DEPRECATED_ITEM", - "LOAD_WARNING_EXTENSION", - "LOAD_APPEND_NO_VALUES", - "LOAD_EXCEPTION_NAME_NOT_UNIQUE", - "LOAD_INVALID_MACRO_NAME", - "LOAD_INVALID_LIST_NAME", - "LOAD_COMPILE_CONDITION" -}; - -const std::string& falco::load_result::warning_code_str(warning_code wc) -{ +static const std::string warning_codes[] = {"LOAD_UNKNOWN_SOURCE", + "LOAD_UNSAFE_NA_CHECK", + "LOAD_NO_EVTTYPE", + "LOAD_UNKNOWN_FILTER", + "LOAD_UNUSED_MACRO", + "LOAD_UNUSED_LIST", + "LOAD_UNKNOWN_ITEM", + "LOAD_DEPRECATED_ITEM", + "LOAD_WARNING_EXTENSION", + "LOAD_APPEND_NO_VALUES", + "LOAD_EXCEPTION_NAME_NOT_UNIQUE", + "LOAD_INVALID_MACRO_NAME", + "LOAD_INVALID_LIST_NAME", + "LOAD_COMPILE_CONDITION"}; + +const std::string& falco::load_result::warning_code_str(warning_code wc) { return warning_codes[wc]; } -static const std::string warning_strings[] = { - "Unknown event source", - "Unsafe comparison in condition", - "Condition has no event-type restriction", - "Unknown field or event-type in condition or output", - "Unused macro", - "Unused list", - "Unknown rules file item", - "Used deprecated item", - "Warning in extension item", - "Overriding/appending with no values", - "Multiple exceptions defined with the same name", - "Invalid macro name", - "Invalid list name", - "Warning in rule condition" -}; - -const std::string& falco::load_result::warning_str(warning_code wc) -{ +static const std::string warning_strings[] = {"Unknown event source", + "Unsafe comparison in condition", + "Condition has no event-type restriction", + "Unknown field or event-type in condition or output", + "Unused macro", + "Unused list", + "Unknown rules file item", + "Used deprecated item", + "Warning in extension item", + "Overriding/appending with no values", + "Multiple exceptions defined with the same name", + "Invalid macro name", + "Invalid list name", + "Warning in rule condition"}; + +const std::string& falco::load_result::warning_str(warning_code wc) { return warning_strings[wc]; } static const std::string warning_descs[] = { - "A rule has a unknown event source. This can occur when reading rules content without having a corresponding plugin loaded, etc. The rule will be silently ignored.", - "Comparing a field value with is unsafe and can lead to unpredictable behavior of the rule condition. If you need to check for the existence of a field, consider using the 'exists' operator instead.", - "A rule condition matches too many evt.type values. This has a significant performance penalty. Make the condition more specific by adding an evt.type field or further restricting the number of evt.type values in the condition.", - "A rule condition or output refers to a field or evt.type that does not exist. This is normally an error, but if a rule has a skip-if-unknown-filter property, the error is downgraded to a warning.", - "A macro is defined in the rules content but is not used by any other macro or rule.", - "A list is defined in the rules content but is not used by any other list, macro, or rule.", - "An unknown top-level object is in the rules content. It will be ignored.", - "A deprecated item is employed by lists, macros, or rules.", - "An extension item has a warning", - "A rule exception is overriding/appending with no values", - "A rule is defining multiple exceptions with the same name", - "A macro is defined with an invalid name", - "A list is defined with an invalid name", - "A rule condition or output have been parsed with a warning" -}; - -const std::string& falco::load_result::warning_desc(warning_code wc) -{ + "A rule has a unknown event source. This can occur when reading rules content without " + "having a corresponding plugin loaded, etc. The rule will be silently ignored.", + "Comparing a field value with is unsafe and can lead to unpredictable behavior of the " + "rule condition. If you need to check for the existence of a field, consider using the " + "'exists' operator instead.", + "A rule condition matches too many evt.type values. This has a significant performance " + "penalty. Make the condition more specific by adding an evt.type field or further " + "restricting the number of evt.type values in the condition.", + "A rule condition or output refers to a field or evt.type that does not exist. This is " + "normally an error, but if a rule has a skip-if-unknown-filter property, the error is " + "downgraded to a warning.", + "A macro is defined in the rules content but is not used by any other macro or rule.", + "A list is defined in the rules content but is not used by any other list, macro, or rule.", + "An unknown top-level object is in the rules content. It will be ignored.", + "A deprecated item is employed by lists, macros, or rules.", + "An extension item has a warning", + "A rule exception is overriding/appending with no values", + "A rule is defining multiple exceptions with the same name", + "A macro is defined with an invalid name", + "A list is defined with an invalid name", + "A rule condition or output have been parsed with a warning"}; + +const std::string& falco::load_result::warning_desc(warning_code wc) { return warning_descs[wc]; } diff --git a/userspace/engine/falco_load_result.h b/userspace/engine/falco_load_result.h index 23f2f8fcd7b..31d5179d789 100644 --- a/userspace/engine/falco_load_result.h +++ b/userspace/engine/falco_load_result.h @@ -21,13 +21,11 @@ limitations under the License. #include #include -namespace falco -{ +namespace falco { // Represents the result of loading a rules file. class load_result { public: - enum error_code { LOAD_ERR_FILE_READ = 0, LOAD_ERR_YAML_PARSE, @@ -121,4 +119,4 @@ class load_result { virtual const nlohmann::json& as_json(const rules_contents_t& contents) = 0; }; -} // namespace falco +} // namespace falco diff --git a/userspace/engine/falco_rule.h b/userspace/engine/falco_rule.h index f002646d26b..2ed166d57d5 100644 --- a/userspace/engine/falco_rule.h +++ b/userspace/engine/falco_rule.h @@ -24,16 +24,15 @@ limitations under the License. #include /*! - \brief Represents a list in the Falco Engine. - The rule ID must be unique across all the lists loaded in the engine. + \brief Represents a list in the Falco Engine. + The rule ID must be unique across all the lists loaded in the engine. */ -struct falco_list -{ - falco_list(): used(false), id(0) { } +struct falco_list { + falco_list(): used(false), id(0) {} falco_list(falco_list&&) = default; - falco_list& operator = (falco_list&&) = default; + falco_list& operator=(falco_list&&) = default; falco_list(const falco_list&) = default; - falco_list& operator = (const falco_list&) = default; + falco_list& operator=(const falco_list&) = default; ~falco_list() = default; bool used; @@ -43,16 +42,15 @@ struct falco_list }; /*! - \brief Represents a macro in the Falco Engine. - The rule ID must be unique across all the macros loaded in the engine. + \brief Represents a macro in the Falco Engine. + The rule ID must be unique across all the macros loaded in the engine. */ -struct falco_macro -{ - falco_macro(): used(false), id(0) { } +struct falco_macro { + falco_macro(): used(false), id(0) {} falco_macro(falco_macro&&) = default; - falco_macro& operator = (falco_macro&&) = default; + falco_macro& operator=(falco_macro&&) = default; falco_macro(const falco_macro&) = default; - falco_macro& operator = (const falco_macro&) = default; + falco_macro& operator=(const falco_macro&) = default; ~falco_macro() = default; bool used; @@ -62,16 +60,15 @@ struct falco_macro }; /*! - \brief Represents a rule in the Falco Engine. - The rule ID must be unique across all the rules loaded in the engine. + \brief Represents a rule in the Falco Engine. + The rule ID must be unique across all the rules loaded in the engine. */ -struct falco_rule -{ +struct falco_rule { falco_rule(): id(0), priority(falco_common::PRIORITY_DEBUG) {} falco_rule(falco_rule&&) = default; - falco_rule& operator = (falco_rule&&) = default; + falco_rule& operator=(falco_rule&&) = default; falco_rule(const falco_rule&) = default; - falco_rule& operator = (const falco_rule&) = default; + falco_rule& operator=(const falco_rule&) = default; ~falco_rule() = default; std::size_t id; diff --git a/userspace/engine/falco_source.h b/userspace/engine/falco_source.h index b222054e24a..0a75095a950 100644 --- a/userspace/engine/falco_source.h +++ b/userspace/engine/falco_source.h @@ -21,23 +21,21 @@ limitations under the License. #include "filter_ruleset.h" /*! - \brief Represents a given data source used by the engine. - The ruleset of a source should be created through the ruleset factory - of the same data source. + \brief Represents a given data source used by the engine. + The ruleset of a source should be created through the ruleset factory + of the same data source. */ -struct falco_source -{ +struct falco_source { falco_source() = default; falco_source(falco_source&&) = default; - falco_source& operator = (falco_source&&) = default; + falco_source& operator=(falco_source&&) = default; falco_source(const falco_source& s): - name(s.name), - ruleset(s.ruleset), - ruleset_factory(s.ruleset_factory), - filter_factory(s.filter_factory), - formatter_factory(s.formatter_factory) { }; - falco_source& operator = (const falco_source& s) - { + name(s.name), + ruleset(s.ruleset), + ruleset_factory(s.ruleset_factory), + filter_factory(s.filter_factory), + formatter_factory(s.formatter_factory) {}; + falco_source& operator=(const falco_source& s) { name = s.name; ruleset = s.ruleset; ruleset_factory = s.ruleset_factory; @@ -56,24 +54,19 @@ struct falco_source // matches an event. mutable std::vector m_rules; - inline bool is_valid_lhs_field(const std::string& field) const - { + inline bool is_valid_lhs_field(const std::string& field) const { // if there's at least one parenthesis we may be parsing a field // wrapped inside one or more transformers. In those cases, the most // rigorous analysis we can do is compiling a simple filter using // the field as left-hand side of a comparison, and see if any error // occurs. - if (field.find('(') != std::string::npos) - { - try - { + if(field.find('(') != std::string::npos) { + try { auto filter = field; filter.append(" exists"); sinsp_filter_compiler(filter_factory, filter).compile(); return true; - } - catch (...) - { + } catch(...) { return false; } } diff --git a/userspace/engine/falco_utils.cpp b/userspace/engine/falco_utils.cpp index 635a4b24367..fb1a9f7aeb3 100644 --- a/userspace/engine/falco_utils.cpp +++ b/userspace/engine/falco_utils.cpp @@ -30,19 +30,22 @@ limitations under the License. #include #include -#define RGX_PROMETHEUS_TIME_DURATION "^((?P[0-9]+)y)?((?P[0-9]+)w)?((?P[0-9]+)d)?((?P[0-9]+)h)?((?P[0-9]+)m)?((?P[0-9]+)s)?((?P[0-9]+)ms)?$" +#define RGX_PROMETHEUS_TIME_DURATION \ + "^((?P[0-9]+)y)?((?P[0-9]+)w)?((?P[0-9]+)d)?((?P[0-9]+)h)?((?P[0-9]+)m)?((?P<" \ + "s>[0-9]+)s)?((?P[0-9]+)ms)?$" // using pre-compiled regex static re2::RE2 s_rgx_prometheus_time_duration(RGX_PROMETHEUS_TIME_DURATION); -// Prometheus time durations: https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations -#define PROMETHEUS_UNIT_Y "y" ///> assuming a year has always 365d -#define PROMETHEUS_UNIT_W "w" ///> assuming a week has always 7d -#define PROMETHEUS_UNIT_D "d" ///> assuming a day has always 24h -#define PROMETHEUS_UNIT_H "h" ///> hour -#define PROMETHEUS_UNIT_M "m" ///> minute -#define PROMETHEUS_UNIT_S "s" ///> second -#define PROMETHEUS_UNIT_MS "ms" ///> millisecond +// Prometheus time durations: +// https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations +#define PROMETHEUS_UNIT_Y "y" ///> assuming a year has always 365d +#define PROMETHEUS_UNIT_W "w" ///> assuming a week has always 7d +#define PROMETHEUS_UNIT_D "d" ///> assuming a day has always 24h +#define PROMETHEUS_UNIT_H "h" ///> hour +#define PROMETHEUS_UNIT_M "m" ///> minute +#define PROMETHEUS_UNIT_S "s" ///> second +#define PROMETHEUS_UNIT_MS "ms" ///> millisecond // standard time unit conversions to milliseconds #define ONE_MS_TO_MS 1UL @@ -53,20 +56,17 @@ static re2::RE2 s_rgx_prometheus_time_duration(RGX_PROMETHEUS_TIME_DURATION); #define ONE_WEEK_TO_MS ONE_DAY_TO_MS * 7UL #define ONE_YEAR_TO_MS ONE_DAY_TO_MS * 365UL -namespace falco -{ +namespace falco { -namespace utils -{ +namespace utils { -uint64_t parse_prometheus_interval(std::string interval_str) -{ +uint64_t parse_prometheus_interval(std::string interval_str) { uint64_t interval = 0; /* Sanitize user input, remove possible whitespaces. */ - interval_str.erase(remove_if(interval_str.begin(), interval_str.end(), isspace), interval_str.end()); + interval_str.erase(remove_if(interval_str.begin(), interval_str.end(), isspace), + interval_str.end()); - if(!interval_str.empty()) - { + if(!interval_str.empty()) { re2::StringPiece input(interval_str); std::string args[14]; re2::RE2::Arg arg0(&args[0]); @@ -83,34 +83,52 @@ uint64_t parse_prometheus_interval(std::string interval_str) re2::RE2::Arg arg11(&args[11]); re2::RE2::Arg arg12(&args[12]); re2::RE2::Arg arg13(&args[13]); - const re2::RE2::Arg* const matches[14] = {&arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, &arg10, &arg11, &arg12, &arg13}; - - const std::map& named_groups = s_rgx_prometheus_time_duration.NamedCapturingGroups(); + const re2::RE2::Arg* const matches[14] = {&arg0, + &arg1, + &arg2, + &arg3, + &arg4, + &arg5, + &arg6, + &arg7, + &arg8, + &arg9, + &arg10, + &arg11, + &arg12, + &arg13}; + + const std::map& named_groups = + s_rgx_prometheus_time_duration.NamedCapturingGroups(); int num_groups = s_rgx_prometheus_time_duration.NumberOfCapturingGroups(); re2::RE2::FullMatchN(input, s_rgx_prometheus_time_duration, matches, num_groups); - static const char* all_prometheus_units[7] = { - PROMETHEUS_UNIT_Y, PROMETHEUS_UNIT_W, PROMETHEUS_UNIT_D, PROMETHEUS_UNIT_H, - PROMETHEUS_UNIT_M, PROMETHEUS_UNIT_S, PROMETHEUS_UNIT_MS }; - - static const uint64_t all_prometheus_time_conversions[7] = { - ONE_YEAR_TO_MS, ONE_WEEK_TO_MS, ONE_DAY_TO_MS, ONE_HOUR_TO_MS, - ONE_MINUTE_TO_MS, ONE_SECOND_TO_MS, ONE_MS_TO_MS }; - - for(size_t i = 0; i < sizeof(all_prometheus_units) / sizeof(const char*); i++) - { + static const char* all_prometheus_units[7] = {PROMETHEUS_UNIT_Y, + PROMETHEUS_UNIT_W, + PROMETHEUS_UNIT_D, + PROMETHEUS_UNIT_H, + PROMETHEUS_UNIT_M, + PROMETHEUS_UNIT_S, + PROMETHEUS_UNIT_MS}; + + static const uint64_t all_prometheus_time_conversions[7] = {ONE_YEAR_TO_MS, + ONE_WEEK_TO_MS, + ONE_DAY_TO_MS, + ONE_HOUR_TO_MS, + ONE_MINUTE_TO_MS, + ONE_SECOND_TO_MS, + ONE_MS_TO_MS}; + + for(size_t i = 0; i < sizeof(all_prometheus_units) / sizeof(const char*); i++) { std::string cur_interval_str; uint64_t cur_interval = 0; - const auto &group_it = named_groups.find(all_prometheus_units[i]); - if(group_it != named_groups.end()) - { + const auto& group_it = named_groups.find(all_prometheus_units[i]); + if(group_it != named_groups.end()) { cur_interval_str = args[group_it->second - 1]; - if(!cur_interval_str.empty()) - { + if(!cur_interval_str.empty()) { cur_interval = std::stoull(cur_interval_str, nullptr, 0); } - if(cur_interval > 0) - { + if(cur_interval > 0) { interval += cur_interval * all_prometheus_time_conversions[i]; } } @@ -120,11 +138,9 @@ uint64_t parse_prometheus_interval(std::string interval_str) } #if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) -std::string calculate_file_sha256sum(const std::string& filename) -{ +std::string calculate_file_sha256sum(const std::string& filename) { std::ifstream file(filename, std::ios::binary); - if (!file.is_open()) - { + if(!file.is_open()) { return ""; } @@ -133,8 +149,7 @@ std::string calculate_file_sha256sum(const std::string& filename) constexpr size_t buffer_size = 4096; char buffer[buffer_size]; - while (file.read(buffer, buffer_size)) - { + while(file.read(buffer, buffer_size)) { SHA256_Update(&sha256_context, buffer, buffer_size); } SHA256_Update(&sha256_context, buffer, file.gcount()); @@ -143,40 +158,32 @@ std::string calculate_file_sha256sum(const std::string& filename) SHA256_Final(digest, &sha256_context); std::stringstream ss; - for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) - { + for(int i = 0; i < SHA256_DIGEST_LENGTH; ++i) { ss << std::hex << std::setw(2) << std::setfill('0') << static_cast(digest[i]); } return ss.str(); } #endif -std::string sanitize_rule_name(const std::string& name) -{ +std::string sanitize_rule_name(const std::string& name) { std::string sanitized_name = name; RE2::GlobalReplace(&sanitized_name, "[^a-zA-Z0-9_:]", "_"); RE2::GlobalReplace(&sanitized_name, "_+", "_"); - if (!sanitized_name.empty() && sanitized_name.back() == '_') - { + if(!sanitized_name.empty() && sanitized_name.back() == '_') { sanitized_name.pop_back(); } return sanitized_name; } -std::string wrap_text(const std::string& in, uint32_t indent, uint32_t line_len) -{ +std::string wrap_text(const std::string& in, uint32_t indent, uint32_t line_len) { std::istringstream is(in); std::ostringstream os; std::string word; uint32_t len = 0; - while (is >> word) - { - if((len + word.length() + 1) <= (line_len-indent)) - { + while(is >> word) { + if((len + word.length() + 1) <= (line_len - indent)) { len += word.length() + 1; - } - else - { + } else { os << std::endl; os << std::left << std::setw(indent) << " "; len = word.length() + 1; @@ -186,18 +193,15 @@ std::string wrap_text(const std::string& in, uint32_t indent, uint32_t line_len) return os.str(); } -uint32_t hardware_concurrency() -{ +uint32_t hardware_concurrency() { auto hc = std::thread::hardware_concurrency(); return hc ? hc : 1; } -void readfile(const std::string& filename, std::string& data) -{ +void readfile(const std::string& filename, std::string& data) { std::ifstream file(filename, std::ios::in); - if(file.is_open()) - { + if(file.is_open()) { std::stringstream ss; ss << file.rdbuf(); @@ -209,22 +213,18 @@ void readfile(const std::string& filename, std::string& data) return; } -bool matches_wildcard(const std::string &pattern, const std::string &s) -{ +bool matches_wildcard(const std::string& pattern, const std::string& s) { std::string::size_type star_pos = pattern.find("*"); - if(star_pos == std::string::npos) - { + if(star_pos == std::string::npos) { // regular match (no wildcards) return pattern == s; } - if(star_pos == 0) - { + if(star_pos == 0) { // wildcard at the beginning "*something*..." std::string::size_type next_pattern_start = pattern.find_first_not_of("*"); - if(next_pattern_start == std::string::npos) - { + if(next_pattern_start == std::string::npos) { // pattern was just a sequence of stars *, **, ***, ... . This always matches. return true; } @@ -232,18 +232,16 @@ bool matches_wildcard(const std::string &pattern, const std::string &s) std::string next_pattern = pattern.substr(next_pattern_start); std::string to_find = next_pattern.substr(0, next_pattern.find("*")); std::string::size_type lit_pos = s.find(to_find); - if(lit_pos == std::string::npos) - { + if(lit_pos == std::string::npos) { return false; } - return matches_wildcard(next_pattern.substr(to_find.size()), s.substr(lit_pos + to_find.size())); - } else - { + return matches_wildcard(next_pattern.substr(to_find.size()), + s.substr(lit_pos + to_find.size())); + } else { // wildcard at the end or in the middle "something*else*..." - - if(pattern.substr(0, star_pos) != s.substr(0, star_pos)) - { + + if(pattern.substr(0, star_pos) != s.substr(0, star_pos)) { return false; } @@ -251,12 +249,10 @@ bool matches_wildcard(const std::string &pattern, const std::string &s) } } -namespace network -{ -bool is_unix_scheme(const std::string& url) -{ +namespace network { +bool is_unix_scheme(const std::string& url) { return sinsp_utils::startswith(url, UNIX_SCHEME); } -} // namespace network -} // namespace utils -} // namespace falco +} // namespace network +} // namespace utils +} // namespace falco diff --git a/userspace/engine/falco_utils.h b/userspace/engine/falco_utils.h index 09b97be0fc5..019ae5183e0 100644 --- a/userspace/engine/falco_utils.h +++ b/userspace/engine/falco_utils.h @@ -23,8 +23,7 @@ limitations under the License. #include #include -namespace falco::utils -{ +namespace falco::utils { uint64_t parse_prometheus_interval(std::string interval_str); #if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) @@ -39,11 +38,10 @@ void readfile(const std::string& filename, std::string& data); uint32_t hardware_concurrency(); -bool matches_wildcard(const std::string &pattern, const std::string &s); +bool matches_wildcard(const std::string& pattern, const std::string& s); -namespace network -{ +namespace network { static const std::string UNIX_SCHEME("unix://"); bool is_unix_scheme(const std::string& url); -} // namespace network -} // namespace falco::utils +} // namespace network +} // namespace falco::utils diff --git a/userspace/engine/filter_details_resolver.cpp b/userspace/engine/filter_details_resolver.cpp index c018bfba829..97b4700be84 100644 --- a/userspace/engine/filter_details_resolver.cpp +++ b/userspace/engine/filter_details_resolver.cpp @@ -21,18 +21,15 @@ limitations under the License. using namespace libsinsp::filter; -static inline std::string get_field_name(const std::string& name, const std::string& arg) -{ +static inline std::string get_field_name(const std::string& name, const std::string& arg) { std::string fld = name; - if (!arg.empty()) - { + if(!arg.empty()) { fld += "[" + arg + "]"; } return fld; } -void filter_details::reset() -{ +void filter_details::reset() { fields.clear(); macros.clear(); operators.clear(); @@ -41,114 +38,92 @@ void filter_details::reset() transformers.clear(); } -void filter_details_resolver::run(ast::expr* filter, filter_details& details) -{ +void filter_details_resolver::run(ast::expr* filter, filter_details& details) { visitor v(details); filter->accept(&v); } -void filter_details_resolver::visitor::visit(ast::and_expr* e) -{ - for(size_t i = 0; i < e->children.size(); i++) - { +void filter_details_resolver::visitor::visit(ast::and_expr* e) { + for(size_t i = 0; i < e->children.size(); i++) { e->children[i]->accept(this); } } -void filter_details_resolver::visitor::visit(ast::or_expr* e) -{ - for(size_t i = 0; i < e->children.size(); i++) - { +void filter_details_resolver::visitor::visit(ast::or_expr* e) { + for(size_t i = 0; i < e->children.size(); i++) { e->children[i]->accept(this); } } -void filter_details_resolver::visitor::visit(ast::not_expr* e) -{ +void filter_details_resolver::visitor::visit(ast::not_expr* e) { e->child->accept(this); } -void filter_details_resolver::visitor::visit(ast::list_expr* e) -{ - if(m_expect_list) - { - for(const auto& item : e->values) - { - if(m_details.known_lists.find(item) != m_details.known_lists.end()) - { +void filter_details_resolver::visitor::visit(ast::list_expr* e) { + if(m_expect_list) { + for(const auto& item : e->values) { + if(m_details.known_lists.find(item) != m_details.known_lists.end()) { m_details.lists.insert(item); } } } - if (m_expect_evtname) - { - for(const auto& item : e->values) - { - if(m_details.known_lists.find(item) == m_details.known_lists.end()) - { + if(m_expect_evtname) { + for(const auto& item : e->values) { + if(m_details.known_lists.find(item) == m_details.known_lists.end()) { m_details.evtnames.insert(item); } } } } -void filter_details_resolver::visitor::visit(ast::binary_check_expr* e) -{ +void filter_details_resolver::visitor::visit(ast::binary_check_expr* e) { m_last_node_field_name.clear(); m_expect_evtname = false; m_expect_list = false; e->left->accept(this); - if (m_last_node_field_name.empty()) - { + if(m_last_node_field_name.empty()) { throw std::runtime_error("can't find field info in binary check expression"); } - + m_details.operators.insert(e->op); m_expect_list = true; - m_expect_evtname = m_last_node_field_name == "evt.type" || m_last_node_field_name == "evt.asynctype"; + m_expect_evtname = + m_last_node_field_name == "evt.type" || m_last_node_field_name == "evt.asynctype"; e->right->accept(this); m_expect_evtname = false; m_expect_list = false; } -void filter_details_resolver::visitor::visit(ast::unary_check_expr* e) -{ +void filter_details_resolver::visitor::visit(ast::unary_check_expr* e) { m_last_node_field_name.clear(); e->left->accept(this); - if (m_last_node_field_name.empty()) - { + if(m_last_node_field_name.empty()) { throw std::runtime_error("can't find field info in unary check expression"); } m_details.fields.insert(m_last_node_field_name); m_details.operators.insert(e->op); } -void filter_details_resolver::visitor::visit(ast::identifier_expr* e) -{ +void filter_details_resolver::visitor::visit(ast::identifier_expr* e) { // todo(jasondellaluce): maybe throw an error if we encounter an unknown macro? - if(m_details.known_macros.find(e->identifier) != m_details.known_macros.end()) - { + if(m_details.known_macros.find(e->identifier) != m_details.known_macros.end()) { m_details.macros.insert(e->identifier); } } -void filter_details_resolver::visitor::visit(ast::value_expr* e) -{ - if (m_expect_evtname) - { +void filter_details_resolver::visitor::visit(ast::value_expr* e) { + if(m_expect_evtname) { m_details.evtnames.insert(e->value); } } -void filter_details_resolver::visitor::visit(ast::field_expr* e) -{ +void filter_details_resolver::visitor::visit(ast::field_expr* e) { m_last_node_field_name = get_field_name(e->field, e->arg); m_details.fields.insert(m_last_node_field_name); } -void filter_details_resolver::visitor::visit(ast::field_transformer_expr* e) -{ +void filter_details_resolver::visitor::visit(ast::field_transformer_expr* e) { m_details.transformers.insert(e->transformer); e->value->accept(this); } diff --git a/userspace/engine/filter_details_resolver.h b/userspace/engine/filter_details_resolver.h index 9e77a9b876c..9ddea16376b 100644 --- a/userspace/engine/filter_details_resolver.h +++ b/userspace/engine/filter_details_resolver.h @@ -22,8 +22,7 @@ limitations under the License. #include #include -struct filter_details -{ +struct filter_details { // input macros and lists std::unordered_set known_macros; std::unordered_set known_lists; @@ -40,29 +39,26 @@ struct filter_details }; /*! - \brief Helper class for getting details about rules' filters. + \brief Helper class for getting details about rules' filters. */ -class filter_details_resolver -{ +class filter_details_resolver { public: /*! - \brief Visits a filter AST and stores details about macros, lists, - fields and operators used. - \param filter The filter AST to be processed. - \param details Helper structure used to state known macros and - lists on input, and to store all the retrieved details as output. + \brief Visits a filter AST and stores details about macros, lists, + fields and operators used. + \param filter The filter AST to be processed. + \param details Helper structure used to state known macros and + lists on input, and to store all the retrieved details as output. */ - void run(libsinsp::filter::ast::expr* filter, - filter_details& details); + void run(libsinsp::filter::ast::expr* filter, filter_details& details); private: - struct visitor : public libsinsp::filter::ast::expr_visitor - { - explicit visitor(filter_details& details) : - m_details(details), - m_expect_list(false), - m_expect_evtname(false), - m_last_node_field_name() {} + struct visitor : public libsinsp::filter::ast::expr_visitor { + explicit visitor(filter_details& details): + m_details(details), + m_expect_list(false), + m_expect_evtname(false), + m_last_node_field_name() {} visitor(visitor&&) = default; visitor(const visitor&) = delete; diff --git a/userspace/engine/filter_macro_resolver.cpp b/userspace/engine/filter_macro_resolver.cpp index 3c22775c98c..56b75efb2dd 100644 --- a/userspace/engine/filter_macro_resolver.cpp +++ b/userspace/engine/filter_macro_resolver.cpp @@ -20,8 +20,7 @@ limitations under the License. using namespace libsinsp::filter; -bool filter_macro_resolver::run(std::shared_ptr& filter) -{ +bool filter_macro_resolver::run(std::shared_ptr& filter) { m_unknown_macros.clear(); m_resolved_macros.clear(); m_errors.clear(); @@ -29,110 +28,90 @@ bool filter_macro_resolver::run(std::shared_ptr& fi visitor v(m_errors, m_unknown_macros, m_resolved_macros, m_macros); v.m_node_substitute = nullptr; filter->accept(&v); - if (v.m_node_substitute) - { + if(v.m_node_substitute) { filter = std::move(v.m_node_substitute); } return !m_resolved_macros.empty(); } -void filter_macro_resolver::set_macro( - const std::string& name, - const std::shared_ptr& macro) -{ +void filter_macro_resolver::set_macro(const std::string& name, + const std::shared_ptr& macro) { m_macros[name] = macro; } -const std::vector& filter_macro_resolver::get_unknown_macros() const -{ +const std::vector& filter_macro_resolver::get_unknown_macros() + const { return m_unknown_macros; } -const std::vector& filter_macro_resolver::get_errors() const -{ +const std::vector& filter_macro_resolver::get_errors() const { return m_errors; } -const std::vector& filter_macro_resolver::get_resolved_macros() const -{ +const std::vector& filter_macro_resolver::get_resolved_macros() + const { return m_resolved_macros; } -void filter_macro_resolver::visitor::visit(ast::and_expr* e) -{ - for (size_t i = 0; i < e->children.size(); i++) - { +void filter_macro_resolver::visitor::visit(ast::and_expr* e) { + for(size_t i = 0; i < e->children.size(); i++) { e->children[i]->accept(this); - if (m_node_substitute) - { + if(m_node_substitute) { e->children[i] = std::move(m_node_substitute); } } m_node_substitute = nullptr; } -void filter_macro_resolver::visitor::visit(ast::or_expr* e) -{ - for (size_t i = 0; i < e->children.size(); i++) - { +void filter_macro_resolver::visitor::visit(ast::or_expr* e) { + for(size_t i = 0; i < e->children.size(); i++) { e->children[i]->accept(this); - if (m_node_substitute) - { + if(m_node_substitute) { e->children[i] = std::move(m_node_substitute); } } m_node_substitute = nullptr; } -void filter_macro_resolver::visitor::visit(ast::not_expr* e) -{ +void filter_macro_resolver::visitor::visit(ast::not_expr* e) { e->child->accept(this); - if (m_node_substitute) - { + if(m_node_substitute) { e->child = std::move(m_node_substitute); } m_node_substitute = nullptr; } -void filter_macro_resolver::visitor::visit(ast::list_expr* e) -{ +void filter_macro_resolver::visitor::visit(ast::list_expr* e) { m_node_substitute = nullptr; } -void filter_macro_resolver::visitor::visit(ast::binary_check_expr* e) -{ +void filter_macro_resolver::visitor::visit(ast::binary_check_expr* e) { m_node_substitute = nullptr; } -void filter_macro_resolver::visitor::visit(ast::unary_check_expr* e) -{ +void filter_macro_resolver::visitor::visit(ast::unary_check_expr* e) { m_node_substitute = nullptr; } -void filter_macro_resolver::visitor::visit(ast::value_expr* e) -{ +void filter_macro_resolver::visitor::visit(ast::value_expr* e) { m_node_substitute = nullptr; } -void filter_macro_resolver::visitor::visit(ast::field_expr* e) -{ +void filter_macro_resolver::visitor::visit(ast::field_expr* e) { m_node_substitute = nullptr; } -void filter_macro_resolver::visitor::visit(ast::field_transformer_expr* e) -{ +void filter_macro_resolver::visitor::visit(ast::field_transformer_expr* e) { m_node_substitute = nullptr; } -void filter_macro_resolver::visitor::visit(ast::identifier_expr* e) -{ +void filter_macro_resolver::visitor::visit(ast::identifier_expr* e) { const auto& macro = m_macros.find(e->identifier); - if (macro != m_macros.end() && macro->second) // skip null-ptr macros + if(macro != m_macros.end() && macro->second) // skip null-ptr macros { // note: checks for loop detection const auto& prevref = std::find(m_macros_path.begin(), m_macros_path.end(), macro->first); - if (prevref != m_macros_path.end()) - { + if(prevref != m_macros_path.end()) { auto msg = "reference loop in macro '" + macro->first + "'"; m_errors.push_back({msg, e->get_pos()}); m_node_substitute = nullptr; @@ -146,15 +125,12 @@ void filter_macro_resolver::visitor::visit(ast::identifier_expr* e) new_node->accept(this); // new_node might already have set a non-NULL m_node_substitute. // if not, the right substituted is the newly-cloned node. - if (!m_node_substitute) - { + if(!m_node_substitute) { m_node_substitute = std::move(new_node); } m_resolved_macros.push_back({e->identifier, e->get_pos()}); m_macros_path.pop_back(); - } - else - { + } else { m_node_substitute = nullptr; m_unknown_macros.push_back({e->identifier, e->get_pos()}); } diff --git a/userspace/engine/filter_macro_resolver.h b/userspace/engine/filter_macro_resolver.h index 7e1edff7fd5..f293715e2aa 100644 --- a/userspace/engine/filter_macro_resolver.h +++ b/userspace/engine/filter_macro_resolver.h @@ -24,114 +24,107 @@ limitations under the License. #include /*! - \brief Helper class for substituting and resolving macro - references in parsed filters. + \brief Helper class for substituting and resolving macro + references in parsed filters. */ -class filter_macro_resolver -{ - public: - /*! - \brief Visits a filter AST and substitutes macro references - according with all the definitions added through set_macro(), - by replacing the reference with a clone of the macro AST. - \param filter The filter AST to be processed. Note that the pointer - is passed by reference and be transformed in order to apply - the substutions. In that case, the old pointer is owned by this - class and is deleted automatically. - \return true if at least one of the defined macros is resolved - */ - bool run(std::shared_ptr& filter); - - /*! - \brief Defines a new macro to be substituted in filters. If called - multiple times for the same macro name, the previous definition - gets overridden. A macro can be undefined by setting a null - AST pointer. - \param name The name of the macro. - \param macro The AST of the macro. - */ - void set_macro( - const std::string& name, - const std::shared_ptr& macro); - - /*! - \brief used in get_{resolved,unknown}_macros and get_errors - to represent an identifier/string value along with an AST position. - */ - typedef std::pair value_info; - - /*! - \brief Returns a set containing the names of all the macros - substituted during the last invocation of run(). Should be - non-empty if the last invocation of run() returned true. - */ - const std::vector& get_resolved_macros() const; - - /*! - \brief Returns a set containing the names of all the macros - that remained unresolved during the last invocation of run(). - A macro remains unresolved if it is found inside the processed - filter but it was not defined with set_macro(); - */ - const std::vector& get_unknown_macros() const; - - /*! - \brief Returns a list of errors occurred during - the latest invocation of run(). - */ - const std::vector& get_errors() const; - - /*! - \brief Clears the resolver by resetting all state related to - known macros and everything related to the previous resolution run. - */ - inline void clear() - { - m_errors.clear(); - m_unknown_macros.clear(); - m_resolved_macros.clear(); - m_macros.clear(); - } - - private: - typedef std::unordered_map< - std::string, - std::shared_ptr - > macro_defs; - - struct visitor : public libsinsp::filter::ast::expr_visitor - { - visitor( - std::vector& errors, - std::vector& unknown_macros, - std::vector& resolved_macros, - macro_defs& macros): - m_errors(errors), - m_unknown_macros(unknown_macros), - m_resolved_macros(resolved_macros), - m_macros(macros) {} - - std::vector m_macros_path; - std::unique_ptr m_node_substitute; - std::vector& m_errors; - std::vector& m_unknown_macros; - std::vector& m_resolved_macros; - macro_defs& m_macros; - - void visit(libsinsp::filter::ast::and_expr* e) override; - void visit(libsinsp::filter::ast::or_expr* e) override; - void visit(libsinsp::filter::ast::not_expr* e) override; - void visit(libsinsp::filter::ast::identifier_expr* e) override; - void visit(libsinsp::filter::ast::value_expr* e) override; - void visit(libsinsp::filter::ast::list_expr* e) override; - void visit(libsinsp::filter::ast::unary_check_expr* e) override; - void visit(libsinsp::filter::ast::binary_check_expr* e) override; - void visit(libsinsp::filter::ast::field_expr* e) override; - void visit(libsinsp::filter::ast::field_transformer_expr* e) override; - }; - - std::vector m_errors; - std::vector m_unknown_macros; - std::vector m_resolved_macros; - macro_defs m_macros; +class filter_macro_resolver { +public: + /*! + \brief Visits a filter AST and substitutes macro references + according with all the definitions added through set_macro(), + by replacing the reference with a clone of the macro AST. + \param filter The filter AST to be processed. Note that the pointer + is passed by reference and be transformed in order to apply + the substutions. In that case, the old pointer is owned by this + class and is deleted automatically. + \return true if at least one of the defined macros is resolved + */ + bool run(std::shared_ptr& filter); + + /*! + \brief Defines a new macro to be substituted in filters. If called + multiple times for the same macro name, the previous definition + gets overridden. A macro can be undefined by setting a null + AST pointer. + \param name The name of the macro. + \param macro The AST of the macro. + */ + void set_macro(const std::string& name, + const std::shared_ptr& macro); + + /*! + \brief used in get_{resolved,unknown}_macros and get_errors + to represent an identifier/string value along with an AST position. + */ + typedef std::pair value_info; + + /*! + \brief Returns a set containing the names of all the macros + substituted during the last invocation of run(). Should be + non-empty if the last invocation of run() returned true. + */ + const std::vector& get_resolved_macros() const; + + /*! + \brief Returns a set containing the names of all the macros + that remained unresolved during the last invocation of run(). + A macro remains unresolved if it is found inside the processed + filter but it was not defined with set_macro(); + */ + const std::vector& get_unknown_macros() const; + + /*! + \brief Returns a list of errors occurred during + the latest invocation of run(). + */ + const std::vector& get_errors() const; + + /*! + \brief Clears the resolver by resetting all state related to + known macros and everything related to the previous resolution run. + */ + inline void clear() { + m_errors.clear(); + m_unknown_macros.clear(); + m_resolved_macros.clear(); + m_macros.clear(); + } + +private: + typedef std::unordered_map > + macro_defs; + + struct visitor : public libsinsp::filter::ast::expr_visitor { + visitor(std::vector& errors, + std::vector& unknown_macros, + std::vector& resolved_macros, + macro_defs& macros): + m_errors(errors), + m_unknown_macros(unknown_macros), + m_resolved_macros(resolved_macros), + m_macros(macros) {} + + std::vector m_macros_path; + std::unique_ptr m_node_substitute; + std::vector& m_errors; + std::vector& m_unknown_macros; + std::vector& m_resolved_macros; + macro_defs& m_macros; + + void visit(libsinsp::filter::ast::and_expr* e) override; + void visit(libsinsp::filter::ast::or_expr* e) override; + void visit(libsinsp::filter::ast::not_expr* e) override; + void visit(libsinsp::filter::ast::identifier_expr* e) override; + void visit(libsinsp::filter::ast::value_expr* e) override; + void visit(libsinsp::filter::ast::list_expr* e) override; + void visit(libsinsp::filter::ast::unary_check_expr* e) override; + void visit(libsinsp::filter::ast::binary_check_expr* e) override; + void visit(libsinsp::filter::ast::field_expr* e) override; + void visit(libsinsp::filter::ast::field_transformer_expr* e) override; + }; + + std::vector m_errors; + std::vector m_unknown_macros; + std::vector m_resolved_macros; + macro_defs m_macros; }; diff --git a/userspace/engine/filter_ruleset.cpp b/userspace/engine/filter_ruleset.cpp index afc748241bd..3536413ba12 100644 --- a/userspace/engine/filter_ruleset.cpp +++ b/userspace/engine/filter_ruleset.cpp @@ -17,12 +17,10 @@ limitations under the License. #include "filter_ruleset.h" -void filter_ruleset::set_engine_state(const filter_ruleset::engine_state_funcs& engine_state) -{ +void filter_ruleset::set_engine_state(const filter_ruleset::engine_state_funcs& engine_state) { m_engine_state = engine_state; } -filter_ruleset::engine_state_funcs& filter_ruleset::get_engine_state() -{ +filter_ruleset::engine_state_funcs& filter_ruleset::get_engine_state() { return m_engine_state; } diff --git a/userspace/engine/filter_ruleset.h b/userspace/engine/filter_ruleset.h index 0b0ad4597f5..e2ae69d1665 100644 --- a/userspace/engine/filter_ruleset.h +++ b/userspace/engine/filter_ruleset.h @@ -25,25 +25,22 @@ limitations under the License. #include /*! - \brief Manages a set of rulesets. A ruleset is a set of - enabled rules that is able to process events and find matches for those rules. + \brief Manages a set of rulesets. A ruleset is a set of + enabled rules that is able to process events and find matches for those rules. */ -class filter_ruleset -{ +class filter_ruleset { public: // A set of functions that can be used to retrieve state from // the falco engine that created this ruleset. - struct engine_state_funcs - { - using ruleset_retriever_func_t = std::function &ruleset)>; + struct engine_state_funcs { + using ruleset_retriever_func_t = + std::function &ruleset)>; ruleset_retriever_func_t get_ruleset; }; - enum class match_type { - exact, substring, wildcard - }; + enum class match_type { exact, substring, wildcard }; virtual ~filter_ruleset() = default; @@ -51,198 +48,171 @@ class filter_ruleset engine_state_funcs &get_engine_state(); /*! - \brief Adds a rule and its filtering filter + condition inside the manager. + \brief Adds a rule and its filtering filter + condition inside the manager. This method only adds the rule inside the internal collection, - but does not enable it for any ruleset. The rule must be enabled - for one or more rulesets with the enable() or enable_tags() methods. - The ast representation of the rule's condition is provided to allow - the filter_ruleset object to parse the ast to obtain event types - or do other analysis/indexing of the condition. - \param rule The rule to be added - \param the filter representing the rule's filtering condition. - \param condition The AST representing the rule's filtering condition + but does not enable it for any ruleset. The rule must be enabled + for one or more rulesets with the enable() or enable_tags() methods. + The ast representation of the rule's condition is provided to allow + the filter_ruleset object to parse the ast to obtain event types + or do other analysis/indexing of the condition. + \param rule The rule to be added + \param the filter representing the rule's filtering condition. + \param condition The AST representing the rule's filtering condition */ - virtual void add( - const falco_rule& rule, - std::shared_ptr filter, - std::shared_ptr condition) = 0; + virtual void add(const falco_rule &rule, + std::shared_ptr filter, + std::shared_ptr condition) = 0; /*! - \brief Adds all rules contained in the provided - rule_loader::compile_output struct. Only - those rules with the provided source and those rules - with priority >= min_priority should be added. The - intent is that this replaces add(). However, we retain - add() for backwards compatibility. Any rules added via - add() are also added to this ruleset. The default - implementation iterates over rules and calls add(), - but can be overridden. - \param rule The compile output. - \param min_priority Only add rules with priority above this priority. - \param source Only add rules with source equal to this source. + \brief Adds all rules contained in the provided + rule_loader::compile_output struct. Only + those rules with the provided source and those rules + with priority >= min_priority should be added. The + intent is that this replaces add(). However, we retain + add() for backwards compatibility. Any rules added via + add() are also added to this ruleset. The default + implementation iterates over rules and calls add(), + but can be overridden. + \param rule The compile output. + \param min_priority Only add rules with priority above this priority. + \param source Only add rules with source equal to this source. */ - virtual void add_compile_output( - const rule_loader::compile_output& compile_output, - falco_common::priority_type min_priority, - const std::string& source) - { - for (const auto& rule : compile_output.rules) - { - if(rule.priority <= min_priority && - rule.source == source) - { + virtual void add_compile_output(const rule_loader::compile_output &compile_output, + falco_common::priority_type min_priority, + const std::string &source) { + for(const auto &rule : compile_output.rules) { + if(rule.priority <= min_priority && rule.source == source) { add(rule, rule.filter, rule.condition); } } }; /*! - \brief Erases the internal state. All rules are disabled in each - ruleset, and all the rules defined with add() are removed. + \brief Erases the internal state. All rules are disabled in each + ruleset, and all the rules defined with add() are removed. */ virtual void clear() = 0; /*! - \brief This is meant to be called after all rules have been added - with add() and enabled on the given ruleset with enable()/enable_tags(). + \brief This is meant to be called after all rules have been added + with add() and enabled on the given ruleset with enable()/enable_tags(). */ virtual void on_loading_complete() = 0; /*! - \brief Processes an event and tries to find a match in a given ruleset. - \return true if a match is found, false otherwise - \param evt The event to be processed - \param match If true is returned, this is filled-out with the first rule - that matched the event - \param ruleset_id The id of the ruleset to be used + \brief Processes an event and tries to find a match in a given ruleset. + \return true if a match is found, false otherwise + \param evt The event to be processed + \param match If true is returned, this is filled-out with the first rule + that matched the event + \param ruleset_id The id of the ruleset to be used */ - virtual bool run( - sinsp_evt *evt, - falco_rule& match, - uint16_t ruleset_id) = 0; - + virtual bool run(sinsp_evt *evt, falco_rule &match, uint16_t ruleset_id) = 0; + /*! - \brief Processes an event and tries to find a match in a given ruleset. - \return true if a match is found, false otherwise - \param evt The event to be processed - \param matches If true is returned, this is filled-out with all the rules - that matched the event - \param ruleset_id The id of the ruleset to be used + \brief Processes an event and tries to find a match in a given ruleset. + \return true if a match is found, false otherwise + \param evt The event to be processed + \param matches If true is returned, this is filled-out with all the rules + that matched the event + \param ruleset_id The id of the ruleset to be used */ - virtual bool run( - sinsp_evt *evt, - std::vector& matches, - uint16_t ruleset_id) = 0; + virtual bool run(sinsp_evt *evt, std::vector &matches, uint16_t ruleset_id) = 0; /*! - \brief Returns the number of rules enabled in a given ruleset - \param ruleset_id The id of the ruleset to be used + \brief Returns the number of rules enabled in a given ruleset + \param ruleset_id The id of the ruleset to be used */ virtual uint64_t enabled_count(uint16_t ruleset_id) = 0; /*! - \brief Returns the union of the evttypes of all the rules enabled - in a given ruleset - \param ruleset_id The id of the ruleset to be used - \deprecated Must use the new typing-improved `enabled_event_codes` - and `enabled_sc_codes` instead - \note todo(jasondellaluce): remove this in future refactors + \brief Returns the union of the evttypes of all the rules enabled + in a given ruleset + \param ruleset_id The id of the ruleset to be used + \deprecated Must use the new typing-improved `enabled_event_codes` + and `enabled_sc_codes` instead + \note todo(jasondellaluce): remove this in future refactors */ - virtual void enabled_evttypes( - std::set &evttypes, - uint16_t ruleset) = 0; - + virtual void enabled_evttypes(std::set &evttypes, uint16_t ruleset) = 0; + /*! - \brief Returns the all the ppm_sc_codes matching the rules - enabled in a given ruleset. - \param ruleset_id The id of the ruleset to be used + \brief Returns the all the ppm_sc_codes matching the rules + enabled in a given ruleset. + \param ruleset_id The id of the ruleset to be used */ - virtual libsinsp::events::set enabled_sc_codes( - uint16_t ruleset) = 0; - + virtual libsinsp::events::set enabled_sc_codes(uint16_t ruleset) = 0; + /*! - \brief Returns the all the ppm_event_codes matching the rules - enabled in a given ruleset. - \param ruleset_id The id of the ruleset to be used + \brief Returns the all the ppm_event_codes matching the rules + enabled in a given ruleset. + \param ruleset_id The id of the ruleset to be used */ - virtual libsinsp::events::set enabled_event_codes( - uint16_t ruleset) = 0; + virtual libsinsp::events::set enabled_event_codes(uint16_t ruleset) = 0; /*! - \brief Find those rules matching the provided substring and enable - them in the provided ruleset. - \param pattern Pattern used to match rule names. - \param match How to match the pattern against rules: - - exact: rules that has the same exact name as the pattern are matched - - substring: rules having the pattern as a substring in the rule are matched. - An empty pattern matches all rules. - - wildcard: rules with names that satisfies a wildcard (*) pattern are matched. - A "*" pattern matches all rules. - Wildcards can appear anywhere in the pattern (e.g. "*hello*world*") - \param ruleset_id The id of the ruleset to be used + \brief Find those rules matching the provided substring and enable + them in the provided ruleset. + \param pattern Pattern used to match rule names. + \param match How to match the pattern against rules: + - exact: rules that has the same exact name as the pattern are matched + - substring: rules having the pattern as a substring in the rule are matched. + An empty pattern matches all rules. + - wildcard: rules with names that satisfies a wildcard (*) pattern are matched. + A "*" pattern matches all rules. + Wildcards can appear anywhere in the pattern (e.g. "*hello*world*") + \param ruleset_id The id of the ruleset to be used */ - virtual void enable( - const std::string &pattern, - match_type match, - uint16_t ruleset_id) = 0; + virtual void enable(const std::string &pattern, match_type match, uint16_t ruleset_id) = 0; /*! - \brief Find those rules matching the provided substring and disable - them in the provided ruleset. - \param pattern Pattern used to match rule names. - \param match How to match the pattern against rules: - - exact: rules that has the same exact name as the pattern are matched - - substring: rules having the pattern as a substring in the rule are matched. - An empty pattern matches all rules. - - wildcard: rules with names that satisfies a wildcard (*) pattern are matched. - A "*" pattern matches all rules. - Wildcards can appear anywhere in the pattern (e.g. "*hello*world*") - \param ruleset_id The id of the ruleset to be used + \brief Find those rules matching the provided substring and disable + them in the provided ruleset. + \param pattern Pattern used to match rule names. + \param match How to match the pattern against rules: + - exact: rules that has the same exact name as the pattern are matched + - substring: rules having the pattern as a substring in the rule are matched. + An empty pattern matches all rules. + - wildcard: rules with names that satisfies a wildcard (*) pattern are matched. + A "*" pattern matches all rules. + Wildcards can appear anywhere in the pattern (e.g. "*hello*world*") + \param ruleset_id The id of the ruleset to be used */ - virtual void disable( - const std::string &pattern, - match_type match, - uint16_t ruleset_id) = 0; + virtual void disable(const std::string &pattern, match_type match, uint16_t ruleset_id) = 0; /*! - \brief Find those rules that have a tag in the set of tags and - enable them for the provided ruleset. Note that the enabled - status is on the rules, and not the tags--if a rule R has - tags (a, b), and you call enable_tags([a]) and then - disable_tags([b]), R will be disabled despite the - fact it has tag a and was enabled by the first call to - enable_tags. - \param substring Tags used to match ruless - \param ruleset_id The id of the ruleset to be used + \brief Find those rules that have a tag in the set of tags and + enable them for the provided ruleset. Note that the enabled + status is on the rules, and not the tags--if a rule R has + tags (a, b), and you call enable_tags([a]) and then + disable_tags([b]), R will be disabled despite the + fact it has tag a and was enabled by the first call to + enable_tags. + \param substring Tags used to match ruless + \param ruleset_id The id of the ruleset to be used */ - virtual void enable_tags( - const std::set &tags, - uint16_t ruleset_id) = 0; + virtual void enable_tags(const std::set &tags, uint16_t ruleset_id) = 0; /*! - \brief Find those rules that have a tag in the set of tags and - disable them for the provided ruleset. Note that the disabled - status is on the rules, and not the tags--if a rule R has - tags (a, b), and you call enable_tags([a]) and then - disable_tags([b]), R will be disabled despite the - fact it has tag a and was enabled by the first call to - enable_tags. - \param substring Tags used to match ruless - \param ruleset_id The id of the ruleset to be used + \brief Find those rules that have a tag in the set of tags and + disable them for the provided ruleset. Note that the disabled + status is on the rules, and not the tags--if a rule R has + tags (a, b), and you call enable_tags([a]) and then + disable_tags([b]), R will be disabled despite the + fact it has tag a and was enabled by the first call to + enable_tags. + \param substring Tags used to match ruless + \param ruleset_id The id of the ruleset to be used */ - virtual void disable_tags( - const std::set &tags, - uint16_t ruleset_id) = 0; + virtual void disable_tags(const std::set &tags, uint16_t ruleset_id) = 0; private: engine_state_funcs m_engine_state; }; /*! - \brief Represents a factory that creates filter_ruleset objects + \brief Represents a factory that creates filter_ruleset objects */ -class filter_ruleset_factory -{ +class filter_ruleset_factory { public: virtual ~filter_ruleset_factory() = default; diff --git a/userspace/engine/filter_warning_resolver.cpp b/userspace/engine/filter_warning_resolver.cpp index e497b5c0a4a..1afb8c8e6a1 100644 --- a/userspace/engine/filter_warning_resolver.cpp +++ b/userspace/engine/filter_warning_resolver.cpp @@ -22,22 +22,18 @@ using namespace falco; static const char* no_value = ""; -static inline bool is_unsafe_field(const std::string& f) -{ - return !strncmp(f.c_str(), "ka.", strlen("ka.")) - || !strncmp(f.c_str(), "jevt.", strlen("jevt.")); +static inline bool is_unsafe_field(const std::string& f) { + return !strncmp(f.c_str(), "ka.", strlen("ka.")) || + !strncmp(f.c_str(), "jevt.", strlen("jevt.")); } -static inline bool is_equality_operator(const std::string& op) -{ - return op == "==" || op == "=" || op == "!=" - || op == "in" || op == "intersects" || op == "pmatch"; +static inline bool is_equality_operator(const std::string& op) { + return op == "==" || op == "=" || op == "!=" || op == "in" || op == "intersects" || + op == "pmatch"; } -bool filter_warning_resolver::run( - libsinsp::filter::ast::expr* filter, - std::set& warnings) const -{ +bool filter_warning_resolver::run(libsinsp::filter::ast::expr* filter, + std::set& warnings) const { visitor v; auto size = warnings.size(); v.m_is_equality_check = false; @@ -46,40 +42,29 @@ bool filter_warning_resolver::run( return warnings.size() > size; } -void filter_warning_resolver::visitor::visit( - libsinsp::filter::ast::binary_check_expr* e) -{ +void filter_warning_resolver::visitor::visit(libsinsp::filter::ast::binary_check_expr* e) { m_last_node_is_unsafe_field = false; e->left->accept(this); - if (m_last_node_is_unsafe_field && is_equality_operator(e->op)) - { + if(m_last_node_is_unsafe_field && is_equality_operator(e->op)) { m_is_equality_check = true; e->right->accept(this); m_is_equality_check = false; } } -void filter_warning_resolver::visitor::visit( - libsinsp::filter::ast::field_expr* e) -{ +void filter_warning_resolver::visitor::visit(libsinsp::filter::ast::field_expr* e) { m_last_node_is_unsafe_field = is_unsafe_field(e->field); } -void filter_warning_resolver::visitor::visit( - libsinsp::filter::ast::value_expr* e) -{ - if (m_is_equality_check && e->value == no_value) - { +void filter_warning_resolver::visitor::visit(libsinsp::filter::ast::value_expr* e) { + if(m_is_equality_check && e->value == no_value) { m_warnings->insert(load_result::LOAD_UNSAFE_NA_CHECK); } } -void filter_warning_resolver::visitor::visit( - libsinsp::filter::ast::list_expr* e) -{ - if (m_is_equality_check - && std::find(e->values.begin(), e->values.end(), no_value) != e->values.end()) - { +void filter_warning_resolver::visitor::visit(libsinsp::filter::ast::list_expr* e) { + if(m_is_equality_check && + std::find(e->values.begin(), e->values.end(), no_value) != e->values.end()) { m_warnings->insert(load_result::LOAD_UNSAFE_NA_CHECK); } } diff --git a/userspace/engine/filter_warning_resolver.h b/userspace/engine/filter_warning_resolver.h index 8de59082c33..cf0c9ba535d 100644 --- a/userspace/engine/filter_warning_resolver.h +++ b/userspace/engine/filter_warning_resolver.h @@ -25,38 +25,35 @@ limitations under the License. #include "falco_load_result.h" /*! - \brief Searches for bad practices in filter conditions and - generates warning messages + \brief Searches for bad practices in filter conditions and + generates warning messages */ -class filter_warning_resolver -{ +class filter_warning_resolver { public: /*! - \brief Visits a filter AST and substitutes macro references - according with all the definitions added through set_macro(), - by replacing the reference with a clone of the macro AST. - \param filter The filter AST to be visited - \param warnings Set of strings to be filled with warning codes. This - is not cleared up before the visit - \param blocking Filled-out with true if at least one warning is - found and at least one warning prevents the filter from being loaded - \return true if at least one warning is generated + \brief Visits a filter AST and substitutes macro references + according with all the definitions added through set_macro(), + by replacing the reference with a clone of the macro AST. + \param filter The filter AST to be visited + \param warnings Set of strings to be filled with warning codes. This + is not cleared up before the visit + \param blocking Filled-out with true if at least one warning is + found and at least one warning prevents the filter from being loaded + \return true if at least one warning is generated */ - bool run( - libsinsp::filter::ast::expr* filter, - std::set& warnings) const; + bool run(libsinsp::filter::ast::expr* filter, + std::set& warnings) const; private: - struct visitor : public libsinsp::filter::ast::base_expr_visitor - { + struct visitor : public libsinsp::filter::ast::base_expr_visitor { visitor(): - m_is_equality_check(false), - m_last_node_is_unsafe_field(false), - m_warnings(nullptr) {} + m_is_equality_check(false), + m_last_node_is_unsafe_field(false), + m_warnings(nullptr) {} visitor(visitor&&) = default; - visitor& operator = (visitor&&) = default; + visitor& operator=(visitor&&) = default; visitor(const visitor&) = delete; - visitor& operator = (const visitor&) = delete; + visitor& operator=(const visitor&) = delete; bool m_is_equality_check; bool m_last_node_is_unsafe_field; diff --git a/userspace/engine/formats.cpp b/userspace/engine/formats.cpp index ada5746329b..cfbd3939afe 100644 --- a/userspace/engine/formats.cpp +++ b/userspace/engine/formats.cpp @@ -21,41 +21,37 @@ limitations under the License. #include "falco_engine.h" falco_formats::falco_formats(std::shared_ptr engine, - bool json_include_output_property, - bool json_include_tags_property, - bool json_include_message_property, - bool time_format_iso_8601) - : m_falco_engine(engine), - m_json_include_output_property(json_include_output_property), - m_json_include_tags_property(json_include_tags_property), - m_json_include_message_property(json_include_message_property), - m_time_format_iso_8601(time_format_iso_8601) -{ -} - -falco_formats::~falco_formats() -{ -} - -std::string falco_formats::format_event(sinsp_evt *evt, const std::string &rule, const std::string &source, - const std::string &level, const std::string &format, const std::set &tags, - const std::string &hostname, const extra_output_field_t &extra_fields) const -{ + bool json_include_output_property, + bool json_include_tags_property, + bool json_include_message_property, + bool time_format_iso_8601): + m_falco_engine(engine), + m_json_include_output_property(json_include_output_property), + m_json_include_tags_property(json_include_tags_property), + m_json_include_message_property(json_include_message_property), + m_time_format_iso_8601(time_format_iso_8601) {} + +falco_formats::~falco_formats() {} + +std::string falco_formats::format_event(sinsp_evt *evt, + const std::string &rule, + const std::string &source, + const std::string &level, + const std::string &format, + const std::set &tags, + const std::string &hostname, + const extra_output_field_t &extra_fields) const { std::string prefix_format; std::string message_format = format; - if(m_time_format_iso_8601) - { + if(m_time_format_iso_8601) { prefix_format = "*%evt.time.iso8601: "; - } - else - { + } else { prefix_format = "*%evt.time: "; } prefix_format += level; - if(message_format[0] != '*') - { + if(message_format[0] != '*') { message_format = "*" + message_format; } @@ -72,15 +68,13 @@ std::string falco_formats::format_event(sinsp_evt *evt, const std::string &rule, std::string message; message_formatter->tostring_withformat(evt, message, sinsp_evt_formatter::OF_NORMAL); - // The complete Falco output, e.g. "13:53:31.726060287: Critical Some Event Description (proc_exe=bash)..." + // The complete Falco output, e.g. "13:53:31.726060287: Critical Some Event Description + // (proc_exe=bash)..." std::string output = prefix + " " + message; - if(message_formatter->get_output_format() == sinsp_evt_formatter::OF_NORMAL) - { + if(message_formatter->get_output_format() == sinsp_evt_formatter::OF_NORMAL) { return output; - } - else if(message_formatter->get_output_format() == sinsp_evt_formatter::OF_JSON) - { + } else if(message_formatter->get_output_format() == sinsp_evt_formatter::OF_JSON) { std::string json_fields_message; std::string json_fields_prefix; @@ -98,8 +92,8 @@ std::string falco_formats::format_event(sinsp_evt *evt, const std::string &rule, // Convert the time-as-nanoseconds to a more json-friendly ISO8601. time_t evttime = evt->get_ts() / 1000000000; - char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS" - char time_ns[12]; // sizeof ".sssssssssZ" + char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS" + char time_ns[12]; // sizeof ".sssssssssZ" std::string iso8601evttime; strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime)); @@ -112,52 +106,47 @@ std::string falco_formats::format_event(sinsp_evt *evt, const std::string &rule, event["source"] = source; event["hostname"] = hostname; - if(m_json_include_output_property) - { + if(m_json_include_output_property) { event["output"] = output; } - if(m_json_include_tags_property) - { + if(m_json_include_tags_property) { event["tags"] = tags; } - if(m_json_include_message_property) - { + if(m_json_include_message_property) { event["message"] = message; } event["output_fields"] = nlohmann::json::parse(json_fields_message); auto prefix_fields = nlohmann::json::parse(json_fields_prefix); - if (prefix_fields.is_object()) { - for (auto const& el : prefix_fields.items()) { + if(prefix_fields.is_object()) { + for(auto const &el : prefix_fields.items()) { event["output_fields"][el.key()] = el.value(); } } - for (auto const& ef : extra_fields) - { + for(auto const &ef : extra_fields) { std::string fformat = ef.second.first; - if (fformat.size() == 0) - { + if(fformat.size() == 0) { continue; } - if (!(fformat[0] == '*')) - { + if(!(fformat[0] == '*')) { fformat = "*" + fformat; } - if(ef.second.second) // raw field + if(ef.second.second) // raw field { std::string json_field_map; auto field_formatter = m_falco_engine->create_formatter(source, fformat); - field_formatter->tostring_withformat(evt, json_field_map, sinsp_evt_formatter::OF_JSON); + field_formatter->tostring_withformat(evt, + json_field_map, + sinsp_evt_formatter::OF_JSON); auto json_obj = nlohmann::json::parse(json_field_map); event["output_fields"][ef.first] = json_obj[ef.first]; - } else - { + } else { event["output_fields"][ef.first] = format_string(evt, fformat, source); } } @@ -169,8 +158,9 @@ std::string falco_formats::format_event(sinsp_evt *evt, const std::string &rule, return "INVALID_OUTPUT_FORMAT"; } -std::string falco_formats::format_string(sinsp_evt *evt, const std::string &format, const std::string &source) const -{ +std::string falco_formats::format_string(sinsp_evt *evt, + const std::string &format, + const std::string &source) const { std::string line; std::shared_ptr formatter; @@ -180,14 +170,14 @@ std::string falco_formats::format_string(sinsp_evt *evt, const std::string &form return line; } -std::map falco_formats::get_field_values(sinsp_evt *evt, const std::string &source, - const std::string &format) const -{ +std::map falco_formats::get_field_values( + sinsp_evt *evt, + const std::string &source, + const std::string &format) const { std::shared_ptr formatter; std::string fformat = format; - if(fformat[0] != '*') - { + if(fformat[0] != '*') { fformat = "*" + fformat; } @@ -195,8 +185,7 @@ std::map falco_formats::get_field_values(sinsp_evt *ev std::map ret; - if (! formatter->get_field_values(evt, ret)) - { + if(!formatter->get_field_values(evt, ret)) { throw falco_exception("Could not extract all field values from event"); } diff --git a/userspace/engine/formats.h b/userspace/engine/formats.h index 797d6718e2a..6b70e70a640 100644 --- a/userspace/engine/formats.h +++ b/userspace/engine/formats.h @@ -21,24 +21,31 @@ limitations under the License. #include #include "falco_engine.h" -class falco_formats -{ +class falco_formats { public: falco_formats(std::shared_ptr engine, - bool json_include_output_property, - bool json_include_tags_property, - bool json_include_message_property, - bool time_format_iso_8601); + bool json_include_output_property, + bool json_include_tags_property, + bool json_include_message_property, + bool time_format_iso_8601); virtual ~falco_formats(); - std::string format_event(sinsp_evt *evt, const std::string &rule, const std::string &source, - const std::string &level, const std::string &format, const std::set &tags, - const std::string &hostname, const extra_output_field_t &extra_fields) const; - - std::string format_string(sinsp_evt *evt, const std::string &format, const std::string &source) const; - - std::map get_field_values(sinsp_evt *evt, const std::string &source, - const std::string &format) const ; + std::string format_event(sinsp_evt *evt, + const std::string &rule, + const std::string &source, + const std::string &level, + const std::string &format, + const std::set &tags, + const std::string &hostname, + const extra_output_field_t &extra_fields) const; + + std::string format_string(sinsp_evt *evt, + const std::string &format, + const std::string &source) const; + + std::map get_field_values(sinsp_evt *evt, + const std::string &source, + const std::string &format) const; protected: std::shared_ptr m_falco_engine; diff --git a/userspace/engine/indexable_ruleset.h b/userspace/engine/indexable_ruleset.h index debfe15787b..fbf6164b360 100644 --- a/userspace/engine/indexable_ruleset.h +++ b/userspace/engine/indexable_ruleset.h @@ -43,139 +43,98 @@ limitations under the License. // const libsinsp::events::set &filter_wrapper::event_codes(); template -class indexable_ruleset : public filter_ruleset -{ +class indexable_ruleset : public filter_ruleset { public: indexable_ruleset() = default; virtual ~indexable_ruleset() = default; // Required to implement filter_ruleset - void clear() override - { - for(size_t i = 0; i < m_rulesets.size(); i++) - { + void clear() override { + for(size_t i = 0; i < m_rulesets.size(); i++) { m_rulesets[i] = std::make_shared(i); } m_filters.clear(); } - uint64_t enabled_count(uint16_t ruleset_id) override - { - while(m_rulesets.size() < (size_t)ruleset_id + 1) - { + uint64_t enabled_count(uint16_t ruleset_id) override { + while(m_rulesets.size() < (size_t)ruleset_id + 1) { m_rulesets.emplace_back(std::make_shared(m_rulesets.size())); } return m_rulesets[ruleset_id]->num_filters(); } - void enabled_evttypes( - std::set &evttypes, - uint16_t ruleset_id) override - { + void enabled_evttypes(std::set &evttypes, uint16_t ruleset_id) override { evttypes.clear(); - for(const auto &e : enabled_event_codes(ruleset_id)) - { + for(const auto &e : enabled_event_codes(ruleset_id)) { evttypes.insert((uint16_t)e); } } - libsinsp::events::set enabled_sc_codes( - uint16_t ruleset_id) override - { - if(m_rulesets.size() < (size_t)ruleset_id + 1) - { + libsinsp::events::set enabled_sc_codes(uint16_t ruleset_id) override { + if(m_rulesets.size() < (size_t)ruleset_id + 1) { return {}; } return m_rulesets[ruleset_id]->sc_codes(); } - libsinsp::events::set enabled_event_codes( - uint16_t ruleset_id) override - { - if(m_rulesets.size() < (size_t)ruleset_id + 1) - { + libsinsp::events::set enabled_event_codes(uint16_t ruleset_id) override { + if(m_rulesets.size() < (size_t)ruleset_id + 1) { return {}; } return m_rulesets[ruleset_id]->event_codes(); } - void enable( - const std::string &pattern, - match_type match, - uint16_t ruleset_id) override - { + void enable(const std::string &pattern, match_type match, uint16_t ruleset_id) override { enable_disable(pattern, match, true, ruleset_id); } - void disable( - const std::string &pattern, - match_type match, - uint16_t ruleset_id) override - { + void disable(const std::string &pattern, match_type match, uint16_t ruleset_id) override { enable_disable(pattern, match, false, ruleset_id); } - void enable_tags( - const std::set &tags, - uint16_t ruleset_id) override - { + void enable_tags(const std::set &tags, uint16_t ruleset_id) override { enable_disable_tags(tags, true, ruleset_id); } - void disable_tags( - const std::set &tags, - uint16_t ruleset_id) override - { + void disable_tags(const std::set &tags, uint16_t ruleset_id) override { enable_disable_tags(tags, false, ruleset_id); } // Note that subclasses do *not* implement run. Instead, they // implement run_wrappers. - bool run(sinsp_evt *evt, falco_rule &match, uint16_t ruleset_id) override - { - if(m_rulesets.size() < (size_t)ruleset_id + 1) - { + bool run(sinsp_evt *evt, falco_rule &match, uint16_t ruleset_id) override { + if(m_rulesets.size() < (size_t)ruleset_id + 1) { return false; } return m_rulesets[ruleset_id]->run(*this, evt, match); } - bool run(sinsp_evt *evt, std::vector &matches, uint16_t ruleset_id) override - { - if(m_rulesets.size() < (size_t)ruleset_id + 1) - { + bool run(sinsp_evt *evt, std::vector &matches, uint16_t ruleset_id) override { + if(m_rulesets.size() < (size_t)ruleset_id + 1) { return false; } return m_rulesets[ruleset_id]->run(*this, evt, matches); } - typedef std::list> - filter_wrapper_list; + typedef std::list> filter_wrapper_list; // Subclasses should call add_wrapper (most likely from // filter_ruleset::add or ::add_compile_output) to add filters. - void add_wrapper(std::shared_ptr wrap) - { - m_filters.insert(wrap); - } + void add_wrapper(std::shared_ptr wrap) { m_filters.insert(wrap); } // If a subclass needs to iterate over all filters, they can // call iterate with this function, which will be called for // all filters. typedef std::function &wrap)> filter_wrapper_func; - uint64_t iterate(filter_wrapper_func func) - { + uint64_t iterate(filter_wrapper_func func) { uint64_t num_filters = 0; - for(const auto &ruleset_ptr : m_rulesets) - { - if(ruleset_ptr) - { - for(const auto &wrap : ruleset_ptr->get_filters()) - { + for(const auto &ruleset_ptr : m_rulesets) { + if(ruleset_ptr) { + for(const auto &wrap : ruleset_ptr->get_filters()) { num_filters++; func(wrap); } @@ -188,34 +147,34 @@ class indexable_ruleset : public filter_ruleset // A subclass must implement these methods. They are analogous // to run() but take care of selecting filters that match a // ruleset and possibly an event type. - virtual bool run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, std::vector &matches) = 0; - virtual bool run_wrappers(sinsp_evt *evt, filter_wrapper_list &wrappers, uint16_t ruleset_id, falco_rule &match) = 0; + virtual bool run_wrappers(sinsp_evt *evt, + filter_wrapper_list &wrappers, + uint16_t ruleset_id, + std::vector &matches) = 0; + virtual bool run_wrappers(sinsp_evt *evt, + filter_wrapper_list &wrappers, + uint16_t ruleset_id, + falco_rule &match) = 0; private: // Helper used by enable()/disable() - void enable_disable( - const std::string &pattern, - match_type match, - bool enabled, - uint16_t ruleset_id) - { - while(m_rulesets.size() < (size_t)ruleset_id + 1) - { + void enable_disable(const std::string &pattern, + match_type match, + bool enabled, + uint16_t ruleset_id) { + while(m_rulesets.size() < (size_t)ruleset_id + 1) { m_rulesets.emplace_back(std::make_shared(m_rulesets.size())); } - for(const auto &wrap : m_filters) - { + for(const auto &wrap : m_filters) { bool matches; std::string::size_type pos; - switch(match) - { + switch(match) { case match_type::exact: pos = wrap->name().find(pattern); - matches = (pattern == "" || (pos == 0 && - pattern.size() == wrap->name().size())); + matches = (pattern == "" || (pos == 0 && pattern.size() == wrap->name().size())); break; case match_type::substring: matches = (pattern == "" || (wrap->name().find(pattern) != std::string::npos)); @@ -228,14 +187,10 @@ class indexable_ruleset : public filter_ruleset matches = false; } - if(matches) - { - if(enabled) - { + if(matches) { + if(enabled) { m_rulesets[ruleset_id]->add_filter(wrap); - } - else - { + } else { m_rulesets[ruleset_id]->remove_filter(wrap); } } @@ -243,32 +198,24 @@ class indexable_ruleset : public filter_ruleset } // Helper used by enable_tags()/disable_tags() - void enable_disable_tags( - const std::set &tags, - bool enabled, - uint16_t ruleset_id) - { - while(m_rulesets.size() < (size_t)ruleset_id + 1) - { + void enable_disable_tags(const std::set &tags, bool enabled, uint16_t ruleset_id) { + while(m_rulesets.size() < (size_t)ruleset_id + 1) { m_rulesets.emplace_back(std::make_shared(m_rulesets.size())); } - for(const auto &wrap : m_filters) - { + for(const auto &wrap : m_filters) { std::set intersect; - set_intersection(tags.begin(), tags.end(), - wrap->tags().begin(), wrap->tags().end(), - inserter(intersect, intersect.begin())); + set_intersection(tags.begin(), + tags.end(), + wrap->tags().begin(), + wrap->tags().end(), + inserter(intersect, intersect.begin())); - if(!intersect.empty()) - { - if(enabled) - { + if(!intersect.empty()) { + if(enabled) { m_rulesets[ruleset_id]->add_filter(wrap); - } - else - { + } else { m_rulesets[ruleset_id]->remove_filter(wrap); } } @@ -276,27 +223,19 @@ class indexable_ruleset : public filter_ruleset } // A group of filters all having the same ruleset - class ruleset_filters - { + class ruleset_filters { public: - ruleset_filters(uint16_t ruleset_id): - m_ruleset_id(ruleset_id) {} + ruleset_filters(uint16_t ruleset_id): m_ruleset_id(ruleset_id) {} - virtual ~ruleset_filters(){}; + virtual ~ruleset_filters() {}; - void add_filter(std::shared_ptr wrap) - { - if(wrap->event_codes().empty()) - { + void add_filter(std::shared_ptr wrap) { + if(wrap->event_codes().empty()) { // Should run for all event types add_wrapper_to_list(m_filter_all_event_types, wrap); - } - else - { - for(auto &etype : wrap->event_codes()) - { - if(m_filter_by_event_type.size() <= etype) - { + } else { + for(auto &etype : wrap->event_codes()) { + if(m_filter_by_event_type.size() <= etype) { m_filter_by_event_type.resize(etype + 1); } @@ -307,18 +246,12 @@ class indexable_ruleset : public filter_ruleset m_filters.insert(wrap); } - void remove_filter(std::shared_ptr wrap) - { - if(wrap->event_codes().empty()) - { + void remove_filter(std::shared_ptr wrap) { + if(wrap->event_codes().empty()) { remove_wrapper_from_list(m_filter_all_event_types, wrap); - } - else - { - for(auto &etype : wrap->event_codes()) - { - if(etype < m_filter_by_event_type.size()) - { + } else { + for(auto &etype : wrap->event_codes()) { + if(etype < m_filter_by_event_type.size()) { remove_wrapper_from_list(m_filter_by_event_type[etype], wrap); } } @@ -327,34 +260,28 @@ class indexable_ruleset : public filter_ruleset m_filters.erase(wrap); } - uint64_t num_filters() - { - return m_filters.size(); - } + uint64_t num_filters() { return m_filters.size(); } - inline const std::set> &get_filters() const - { + inline const std::set> &get_filters() const { return m_filters; } // Evaluate an event against the ruleset and return the first rule // that matched. - bool run(indexable_ruleset &ruleset, sinsp_evt *evt, falco_rule &match) - { + bool run(indexable_ruleset &ruleset, sinsp_evt *evt, falco_rule &match) { if(evt->get_type() < m_filter_by_event_type.size() && - m_filter_by_event_type[evt->get_type()].size() > 0) - { - if(ruleset.run_wrappers(evt, m_filter_by_event_type[evt->get_type()], m_ruleset_id, match)) - { + m_filter_by_event_type[evt->get_type()].size() > 0) { + if(ruleset.run_wrappers(evt, + m_filter_by_event_type[evt->get_type()], + m_ruleset_id, + match)) { return true; } } // Finally, try filters that are not specific to an event type. - if(m_filter_all_event_types.size() > 0) - { - if(ruleset.run_wrappers(evt, m_filter_all_event_types, m_ruleset_id, match)) - { + if(m_filter_all_event_types.size() > 0) { + if(ruleset.run_wrappers(evt, m_filter_all_event_types, m_ruleset_id, match)) { return true; } } @@ -364,22 +291,20 @@ class indexable_ruleset : public filter_ruleset // Evaluate an event against the ruleset and return all the // matching rules. - bool run(indexable_ruleset &ruleset, sinsp_evt *evt, std::vector &matches) - { + bool run(indexable_ruleset &ruleset, sinsp_evt *evt, std::vector &matches) { if(evt->get_type() < m_filter_by_event_type.size() && - m_filter_by_event_type[evt->get_type()].size() > 0) - { - if(ruleset.run_wrappers(evt, m_filter_by_event_type[evt->get_type()], m_ruleset_id, matches)) - { + m_filter_by_event_type[evt->get_type()].size() > 0) { + if(ruleset.run_wrappers(evt, + m_filter_by_event_type[evt->get_type()], + m_ruleset_id, + matches)) { return true; } } // Finally, try filters that are not specific to an event type. - if(m_filter_all_event_types.size() > 0) - { - if(ruleset.run_wrappers(evt, m_filter_all_event_types, m_ruleset_id, matches)) - { + if(m_filter_all_event_types.size() > 0) { + if(ruleset.run_wrappers(evt, m_filter_all_event_types, m_ruleset_id, matches)) { return true; } } @@ -387,49 +312,39 @@ class indexable_ruleset : public filter_ruleset return false; } - libsinsp::events::set sc_codes() - { + libsinsp::events::set sc_codes() { libsinsp::events::set res; - for(const auto &wrap : m_filters) - { + for(const auto &wrap : m_filters) { res.insert(wrap->sc_codes().begin(), wrap->sc_codes().end()); } return res; } - libsinsp::events::set event_codes() - { + libsinsp::events::set event_codes() { libsinsp::events::set res; - for(const auto &wrap : m_filters) - { + for(const auto &wrap : m_filters) { res.insert(wrap->event_codes().begin(), wrap->event_codes().end()); } return res; } private: - void add_wrapper_to_list(filter_wrapper_list &wrappers, std::shared_ptr wrap) - { + void add_wrapper_to_list(filter_wrapper_list &wrappers, + std::shared_ptr wrap) { // This is O(n) but it's also uncommon // (when loading rules only). - auto pos = std::find(wrappers.begin(), - wrappers.end(), - wrap); + auto pos = std::find(wrappers.begin(), wrappers.end(), wrap); - if(pos == wrappers.end()) - { + if(pos == wrappers.end()) { wrappers.push_back(wrap); } } - void remove_wrapper_from_list(filter_wrapper_list &wrappers, std::shared_ptr wrap) - { + void remove_wrapper_from_list(filter_wrapper_list &wrappers, + std::shared_ptr wrap) { // This is O(n) but it's also uncommon // (when loading rules only). - auto pos = std::find(wrappers.begin(), - wrappers.end(), - wrap); - if(pos != wrappers.end()) - { + auto pos = std::find(wrappers.begin(), wrappers.end(), wrap); + if(pos != wrappers.end()) { wrappers.erase(pos); } } diff --git a/userspace/engine/indexed_vector.h b/userspace/engine/indexed_vector.h index 13a25a9bcfe..21d3cbf643f 100644 --- a/userspace/engine/indexed_vector.h +++ b/userspace/engine/indexed_vector.h @@ -22,63 +22,54 @@ limitations under the License. #include /*! - \brief Simple wrapper of std::vector that allows random access - through both numeric and string indexes with O(1) complexity + \brief Simple wrapper of std::vector that allows random access + through both numeric and string indexes with O(1) complexity */ -template -class indexed_vector -{ +template +class indexed_vector { public: indexed_vector() = default; virtual ~indexed_vector() = default; indexed_vector(indexed_vector&&) = default; - indexed_vector& operator = (indexed_vector&&) = default; + indexed_vector& operator=(indexed_vector&&) = default; indexed_vector(const indexed_vector&) = default; - indexed_vector& operator = (const indexed_vector&) = default; + indexed_vector& operator=(const indexed_vector&) = default; /*! - \brief Returns the number of elements + \brief Returns the number of elements */ - virtual inline size_t size() const - { - return m_entries.size(); - } + virtual inline size_t size() const { return m_entries.size(); } /*! - \brief Returns true if the vector is empty + \brief Returns true if the vector is empty */ - virtual inline bool empty() const - { - return m_entries.empty(); - } + virtual inline bool empty() const { return m_entries.empty(); } /*! - \brief Removes all the elements + \brief Removes all the elements */ - virtual inline void clear() - { + virtual inline void clear() { m_entries.clear(); m_index.clear(); } /*! - \brief Inserts a new element in the vector with a given string index - and returns its numeric index. String indexes are unique in - the vector. If no element is already present with the given string - index, then the provided element is added to the vector and its - numeric index is assigned as the next free slot in the vector. - Otherwise, the existing element gets overwritten with the contents - of the provided one and the numeric index of the existing element - is returned. - \param entry Element to add in the vector - \param index String index of the element to be added in the vector - \return The numeric index assigned to the element + \brief Inserts a new element in the vector with a given string index + and returns its numeric index. String indexes are unique in + the vector. If no element is already present with the given string + index, then the provided element is added to the vector and its + numeric index is assigned as the next free slot in the vector. + Otherwise, the existing element gets overwritten with the contents + of the provided one and the numeric index of the existing element + is returned. + \param entry Element to add in the vector + \param index String index of the element to be added in the vector + \return The numeric index assigned to the element */ - virtual inline size_t insert(const T& entry, const std::string& index) - { + virtual inline size_t insert(const T& entry, const std::string& index) { size_t id; auto prev = m_index.find(index); - if (prev != m_index.end()) { + if(prev != m_index.end()) { id = prev->second; m_entries[id] = entry; return id; @@ -90,50 +81,37 @@ class indexed_vector } /*! - \brief Returns a pointer to the element at the given numeric index, - or nullptr if no element exists at the given index. + \brief Returns a pointer to the element at the given numeric index, + or nullptr if no element exists at the given index. */ - virtual inline T* at(size_t id) const - { - if (id < m_entries.size()) - { - return (T* const) &m_entries[id]; + virtual inline T* at(size_t id) const { + if(id < m_entries.size()) { + return (T* const)&m_entries[id]; } return nullptr; } /*! - \brief Returns a pointer to the element at the given string index, - or nullptr if no element exists at the given index. + \brief Returns a pointer to the element at the given string index, + or nullptr if no element exists at the given index. */ - virtual inline T* at(const std::string& index) const - { + virtual inline T* at(const std::string& index) const { auto it = m_index.find(index); - if (it != m_index.end()) { + if(it != m_index.end()) { return at(it->second); } return nullptr; } - virtual inline typename std::vector::iterator begin() - { - return m_entries.begin(); - } + virtual inline typename std::vector::iterator begin() { return m_entries.begin(); } - virtual inline typename std::vector::iterator end() - { - return m_entries.end(); - } + virtual inline typename std::vector::iterator end() { return m_entries.end(); } - virtual inline typename std::vector::const_iterator begin() const - { + virtual inline typename std::vector::const_iterator begin() const { return m_entries.begin(); } - virtual inline typename std::vector::const_iterator end() const - { - return m_entries.end(); - } + virtual inline typename std::vector::const_iterator end() const { return m_entries.end(); } private: std::vector m_entries; diff --git a/userspace/engine/logger.cpp b/userspace/engine/logger.cpp index 78b4ca8ef62..859aa36a83b 100644 --- a/userspace/engine/logger.cpp +++ b/userspace/engine/logger.cpp @@ -23,133 +23,89 @@ limitations under the License. falco_logger::level falco_logger::current_level = falco_logger::level::INFO; bool falco_logger::time_format_iso_8601 = false; -static sinsp_logger::severity decode_sinsp_severity(const std::string& s) -{ - if(s == "trace") - { +static sinsp_logger::severity decode_sinsp_severity(const std::string& s) { + if(s == "trace") { return sinsp_logger::SEV_TRACE; - } - else if(s == "debug") - { + } else if(s == "debug") { return sinsp_logger::SEV_DEBUG; - } - else if(s == "info") - { + } else if(s == "info") { return sinsp_logger::SEV_INFO; - } - else if(s == "notice") - { + } else if(s == "notice") { return sinsp_logger::SEV_NOTICE; - } - else if(s == "warning") - { + } else if(s == "warning") { return sinsp_logger::SEV_WARNING; - } - else if(s == "error") - { + } else if(s == "error") { return sinsp_logger::SEV_ERROR; - } - else if(s == "critical") - { + } else if(s == "critical") { return sinsp_logger::SEV_CRITICAL; - } - else if(s == "fatal") - { + } else if(s == "fatal") { return sinsp_logger::SEV_FATAL; } throw falco_exception("Unknown sinsp log severity " + s); } -void falco_logger::set_time_format_iso_8601(bool val) -{ +void falco_logger::set_time_format_iso_8601(bool val) { falco_logger::time_format_iso_8601 = val; } -void falco_logger::set_level(const std::string &level) -{ - if(level == "emergency") - { +void falco_logger::set_level(const std::string& level) { + if(level == "emergency") { falco_logger::current_level = falco_logger::level::EMERG; - } - else if(level == "alert") - { + } else if(level == "alert") { falco_logger::current_level = falco_logger::level::ALERT; - } - else if(level == "critical") - { + } else if(level == "critical") { falco_logger::current_level = falco_logger::level::CRIT; - } - else if(level == "error") - { + } else if(level == "error") { falco_logger::current_level = falco_logger::level::ERR; - } - else if(level == "warning") - { + } else if(level == "warning") { falco_logger::current_level = falco_logger::level::WARNING; - } - else if(level == "notice") - { + } else if(level == "notice") { falco_logger::current_level = falco_logger::level::NOTICE; - } - else if(level == "info") - { + } else if(level == "info") { falco_logger::current_level = falco_logger::level::INFO; - } - else if(level == "debug") - { + } else if(level == "debug") { falco_logger::current_level = falco_logger::level::DEBUG; - } - else - { + } else { throw falco_exception("Unknown log level " + level); } } static std::string s_sinsp_logger_prefix = ""; -void falco_logger::set_sinsp_logging(bool enable, const std::string& severity, const std::string& prefix) -{ - if (enable) - { +void falco_logger::set_sinsp_logging(bool enable, + const std::string& severity, + const std::string& prefix) { + if(enable) { s_sinsp_logger_prefix = prefix; libsinsp_logger()->set_severity(decode_sinsp_severity(severity)); libsinsp_logger()->disable_timestamps(); libsinsp_logger()->add_callback_log( - [](std::string&& str, const sinsp_logger::severity sev) - { - // note: using falco_logger::level ensures that the sinsp - // logs are always printed by the Falco logger. These - // logs are pre-filtered at the sinsp level depending - // on the configured severity - falco_logger::log(falco_logger::current_level, s_sinsp_logger_prefix + str); - }); - } - else - { + [](std::string&& str, const sinsp_logger::severity sev) { + // note: using falco_logger::level ensures that the sinsp + // logs are always printed by the Falco logger. These + // logs are pre-filtered at the sinsp level depending + // on the configured severity + falco_logger::log(falco_logger::current_level, s_sinsp_logger_prefix + str); + }); + } else { libsinsp_logger()->remove_callback_log(); } } - bool falco_logger::log_stderr = true; bool falco_logger::log_syslog = true; -void falco_logger::log(falco_logger::level priority, const std::string&& msg) -{ - - if(priority > falco_logger::current_level) - { +void falco_logger::log(falco_logger::level priority, const std::string&& msg) { + if(priority > falco_logger::current_level) { return; } std::string copy = msg; #ifndef _WIN32 - if (falco_logger::log_syslog) - { + if(falco_logger::log_syslog) { // Syslog output should not have any trailing newline - if(copy.back() == '\n') - { + if(copy.back() == '\n') { copy.pop_back(); } @@ -157,37 +113,27 @@ void falco_logger::log(falco_logger::level priority, const std::string&& msg) } #endif - if (falco_logger::log_stderr) - { + if(falco_logger::log_stderr) { // log output should always have a trailing newline - if(copy.back() != '\n') - { + if(copy.back() != '\n') { copy.push_back('\n'); } std::time_t result = std::time(nullptr); - if(falco_logger::time_format_iso_8601) - { + if(falco_logger::time_format_iso_8601) { char buf[sizeof "YYYY-MM-DDTHH:MM:SS-0000"]; - const struct tm *gtm = std::gmtime(&result); - if(gtm != NULL && - (strftime(buf, sizeof(buf), "%FT%T%z", gtm) != 0)) - { + const struct tm* gtm = std::gmtime(&result); + if(gtm != NULL && (strftime(buf, sizeof(buf), "%FT%T%z", gtm) != 0)) { fprintf(stderr, "%s: %s", buf, copy.c_str()); } - } - else - { - const struct tm *ltm = std::localtime(&result); - char *atime = (ltm ? std::asctime(ltm) : NULL); + } else { + const struct tm* ltm = std::localtime(&result); + char* atime = (ltm ? std::asctime(ltm) : NULL); std::string tstr; - if(atime) - { + if(atime) { tstr = atime; - tstr = tstr.substr(0, 24);// remove trailing newline - } - else - { + tstr = tstr.substr(0, 24); // remove trailing newline + } else { tstr = "N/A"; } fprintf(stderr, "%s: %s", tstr.c_str(), copy.c_str()); diff --git a/userspace/engine/logger.h b/userspace/engine/logger.h index 25b7a29a2b3..919c5cc42c3 100644 --- a/userspace/engine/logger.h +++ b/userspace/engine/logger.h @@ -22,28 +22,18 @@ limitations under the License. #include #endif -class falco_logger -{ - public: - - enum class level : int - { - EMERG = 0, - ALERT, - CRIT, - ERR, - WARNING, - NOTICE, - INFO, - DEBUG - }; +class falco_logger { +public: + enum class level : int { EMERG = 0, ALERT, CRIT, ERR, WARNING, NOTICE, INFO, DEBUG }; static void set_time_format_iso_8601(bool val); // Will throw exception if level is unknown. - static void set_level(const std::string &level); + static void set_level(const std::string& level); - static void set_sinsp_logging(bool enable, const std::string& severity, const std::string& prefix); + static void set_sinsp_logging(bool enable, + const std::string& severity, + const std::string& prefix); static void log(falco_logger::level priority, const std::string&& msg); diff --git a/userspace/engine/rule_loader.cpp b/userspace/engine/rule_loader.cpp index c04ab3b47cc..83a2b92d92d 100644 --- a/userspace/engine/rule_loader.cpp +++ b/userspace/engine/rule_loader.cpp @@ -20,72 +20,62 @@ limitations under the License. #include "rule_loader.h" #include "yaml_helper.h" - -static const std::string item_type_strings[] = { - "value for", - "exceptions", - "exception", - "exception values", - "exception value", - "rules content", - "rules content item", - "required_engine_version", - "required plugin versions", - "required plugin versions entry", - "required plugin versions alternative", - "list", - "list item", - "macro", - "macro condition", - "rule", - "rule condition", - "condition expression", - "rule output", - "rule output expression", - "rule priority", - "overrides", - "extension item" -}; - -const std::string& rule_loader::context::item_type_as_string(enum item_type it) -{ +static const std::string item_type_strings[] = {"value for", + "exceptions", + "exception", + "exception values", + "exception value", + "rules content", + "rules content item", + "required_engine_version", + "required plugin versions", + "required plugin versions entry", + "required plugin versions alternative", + "list", + "list item", + "macro", + "macro condition", + "rule", + "rule condition", + "condition expression", + "rule output", + "rule output expression", + "rule priority", + "overrides", + "extension item"}; + +const std::string& rule_loader::context::item_type_as_string(enum item_type it) { return item_type_strings[it]; } -rule_loader::context::context(const std::string& name) -{ +rule_loader::context::context(const std::string& name) { // This ensures that every context has one location, even if // that location is effectively the whole document. location loc = {name, position(), rule_loader::context::RULES_CONTENT, ""}; m_locs.push_back(loc); } -rule_loader::context::context(const YAML::Node &item, - const item_type item_type, - const std::string& item_name, - const context& parent) -{ +rule_loader::context::context(const YAML::Node& item, + const item_type item_type, + const std::string& item_name, + const context& parent) { init(parent.name(), position(item.Mark()), item_type, item_name, parent); } -rule_loader::context::context(const YAML::Mark &mark, const context& parent) -{ +rule_loader::context::context(const YAML::Mark& mark, const context& parent) { init(parent.name(), position(mark), item_type::VALUE_FOR, "", parent); } rule_loader::context::context(const libsinsp::filter::ast::pos_info& pos, - const std::string& condition, - const context& parent) - : alt_content(condition) -{ - + const std::string& condition, + const context& parent): + alt_content(condition) { // Contexts based on conditions don't use the // filename. Instead the "name" is just the condition, and // uses a short prefix of the condition. - std::string condition_name = "\"" + ( - condition.length() > 20 - ? condition.substr(0, 20 - 3) + "...\"" - : condition + "\""); + std::string condition_name = + "\"" + + (condition.length() > 20 ? condition.substr(0, 20 - 3) + "...\"" : condition + "\""); std::replace(condition_name.begin(), condition_name.end(), '\n', ' '); std::replace(condition_name.begin(), condition_name.end(), '\r', ' '); @@ -104,11 +94,9 @@ rule_loader::context::context(const libsinsp::filter::ast::pos_info& pos, init(condition_name, condpos, rule_loader::context::CONDITION_EXPRESSION, item_name, parent); } -const std::string& rule_loader::context::name() const -{ +const std::string& rule_loader::context::name() const { // All valid contexts should have at least one location. - if(m_locs.empty()) - { + if(m_locs.empty()) { throw falco_exception("rule_loader::context without location?"); } @@ -116,11 +104,10 @@ const std::string& rule_loader::context::name() const } void rule_loader::context::init(const std::string& name, - const position& pos, - const item_type item_type, - const std::string& item_name, - const context& parent) -{ + const position& pos, + const item_type item_type, + const std::string& item_name, + const context& parent) { // Copy parent locations m_locs = parent.m_locs; @@ -129,54 +116,43 @@ void rule_loader::context::init(const std::string& name, m_locs.push_back(loc); } -std::string rule_loader::context::as_string() -{ +std::string rule_loader::context::as_string() { std::ostringstream os; // All valid contexts should have at least one location. - if(m_locs.empty()) - { + if(m_locs.empty()) { throw falco_exception("rule_loader::context without location?"); } bool first = true; - for(const auto& loc : m_locs) - { + for(const auto& loc : m_locs) { os << (first ? "In " : " "); first = false; os << item_type_as_string(loc.item_type); - if(!loc.item_name.empty()) - { + if(!loc.item_name.empty()) { os << " '" << loc.item_name << "'"; } os << ": "; - os << "(" - << loc.name << ":" - << loc.pos.line << ":" - << loc.pos.column - << ")" << std::endl; + os << "(" << loc.name << ":" << loc.pos.line << ":" << loc.pos.column << ")" << std::endl; } return os.str(); } -nlohmann::json rule_loader::context::as_json() -{ +nlohmann::json rule_loader::context::as_json() { nlohmann::json ret; ret["locations"] = nlohmann::json::array(); // All valid contexts should have at least one location. - if(m_locs.empty()) - { + if(m_locs.empty()) { throw falco_exception("rule_loader::context without location?"); } - for(const auto& loc : m_locs) - { + for(const auto& loc : m_locs) { nlohmann::json jloc, jpos; jloc["item_type"] = item_type_as_string(loc.item_type); @@ -195,28 +171,25 @@ nlohmann::json rule_loader::context::as_json() return ret; } -std::string rule_loader::context::snippet(const falco::load_result::rules_contents_t& rules_contents, - size_t snippet_width) const -{ +std::string rule_loader::context::snippet( + const falco::load_result::rules_contents_t& rules_contents, + size_t snippet_width) const { // All valid contexts should have at least one location. - if(m_locs.empty()) - { + if(m_locs.empty()) { throw falco_exception("rule_loader::context without location?"); } rule_loader::context::location loc = m_locs.back(); auto it = rules_contents.find(loc.name); - if(alt_content.empty() && it == rules_contents.end()) - { + if(alt_content.empty() && it == rules_contents.end()) { return "\n"; } // If not using alt content, the last location's name must be found in rules_contents const std::string& snip_content = (!alt_content.empty() ? alt_content : it->second.get()); - if(snip_content.empty()) - { + if(snip_content.empty()) { return "\n"; } @@ -225,7 +198,8 @@ std::string rule_loader::context::snippet(const falco::load_result::rules_conten // tags: // The YAML::Mark position can be past the end of the file. size_t pos = loc.pos.pos; - for(; pos > 0 && (pos >= snip_content.size() || snip_content.at(pos) == '\n'); pos--); + for(; pos > 0 && (pos >= snip_content.size() || snip_content.at(pos) == '\n'); pos--) + ; // The snippet is generally the line that contains the // position. So walk backwards from pos to the preceding @@ -236,151 +210,127 @@ std::string rule_loader::context::snippet(const falco::load_result::rules_conten // forwards/walk backwards is capped at a maximum of // snippet_width/2 characters in either direction. size_t from = pos; - for(; from > 0 && snip_content.at(from) != '\n' && (pos - from) < (snippet_width/2); from--); + for(; from > 0 && snip_content.at(from) != '\n' && (pos - from) < (snippet_width / 2); from--) + ; size_t to = pos; - for(; to < snip_content.size()-1 && snip_content.at(to) != '\n' && (to - pos) < (snippet_width/2); to++); + for(; to < snip_content.size() - 1 && snip_content.at(to) != '\n' && + (to - pos) < (snippet_width / 2); + to++) + ; // Don't include the newlines - if(from < snip_content.size() && snip_content.at(from) == '\n') - { + if(from < snip_content.size() && snip_content.at(from) == '\n') { from++; } - if(to < snip_content.size() && snip_content.at(to) == '\n') - { + if(to < snip_content.size() && snip_content.at(to) == '\n') { to--; } - std::string ret = snip_content.substr(from, to-from+1); + std::string ret = snip_content.substr(from, to - from + 1); - if(ret.empty()) - { + if(ret.empty()) { return "\n"; } // Replace the initial/end characters with '...' if the walk // forwards/backwards was incomplete - if(pos - from >= (snippet_width/2)) - { + if(pos - from >= (snippet_width / 2)) { ret.replace(0, 3, "..."); } - if(to - pos >= (snippet_width/2)) - { - ret.replace(ret.size()-3, 3, "..."); + if(to - pos >= (snippet_width / 2)) { + ret.replace(ret.size() - 3, 3, "..."); } ret += "\n"; // Add a blank line with a marker at the position within the snippet - if(pos-from <= ret.size() - 1) - { - ret += std::string(pos-from, ' ') + '^' + "\n"; + if(pos - from <= ret.size() - 1) { + ret += std::string(pos - from, ' ') + '^' + "\n"; } return ret; } -rule_loader::result::result(const std::string &name) - : name(name), - success(true) -{ -} +rule_loader::result::result(const std::string& name): name(name), success(true) {} -bool rule_loader::result::successful() -{ +bool rule_loader::result::successful() { return success; } -bool rule_loader::result::has_warnings() -{ +bool rule_loader::result::has_warnings() { return (warnings.size() > 0); } -std::string rule_loader::result::schema_validation() -{ - if (schema_validation_status.empty()) - { +std::string rule_loader::result::schema_validation() { + if(schema_validation_status.empty()) { return yaml_helper::validation_none; } return schema_validation_status[0]; } -void rule_loader::result::add_error(load_result::error_code ec, const std::string& msg, const context& ctx) -{ +void rule_loader::result::add_error(load_result::error_code ec, + const std::string& msg, + const context& ctx) { error err = {ec, msg, ctx}; success = false; errors.push_back(err); } -void rule_loader::result::add_warning(load_result::warning_code wc, const std::string& msg, const context& ctx) -{ +void rule_loader::result::add_warning(load_result::warning_code wc, + const std::string& msg, + const context& ctx) { warning warn = {wc, msg, ctx}; warnings.push_back(warn); } -void rule_loader::result::set_schema_validation_status(const std::vector& status) -{ +void rule_loader::result::set_schema_validation_status(const std::vector& status) { schema_validation_status = status; } -const std::string& rule_loader::result::as_string(bool verbose, const rules_contents_t& contents) -{ - if(verbose) - { +const std::string& rule_loader::result::as_string(bool verbose, const rules_contents_t& contents) { + if(verbose) { return as_verbose_string(contents); - } - else - { + } else { return as_summary_string(); } } -const std::string& rule_loader::result::as_summary_string() -{ +const std::string& rule_loader::result::as_summary_string() { std::ostringstream os; - if(!res_summary_string.empty()) - { + if(!res_summary_string.empty()) { return res_summary_string; } - if(!name.empty()) - { + if(!name.empty()) { os << name << ": "; } - if(success) - { + if(success) { os << "Ok"; - if (!warnings.empty()) - { + if(!warnings.empty()) { os << ", with warnings"; } - } - else - { + } else { os << "Invalid"; } // Only print schema validation info if any validation was requested - if (!schema_validation_status.empty()) - { + if(!schema_validation_status.empty()) { bool schema_valid = schema_validation() == yaml_helper::validation_ok; // Only print info when there are validation warnings - if (!schema_valid) - { + if(!schema_valid) { os << std::endl; os << " " << schema_validation_status.size() << " schema warnings: ["; bool first = true; - for(auto& status : schema_validation_status) - { - if(!first) - { + for(auto& status : schema_validation_status) { + if(!first) { os << " "; } first = false; @@ -391,42 +341,36 @@ const std::string& rule_loader::result::as_summary_string() } } - if(!errors.empty()) - { + if(!errors.empty()) { os << std::endl; os << " " << errors.size() << " errors: ["; bool first = true; - for(auto &err : errors) - { - if(!first) - { + for(auto& err : errors) { + if(!first) { os << " "; } first = false; - os << load_result::error_code_str(err.ec) - << " (" << load_result::error_str(err.ec) << ")"; + os << load_result::error_code_str(err.ec) << " (" << load_result::error_str(err.ec) + << ")"; } os << "]"; } - if(!warnings.empty()) - { + if(!warnings.empty()) { os << std::endl; os << " " << warnings.size() << " warnings: ["; bool first = true; - for(auto &warn : warnings) - { - if(!first) - { + for(auto& warn : warnings) { + if(!first) { os << " "; } first = false; - os << load_result::warning_code_str(warn.wc) - << " (" << load_result::warning_str(warn.wc) << ")"; + os << load_result::warning_code_str(warn.wc) << " (" + << load_result::warning_str(warn.wc) << ")"; } os << "]"; } @@ -435,93 +379,73 @@ const std::string& rule_loader::result::as_summary_string() return res_summary_string; } -const std::string& rule_loader::result::as_verbose_string(const rules_contents_t& contents) -{ +const std::string& rule_loader::result::as_verbose_string(const rules_contents_t& contents) { std::ostringstream os; - if(!res_verbose_string.empty()) - { + if(!res_verbose_string.empty()) { return res_verbose_string; } - if(!name.empty()) - { + if(!name.empty()) { os << name << ": "; } - if(success) - { + if(success) { os << "Ok"; - if (!warnings.empty()) - { + if(!warnings.empty()) { os << ", with warnings"; } - } - else - { + } else { os << "Invalid"; } // Only print schema validation info if any validation was requested - if (!schema_validation_status.empty()) - { + if(!schema_validation_status.empty()) { bool schema_valid = schema_validation() == yaml_helper::validation_ok; // Only print info when there are validation warnings - if (!schema_valid) - { + if(!schema_valid) { os << std::endl; - os << schema_validation_status.size() - << " Schema warnings:" << std::endl; + os << schema_validation_status.size() << " Schema warnings:" << std::endl; - for(auto& status : schema_validation_status) - { + for(auto& status : schema_validation_status) { os << "------" << std::endl; os << status << std::endl; } os << "------" << std::endl; } } - if (!errors.empty()) - { + if(!errors.empty()) { os << std::endl; - os << errors.size() - << " Errors:" << std::endl; + os << errors.size() << " Errors:" << std::endl; - for(auto &err : errors) - { + for(auto& err : errors) { os << err.ctx.as_string(); os << "------" << std::endl; os << err.ctx.snippet(contents); os << "------" << std::endl; - os << load_result::error_code_str(err.ec) - << " (" << load_result::error_str(err.ec) << "): " - << err.msg - << std::endl; + os << load_result::error_code_str(err.ec) << " (" << load_result::error_str(err.ec) + << "): " << err.msg << std::endl; } } - if (!warnings.empty()) - { + if(!warnings.empty()) { os << std::endl; - os << warnings.size() - << " Warnings:" << std::endl; + os << warnings.size() << " Warnings:" << std::endl; - for(auto &warn : warnings) - { + for(auto& warn : warnings) { os << warn.ctx.as_string(); os << "------" << std::endl; os << warn.ctx.snippet(contents); os << "------" << std::endl; - os << load_result::warning_code_str(warn.wc) - << " (" << load_result::warning_str(warn.wc) << "): " - << warn.msg; + os << load_result::warning_code_str(warn.wc) << " (" + << load_result::warning_str(warn.wc) << "): " << warn.msg; os << std::endl; } } @@ -530,12 +454,10 @@ const std::string& rule_loader::result::as_verbose_string(const rules_contents_t return res_verbose_string; } -const nlohmann::json& rule_loader::result::as_json(const rules_contents_t& contents) -{ +const nlohmann::json& rule_loader::result::as_json(const rules_contents_t& contents) { nlohmann::json j; - if(!res_json.empty()) - { + if(!res_json.empty()) { return res_json; } @@ -543,23 +465,19 @@ const nlohmann::json& rule_loader::result::as_json(const rules_contents_t& conte j["successful"] = success; // Only print schema validation info if any validation was requested - if (!schema_validation_status.empty()) - { + if(!schema_validation_status.empty()) { bool schema_valid = schema_validation() == yaml_helper::validation_ok; j["schema_valid"] = schema_valid; j["schema_warnings"] = nlohmann::json::array(); - if (!schema_valid) - { - for (const auto &schema_warning : schema_validation_status) - { + if(!schema_valid) { + for(const auto& schema_warning : schema_validation_status) { j["schema_warnings"].push_back(schema_warning); } } } j["errors"] = nlohmann::json::array(); - for(auto &err : errors) - { + for(auto& err : errors) { nlohmann::json jerr; jerr["context"] = err.ctx.as_json(); @@ -573,8 +491,7 @@ const nlohmann::json& rule_loader::result::as_json(const rules_contents_t& conte } j["warnings"] = nlohmann::json::array(); - for(auto &warn : warnings) - { + for(auto& warn : warnings) { nlohmann::json jwarn; jwarn["context"] = warn.ctx.as_json(); @@ -591,59 +508,46 @@ const nlohmann::json& rule_loader::result::as_json(const rules_contents_t& conte return res_json; } -rule_loader::engine_version_info::engine_version_info(context &ctx) - : ctx(ctx) -{ -} +rule_loader::engine_version_info::engine_version_info(context& ctx): ctx(ctx) {} -rule_loader::plugin_version_info::plugin_version_info() - : ctx("no-filename-given") -{ -} +rule_loader::plugin_version_info::plugin_version_info(): ctx("no-filename-given") {} -rule_loader::plugin_version_info::plugin_version_info(context &ctx) - : ctx(ctx) -{ -} +rule_loader::plugin_version_info::plugin_version_info(context& ctx): ctx(ctx) {} -rule_loader::list_info::list_info(context &ctx) - : ctx(ctx), index(0), visibility(0) -{ -} +rule_loader::list_info::list_info(context& ctx): ctx(ctx), index(0), visibility(0) {} -rule_loader::macro_info::macro_info(context &ctx) - : ctx(ctx), cond_ctx(ctx), index(0), visibility(0) -{ -} +rule_loader::macro_info::macro_info(context& ctx): + ctx(ctx), + cond_ctx(ctx), + index(0), + visibility(0) {} -rule_loader::rule_exception_info::rule_exception_info(context &ctx) - : ctx(ctx) -{ -} +rule_loader::rule_exception_info::rule_exception_info(context& ctx): ctx(ctx) {} -rule_loader::rule_info::rule_info(context &ctx) - : ctx(ctx), cond_ctx(ctx), output_ctx(ctx), index(0), visibility(0), - unknown_source(false), priority(falco_common::PRIORITY_DEBUG), - enabled(true), warn_evttypes(true), skip_if_unknown_filter(false) -{ -} +rule_loader::rule_info::rule_info(context& ctx): + ctx(ctx), + cond_ctx(ctx), + output_ctx(ctx), + index(0), + visibility(0), + unknown_source(false), + priority(falco_common::PRIORITY_DEBUG), + enabled(true), + warn_evttypes(true), + skip_if_unknown_filter(false) {} -rule_loader::rule_update_info::rule_update_info(context &ctx) - : ctx(ctx), cond_ctx(ctx) -{ -} +rule_loader::rule_update_info::rule_update_info(context& ctx): ctx(ctx), cond_ctx(ctx) {} -rule_loader::rule_load_exception::rule_load_exception(falco::load_result::error_code ec, const std::string& msg, const context& ctx) - : ec(ec), msg(msg), ctx(ctx) -{ -} +rule_loader::rule_load_exception::rule_load_exception(falco::load_result::error_code ec, + const std::string& msg, + const context& ctx): + ec(ec), + msg(msg), + ctx(ctx) {} -rule_loader::rule_load_exception::~rule_load_exception() -{ -} +rule_loader::rule_load_exception::~rule_load_exception() {} -const char* rule_loader::rule_load_exception::what() const noexcept -{ +const char* rule_loader::rule_load_exception::what() const noexcept { // const + noexcept: can't use functions that change the object or throw return msg.c_str(); } diff --git a/userspace/engine/rule_loader.h b/userspace/engine/rule_loader.h index 5c45d78b40e..fe358f5a0d8 100644 --- a/userspace/engine/rule_loader.h +++ b/userspace/engine/rule_loader.h @@ -28,487 +28,473 @@ limitations under the License. #include "indexed_vector.h" #include -namespace rule_loader -{ - class context - { - public: - // The kinds of items that can be in rules - // content. These generally map to yaml items but a - // few are more specific (e.g. "within condition - // expression", "value for yaml node", etc.) - enum item_type { - VALUE_FOR = 0, - EXCEPTIONS, - EXCEPTION, - EXCEPTION_VALUES, - EXCEPTION_VALUE, - RULES_CONTENT, - RULES_CONTENT_ITEM, - REQUIRED_ENGINE_VERSION, - REQUIRED_PLUGIN_VERSIONS, - REQUIRED_PLUGIN_VERSIONS_ENTRY, - REQUIRED_PLUGIN_VERSIONS_ALTERNATIVE, - LIST, - LIST_ITEM, - MACRO, - MACRO_CONDITION, - RULE, - RULE_CONDITION, - CONDITION_EXPRESSION, - RULE_OUTPUT, - RULE_OUTPUT_EXPRESSION, - RULE_PRIORITY, - OVERRIDE, - EXTENSION_ITEM - }; - - static const std::string& item_type_as_string(enum item_type it); - - static const size_t default_snippet_width = 160; - - struct position - { - position() : pos(0), line(0), column(0) {}; - explicit position(const YAML::Mark& mark) : pos(mark.pos), line(mark.line), column(mark.column) {}; - ~position() = default; - position(position&&) = default; - position& operator = (position&&) = default; - position(const position&) = default; - position& operator = (const position&) = default; - - int pos; - int line; - int column; - }; - - struct location - { - location(): item_type(context::item_type::VALUE_FOR) {} - location( - const std::string& n, - const position& p, - context::item_type i, - const std::string& in): - name(n), pos(p), item_type(i), item_name(in) {} - location(location&&) = default; - location& operator = (location&&) = default; - location(const location&) = default; - location& operator = (const location&) = default; - - // A name for the content this location refers - // to. Will generally be a filename, can also - // refer to a rule/macro condition when the - // location points into a condition string. - std::string name; - - // The original location in the document - position pos; - - // The kind of item at this location - // (e.g. "list", "macro", "rule", "exception", etc) - context::item_type item_type; - - // The name of this item (e.g. "Write Below Etc", - // etc). - std::string item_name; - }; - - explicit context(const std::string& name); - context(const YAML::Node& item, - item_type item_type, - const std::string& item_name, - const context& parent); - context( - const YAML::Mark &mark, - const context& parent); - - // Build a context from a condition expression + - // parser position. This does not use the original - // yaml content because: - // - YAML block indicators will remove whitespace/newlines/wrapping - // from the YAML node containing the condition expression. - // - When compiling, the condition expression has expanded - // macro and list references with their values. - context(const libsinsp::filter::ast::pos_info& pos, - const std::string& condition, - const context& parent); - - virtual ~context() = default; - - context(context&&) = default; - context& operator = (context&&) = default; - context(const context&) = default; - context& operator = (const context&) = default; - - // Return the content name (generally filename) for - // this context - const std::string& name() const; - - // Return a snippet of the provided rules content - // corresponding to this context. - // Uses the provided rules_contents to look up the original - // rules content for a given location name. - // (If this context has a non-empty alt_content, it - // will be used to create the snippet, ignoring the - // provided rules_contents). - std::string snippet(const falco::load_result::rules_contents_t& rules_contents, size_t snippet_width = default_snippet_width) const; - - std::string as_string(); - nlohmann::json as_json(); - - private: - void init(const std::string& name, - const position& pos, - const item_type item_type, - const std::string& item_name, - const context& parent); - - // A chain of locations from the current item, its - // parent, possibly older ancestors. - std::vector m_locs; - - // If non-empty, this content will be used when - // creating snippets. Used for contexts involving - // condition expressions. - std::string alt_content; +namespace rule_loader { +class context { +public: + // The kinds of items that can be in rules + // content. These generally map to yaml items but a + // few are more specific (e.g. "within condition + // expression", "value for yaml node", etc.) + enum item_type { + VALUE_FOR = 0, + EXCEPTIONS, + EXCEPTION, + EXCEPTION_VALUES, + EXCEPTION_VALUE, + RULES_CONTENT, + RULES_CONTENT_ITEM, + REQUIRED_ENGINE_VERSION, + REQUIRED_PLUGIN_VERSIONS, + REQUIRED_PLUGIN_VERSIONS_ENTRY, + REQUIRED_PLUGIN_VERSIONS_ALTERNATIVE, + LIST, + LIST_ITEM, + MACRO, + MACRO_CONDITION, + RULE, + RULE_CONDITION, + CONDITION_EXPRESSION, + RULE_OUTPUT, + RULE_OUTPUT_EXPRESSION, + RULE_PRIORITY, + OVERRIDE, + EXTENSION_ITEM }; - struct warning - { - warning(): wc(falco::load_result::warning_code::LOAD_UNKNOWN_SOURCE), ctx("no-filename-given") {} - warning( - falco::load_result::warning_code w, - const std::string& m, - const context& c): wc(w), msg(m), ctx(c) {} - warning(warning&&) = default; - warning& operator = (warning&&) = default; - warning(const warning&) = default; - warning& operator = (const warning&) = default; - - falco::load_result::warning_code wc; - std::string msg; - context ctx; + static const std::string& item_type_as_string(enum item_type it); + + static const size_t default_snippet_width = 160; + + struct position { + position(): pos(0), line(0), column(0) {}; + explicit position(const YAML::Mark& mark): + pos(mark.pos), + line(mark.line), + column(mark.column) {}; + ~position() = default; + position(position&&) = default; + position& operator=(position&&) = default; + position(const position&) = default; + position& operator=(const position&) = default; + + int pos; + int line; + int column; }; - struct error - { - error(): ec(falco::load_result::error_code::LOAD_ERR_FILE_READ), ctx("no-filename-given") {} - error( - falco::load_result::error_code e, - const std::string& m, - const context& c): ec(e), msg(m), ctx(c) {} - error(error&&) = default; - error& operator = (error&&) = default; - error(const error&) = default; - error& operator = (const error&) = default; - - falco::load_result::error_code ec; - std::string msg; - context ctx; - }; + struct location { + location(): item_type(context::item_type::VALUE_FOR) {} + location(const std::string& n, + const position& p, + context::item_type i, + const std::string& in): + name(n), + pos(p), + item_type(i), + item_name(in) {} + location(location&&) = default; + location& operator=(location&&) = default; + location(const location&) = default; + location& operator=(const location&) = default; + + // A name for the content this location refers + // to. Will generally be a filename, can also + // refer to a rule/macro condition when the + // location points into a condition string. + std::string name; - class rule_load_exception : public std::exception - { - public: - rule_load_exception(falco::load_result::error_code ec, const std::string& msg, const context& ctx); - virtual ~rule_load_exception(); + // The original location in the document + position pos; - const char* what() const noexcept override; + // The kind of item at this location + // (e.g. "list", "macro", "rule", "exception", etc) + context::item_type item_type; - falco::load_result::error_code ec; - std::string msg; - context ctx; + // The name of this item (e.g. "Write Below Etc", + // etc). + std::string item_name; }; - /*! - \brief Contains the result of loading rule definitions - */ - class result : public falco::load_result - { - public: - explicit result(const std::string &name); - virtual ~result() = default; - result(result&&) = default; - result& operator = (result&&) = default; - result(const result&) = default; - result& operator = (const result&) = default; - - virtual bool successful() override; - virtual bool has_warnings() override; - - virtual const std::string& as_string(bool verbose, const falco::load_result::rules_contents_t& contents) override; - virtual const nlohmann::json& as_json(const falco::load_result::rules_contents_t& contents) override; - - void add_error(falco::load_result::error_code ec, - const std::string& msg, - const context& ctx); - - void add_warning(falco::load_result::warning_code ec, - const std::string& msg, - const context& ctx); - - void set_schema_validation_status(const std::vector& status); - std::string schema_validation(); - protected: - - const std::string& as_summary_string(); - const std::string& as_verbose_string(const falco::load_result::rules_contents_t& contents); - std::string name; - bool success; - std::vector schema_validation_status; + explicit context(const std::string& name); + context(const YAML::Node& item, + item_type item_type, + const std::string& item_name, + const context& parent); + context(const YAML::Mark& mark, const context& parent); + + // Build a context from a condition expression + + // parser position. This does not use the original + // yaml content because: + // - YAML block indicators will remove whitespace/newlines/wrapping + // from the YAML node containing the condition expression. + // - When compiling, the condition expression has expanded + // macro and list references with their values. + context(const libsinsp::filter::ast::pos_info& pos, + const std::string& condition, + const context& parent); + + virtual ~context() = default; + + context(context&&) = default; + context& operator=(context&&) = default; + context(const context&) = default; + context& operator=(const context&) = default; + + // Return the content name (generally filename) for + // this context + const std::string& name() const; + + // Return a snippet of the provided rules content + // corresponding to this context. + // Uses the provided rules_contents to look up the original + // rules content for a given location name. + // (If this context has a non-empty alt_content, it + // will be used to create the snippet, ignoring the + // provided rules_contents). + std::string snippet(const falco::load_result::rules_contents_t& rules_contents, + size_t snippet_width = default_snippet_width) const; + + std::string as_string(); + nlohmann::json as_json(); + +private: + void init(const std::string& name, + const position& pos, + const item_type item_type, + const std::string& item_name, + const context& parent); + + // A chain of locations from the current item, its + // parent, possibly older ancestors. + std::vector m_locs; + + // If non-empty, this content will be used when + // creating snippets. Used for contexts involving + // condition expressions. + std::string alt_content; +}; - std::vector errors; - std::vector warnings; +struct warning { + warning(): + wc(falco::load_result::warning_code::LOAD_UNKNOWN_SOURCE), + ctx("no-filename-given") {} + warning(falco::load_result::warning_code w, const std::string& m, const context& c): + wc(w), + msg(m), + ctx(c) {} + warning(warning&&) = default; + warning& operator=(warning&&) = default; + warning(const warning&) = default; + warning& operator=(const warning&) = default; + + falco::load_result::warning_code wc; + std::string msg; + context ctx; +}; - std::string res_summary_string; - std::string res_verbose_string; - nlohmann::json res_json; - }; +struct error { + error(): ec(falco::load_result::error_code::LOAD_ERR_FILE_READ), ctx("no-filename-given") {} + error(falco::load_result::error_code e, const std::string& m, const context& c): + ec(e), + msg(m), + ctx(c) {} + error(error&&) = default; + error& operator=(error&&) = default; + error(const error&) = default; + error& operator=(const error&) = default; + + falco::load_result::error_code ec; + std::string msg; + context ctx; +}; - struct extra_output_format_conf - { - std::string m_format; - std::string m_source; - std::set m_tags; - std::string m_rule; - bool m_replace_container_info; - }; +class rule_load_exception : public std::exception { +public: + rule_load_exception(falco::load_result::error_code ec, + const std::string& msg, + const context& ctx); + virtual ~rule_load_exception(); - struct extra_output_field_conf - { - std::string m_key; - std::string m_format; - std::string m_source; - std::set m_tags; - std::string m_rule; - bool m_raw; - }; + const char* what() const noexcept override; - /*! - \brief Contains the info required to load rule definitions - */ - struct configuration - { - explicit configuration( - const std::string& cont, - const indexed_vector& srcs, - const std::string& name) - : content(cont), sources(srcs), name(name), res(std::make_unique(name)) - { - } - - // inputs - const std::string& content; - const indexed_vector& sources; - std::string name; + falco::load_result::error_code ec; + std::string msg; + context ctx; +}; - std::vector extra_output_format; - std::vector extra_output_fields; +/*! + \brief Contains the result of loading rule definitions +*/ +class result : public falco::load_result { +public: + explicit result(const std::string& name); + virtual ~result() = default; + result(result&&) = default; + result& operator=(result&&) = default; + result(const result&) = default; + result& operator=(const result&) = default; + + virtual bool successful() override; + virtual bool has_warnings() override; + + virtual const std::string& as_string( + bool verbose, + const falco::load_result::rules_contents_t& contents) override; + virtual const nlohmann::json& as_json( + const falco::load_result::rules_contents_t& contents) override; + + void add_error(falco::load_result::error_code ec, const std::string& msg, const context& ctx); + + void add_warning(falco::load_result::warning_code ec, + const std::string& msg, + const context& ctx); + + void set_schema_validation_status(const std::vector& status); + std::string schema_validation(); + +protected: + const std::string& as_summary_string(); + const std::string& as_verbose_string(const falco::load_result::rules_contents_t& contents); + std::string name; + bool success; + std::vector schema_validation_status; + + std::vector errors; + std::vector warnings; + + std::string res_summary_string; + std::string res_verbose_string; + nlohmann::json res_json; +}; - // outputs - std::unique_ptr res; - }; +struct extra_output_format_conf { + std::string m_format; + std::string m_source; + std::set m_tags; + std::string m_rule; + bool m_replace_container_info; +}; - /*! - \brief Represents infos about an engine version requirement - */ - struct engine_version_info - { - engine_version_info() : ctx("no-filename-given"), version("0.0.0") { }; - explicit engine_version_info(context &ctx); - ~engine_version_info() = default; - engine_version_info(engine_version_info&&) = default; - engine_version_info& operator = (engine_version_info&&) = default; - engine_version_info(const engine_version_info&) = default; - engine_version_info& operator = (const engine_version_info&) = default; - - context ctx; - sinsp_version version; - }; +struct extra_output_field_conf { + std::string m_key; + std::string m_format; + std::string m_source; + std::set m_tags; + std::string m_rule; + bool m_raw; +}; - /*! - \brief Represents infos about a plugin version requirement - */ - struct plugin_version_info - { - struct requirement - { - requirement() = default; - requirement(const std::string& n, const std::string& v): - name(n), version(v) { } - requirement(requirement&&) = default; - requirement& operator = (requirement&&) = default; - requirement(const requirement&) = default; - requirement& operator = (const requirement&) = default; - - std::string name; - std::string version; - }; - - typedef std::vector requirement_alternatives; - - // This differs from the other _info structs by having - // a default constructor. This allows it to be used - // by falco_engine, which aliases the type. - plugin_version_info(); - explicit plugin_version_info(context &ctx); - ~plugin_version_info() = default; - plugin_version_info(plugin_version_info&&) = default; - plugin_version_info& operator = (plugin_version_info&&) = default; - plugin_version_info(const plugin_version_info&) = default; - plugin_version_info& operator = (const plugin_version_info&) = default; - - context ctx; - requirement_alternatives alternatives; - }; +/*! + \brief Contains the info required to load rule definitions +*/ +struct configuration { + explicit configuration(const std::string& cont, + const indexed_vector& srcs, + const std::string& name): + content(cont), + sources(srcs), + name(name), + res(std::make_unique(name)) {} + + // inputs + const std::string& content; + const indexed_vector& sources; + std::string name; + + std::vector extra_output_format; + std::vector extra_output_fields; + + // outputs + std::unique_ptr res; +}; - /*! - \brief Represents infos about a list - */ - struct list_info - { - explicit list_info(context &ctx); - ~list_info() = default; - list_info(list_info&&) = default; - list_info& operator = (list_info&&) = default; - list_info(const list_info&) = default; - list_info& operator = (const list_info&) = default; - - context ctx; - size_t index; - size_t visibility; - std::string name; - std::vector items; - }; +/*! + \brief Represents infos about an engine version requirement +*/ +struct engine_version_info { + engine_version_info(): ctx("no-filename-given"), version("0.0.0") {}; + explicit engine_version_info(context& ctx); + ~engine_version_info() = default; + engine_version_info(engine_version_info&&) = default; + engine_version_info& operator=(engine_version_info&&) = default; + engine_version_info(const engine_version_info&) = default; + engine_version_info& operator=(const engine_version_info&) = default; + + context ctx; + sinsp_version version; +}; - /*! - \brief Represents infos about a macro - */ - struct macro_info - { - explicit macro_info(context &ctx); - ~macro_info() = default; - macro_info(macro_info&&) = default; - macro_info& operator = (macro_info&&) = default; - macro_info(const macro_info&) = default; - macro_info& operator = (const macro_info&) = default; - - context ctx; - context cond_ctx; - size_t index; - size_t visibility; - std::string name; - std::string cond; - }; +/*! + \brief Represents infos about a plugin version requirement +*/ +struct plugin_version_info { + struct requirement { + requirement() = default; + requirement(const std::string& n, const std::string& v): name(n), version(v) {} + requirement(requirement&&) = default; + requirement& operator=(requirement&&) = default; + requirement(const requirement&) = default; + requirement& operator=(const requirement&) = default; - /*! - \brief Represents infos about a single rule exception - */ - struct rule_exception_info - { - explicit rule_exception_info(context &ctx); - ~rule_exception_info() = default; - rule_exception_info(rule_exception_info&&) = default; - rule_exception_info& operator = (rule_exception_info&&) = default; - rule_exception_info(const rule_exception_info&) = default; - rule_exception_info& operator = (const rule_exception_info&) = default; - - /*! - \brief This is necessary due to the dynamic-typed nature of - exceptions. Each of fields, comps, and values, can either be a - single value or a list of values. This is a simple hack to make - this easier to implement in C++, that is not non-dynamic-typed. - */ - struct entry { - entry(): is_list(false) {} - explicit entry(const std::string& i): is_list(false), item(i) {} - explicit entry(const std::vector& v): is_list(true), items(v) {} - entry(entry&&) = default; - entry& operator = (entry&&) = default; - entry(const entry&) = default; - entry& operator = (const entry&) = default; - - bool is_list; - std::string item; - std::vector items; - - inline bool is_valid() const - { - return (is_list && !items.empty()) - || (!is_list && !item.empty()); - } - }; - - context ctx; std::string name; - entry fields; - entry comps; - std::vector values; + std::string version; }; + typedef std::vector requirement_alternatives; + + // This differs from the other _info structs by having + // a default constructor. This allows it to be used + // by falco_engine, which aliases the type. + plugin_version_info(); + explicit plugin_version_info(context& ctx); + ~plugin_version_info() = default; + plugin_version_info(plugin_version_info&&) = default; + plugin_version_info& operator=(plugin_version_info&&) = default; + plugin_version_info(const plugin_version_info&) = default; + plugin_version_info& operator=(const plugin_version_info&) = default; + + context ctx; + requirement_alternatives alternatives; +}; + +/*! + \brief Represents infos about a list +*/ +struct list_info { + explicit list_info(context& ctx); + ~list_info() = default; + list_info(list_info&&) = default; + list_info& operator=(list_info&&) = default; + list_info(const list_info&) = default; + list_info& operator=(const list_info&) = default; + + context ctx; + size_t index; + size_t visibility; + std::string name; + std::vector items; +}; + +/*! + \brief Represents infos about a macro +*/ +struct macro_info { + explicit macro_info(context& ctx); + ~macro_info() = default; + macro_info(macro_info&&) = default; + macro_info& operator=(macro_info&&) = default; + macro_info(const macro_info&) = default; + macro_info& operator=(const macro_info&) = default; + + context ctx; + context cond_ctx; + size_t index; + size_t visibility; + std::string name; + std::string cond; +}; + +/*! + \brief Represents infos about a single rule exception +*/ +struct rule_exception_info { + explicit rule_exception_info(context& ctx); + ~rule_exception_info() = default; + rule_exception_info(rule_exception_info&&) = default; + rule_exception_info& operator=(rule_exception_info&&) = default; + rule_exception_info(const rule_exception_info&) = default; + rule_exception_info& operator=(const rule_exception_info&) = default; + /*! - \brief Represents infos about a rule + \brief This is necessary due to the dynamic-typed nature of + exceptions. Each of fields, comps, and values, can either be a + single value or a list of values. This is a simple hack to make + this easier to implement in C++, that is not non-dynamic-typed. */ - struct rule_info - { - explicit rule_info(context &ctx); - ~rule_info() = default; - rule_info(rule_info&&) = default; - rule_info& operator = (rule_info&&) = default; - rule_info(const rule_info&) = default; - rule_info& operator = (const rule_info&) = default; - - context ctx; - context cond_ctx; - context output_ctx; - size_t index; - size_t visibility; - bool unknown_source; - std::string name; - std::string cond; - std::string source; - std::string desc; - std::string output; - std::set tags; - std::vector exceptions; - falco_common::priority_type priority; - bool enabled; - bool warn_evttypes; - bool skip_if_unknown_filter; + struct entry { + entry(): is_list(false) {} + explicit entry(const std::string& i): is_list(false), item(i) {} + explicit entry(const std::vector& v): is_list(true), items(v) {} + entry(entry&&) = default; + entry& operator=(entry&&) = default; + entry(const entry&) = default; + entry& operator=(const entry&) = default; + + bool is_list; + std::string item; + std::vector items; + + inline bool is_valid() const { + return (is_list && !items.empty()) || (!is_list && !item.empty()); + } }; - /*! - \brief Represents infos about a rule update (append or replace) request - */ + context ctx; + std::string name; + entry fields; + entry comps; + std::vector values; +}; - struct rule_update_info - { - explicit rule_update_info(context &ctx); - ~rule_update_info() = default; - rule_update_info(rule_update_info&&) = default; - rule_update_info& operator = (rule_update_info&&) = default; - rule_update_info(const rule_update_info&) = default; - rule_update_info& operator = (const rule_update_info&) = default; - - bool has_any_value() - { - return cond.has_value() || output.has_value() || desc.has_value() || tags.has_value() || - exceptions.has_value() || priority.has_value() || enabled.has_value() || - warn_evttypes.has_value() || skip_if_unknown_filter.has_value(); - } +/*! + \brief Represents infos about a rule +*/ +struct rule_info { + explicit rule_info(context& ctx); + ~rule_info() = default; + rule_info(rule_info&&) = default; + rule_info& operator=(rule_info&&) = default; + rule_info(const rule_info&) = default; + rule_info& operator=(const rule_info&) = default; + + context ctx; + context cond_ctx; + context output_ctx; + size_t index; + size_t visibility; + bool unknown_source; + std::string name; + std::string cond; + std::string source; + std::string desc; + std::string output; + std::set tags; + std::vector exceptions; + falco_common::priority_type priority; + bool enabled; + bool warn_evttypes; + bool skip_if_unknown_filter; +}; - context ctx; - context cond_ctx; - std::string name; - std::optional cond; - std::optional output; - std::optional desc; - std::optional> tags; - std::optional> exceptions; - std::optional priority; - std::optional enabled; - std::optional warn_evttypes; - std::optional skip_if_unknown_filter; - }; +/*! + \brief Represents infos about a rule update (append or replace) request +*/ + +struct rule_update_info { + explicit rule_update_info(context& ctx); + ~rule_update_info() = default; + rule_update_info(rule_update_info&&) = default; + rule_update_info& operator=(rule_update_info&&) = default; + rule_update_info(const rule_update_info&) = default; + rule_update_info& operator=(const rule_update_info&) = default; + + bool has_any_value() { + return cond.has_value() || output.has_value() || desc.has_value() || tags.has_value() || + exceptions.has_value() || priority.has_value() || enabled.has_value() || + warn_evttypes.has_value() || skip_if_unknown_filter.has_value(); + } + + context ctx; + context cond_ctx; + std::string name; + std::optional cond; + std::optional output; + std::optional desc; + std::optional> tags; + std::optional> exceptions; + std::optional priority; + std::optional enabled; + std::optional warn_evttypes; + std::optional skip_if_unknown_filter; }; +}; // namespace rule_loader diff --git a/userspace/engine/rule_loader_collector.cpp b/userspace/engine/rule_loader_collector.cpp index 394e8a7982c..18103950db2 100644 --- a/userspace/engine/rule_loader_collector.cpp +++ b/userspace/engine/rule_loader_collector.cpp @@ -22,102 +22,86 @@ limitations under the License. #include "rule_loader_collector.h" #include "rule_loading_messages.h" -#define THROW(cond, err, ctx) { if ((cond)) { throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_VALIDATE, (err), (ctx)); } } - +#define THROW(cond, err, ctx) \ + { \ + if((cond)) { \ + throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_VALIDATE, \ + (err), \ + (ctx)); \ + } \ + } -static inline bool is_operator_defined(const std::string& op) -{ +static inline bool is_operator_defined(const std::string& op) { auto ops = libsinsp::filter::parser::supported_operators(); return find(ops.begin(), ops.end(), op) != ops.end(); } -template -static inline void define_info(indexed_vector& infos, T& info, uint32_t id) -{ +template +static inline void define_info(indexed_vector& infos, T& info, uint32_t id) { auto prev = infos.at(info.name); - if (prev) - { + if(prev) { info.index = prev->index; info.visibility = id; *prev = info; - } - else - { + } else { info.index = id; info.visibility = id; infos.insert(info, info.name); } } -template -static inline void append_info(T* prev, U& info, uint32_t id) -{ +template +static inline void append_info(T* prev, U& info, uint32_t id) { prev->visibility = id; } -template -static inline void replace_info(T* prev, U& info, uint32_t id) -{ +template +static inline void replace_info(T* prev, U& info, uint32_t id) { prev->visibility = id; } -static void validate_exception_info( - const falco_source* source, - rule_loader::rule_exception_info &ex) -{ - if (ex.fields.is_list) - { - if (!ex.comps.is_valid()) - { +static void validate_exception_info(const falco_source* source, + rule_loader::rule_exception_info& ex) { + if(ex.fields.is_list) { + if(!ex.comps.is_valid()) { ex.comps.is_list = true; - for (size_t i = 0; i < ex.fields.items.size(); i++) - { + for(size_t i = 0; i < ex.fields.items.size(); i++) { ex.comps.items.push_back(rule_loader::rule_exception_info::entry("=")); } } THROW(ex.fields.items.size() != ex.comps.items.size(), - "Fields and comps lists must have equal length", - ex.ctx); - for (const auto &v : ex.comps.items) - { + "Fields and comps lists must have equal length", + ex.ctx); + for(const auto& v : ex.comps.items) { THROW(!is_operator_defined(v.item), std::string("'") + v.item + "' is not a supported comparison operator", ex.ctx); } - if (source) - { - for (const auto &v : ex.fields.items) - { + if(source) { + for(const auto& v : ex.fields.items) { THROW(!source->is_valid_lhs_field(v.item), - std::string("'") + v.item + "' is not a supported filter field", - ex.ctx); + std::string("'") + v.item + "' is not a supported filter field", + ex.ctx); } } - } - else - { - if (!ex.comps.is_valid()) - { + } else { + if(!ex.comps.is_valid()) { ex.comps.is_list = false; ex.comps.item = "in"; } - THROW(ex.comps.is_list, - "Fields and comps must both be strings", - ex.ctx); + THROW(ex.comps.is_list, "Fields and comps must both be strings", ex.ctx); THROW((ex.comps.item != "in" && ex.comps.item != "pmatch" && ex.comps.item != "intersects"), "When fields is a single value, comps must be one of (in, pmatch, intersects)", ex.ctx); - if (source) - { + if(source) { THROW(!source->is_valid_lhs_field(ex.fields.item), - std::string("'") + ex.fields.item + "' is not a supported filter field", - ex.ctx); + std::string("'") + ex.fields.item + "' is not a supported filter field", + ex.ctx); } } } -void rule_loader::collector::clear() -{ +void rule_loader::collector::clear() { m_cur_index = 0; m_rule_infos.clear(); m_list_infos.clear(); @@ -125,84 +109,71 @@ void rule_loader::collector::clear() m_required_plugin_versions.clear(); } -const std::vector& rule_loader::collector::required_plugin_versions() const -{ +const std::vector& +rule_loader::collector::required_plugin_versions() const { return m_required_plugin_versions; } -const rule_loader::engine_version_info& rule_loader::collector::required_engine_version() const -{ +const rule_loader::engine_version_info& rule_loader::collector::required_engine_version() const { return m_required_engine_version; } -const indexed_vector& rule_loader::collector::lists() const -{ +const indexed_vector& rule_loader::collector::lists() const { return m_list_infos; } -const indexed_vector& rule_loader::collector::macros() const -{ +const indexed_vector& rule_loader::collector::macros() const { return m_macro_infos; } -const indexed_vector& rule_loader::collector::rules() const -{ +const indexed_vector& rule_loader::collector::rules() const { return m_rule_infos; } -void rule_loader::collector::define(configuration& cfg, engine_version_info& info) -{ +void rule_loader::collector::define(configuration& cfg, engine_version_info& info) { auto v = falco_engine::engine_version(); - THROW(!v.compatible_with(info.version), "Rules require engine version " - + info.version.as_string() + ", but engine version is " + v.as_string(), + THROW(!v.compatible_with(info.version), + "Rules require engine version " + info.version.as_string() + ", but engine version is " + + v.as_string(), info.ctx); - + // Store max required_engine_version - if(m_required_engine_version.version < info.version) - { + if(m_required_engine_version.version < info.version) { m_required_engine_version = info; } } -void rule_loader::collector::define(configuration& cfg, plugin_version_info& info) -{ +void rule_loader::collector::define(configuration& cfg, plugin_version_info& info) { std::unordered_set plugin_names; - for (const auto& req : info.alternatives) - { + for(const auto& req : info.alternatives) { sinsp_version plugin_version(req.version); THROW(!plugin_version.is_valid(), - "Invalid required version '" + req.version - + "' for plugin '" + req.name + "'", - info.ctx); + "Invalid required version '" + req.version + "' for plugin '" + req.name + "'", + info.ctx); THROW(plugin_names.find(req.name) != plugin_names.end(), - "Defined multiple alternative version requirements for plugin '" - + req.name + "'", - info.ctx); + "Defined multiple alternative version requirements for plugin '" + req.name + "'", + info.ctx); plugin_names.insert(req.name); } m_required_plugin_versions.push_back(info.alternatives); } -void rule_loader::collector::define(configuration& cfg, list_info& info) -{ +void rule_loader::collector::define(configuration& cfg, list_info& info) { define_info(m_list_infos, info, m_cur_index++); } -void rule_loader::collector::append(configuration& cfg, list_info& info) -{ +void rule_loader::collector::append(configuration& cfg, list_info& info) { auto prev = m_list_infos.at(info.name); THROW(!prev, ERROR_NO_PREVIOUS_LIST, info.ctx); prev->items.insert(prev->items.end(), info.items.begin(), info.items.end()); append_info(prev, info, m_cur_index++); } -void rule_loader::collector::define(configuration& cfg, macro_info& info) -{ +void rule_loader::collector::define(configuration& cfg, macro_info& info) { define_info(m_macro_infos, info, m_cur_index++); } -void rule_loader::collector::append(configuration& cfg, macro_info& info) -{ +void rule_loader::collector::append(configuration& cfg, macro_info& info) { auto prev = m_macro_infos.at(info.name); THROW(!prev, ERROR_NO_PREVIOUS_MACRO, info.ctx); prev->cond += " "; @@ -210,108 +181,92 @@ void rule_loader::collector::append(configuration& cfg, macro_info& info) append_info(prev, info, m_cur_index++); } -void rule_loader::collector::define(configuration& cfg, rule_info& info) -{ +void rule_loader::collector::define(configuration& cfg, rule_info& info) { const auto* prev = m_rule_infos.at(info.name); THROW(prev && prev->source != info.source, - "Rule has been re-defined with a different source", - info.ctx); + "Rule has been re-defined with a different source", + info.ctx); const auto* source = cfg.sources.at(info.source); - if (!source) - { + if(!source) { info.unknown_source = true; cfg.res->add_warning(falco::load_result::LOAD_UNKNOWN_SOURCE, - "Unknown source " + info.source + ", skipping", - info.ctx); + "Unknown source " + info.source + ", skipping", + info.ctx); } - for (auto &ex : info.exceptions) - { + for(auto& ex : info.exceptions) { THROW(!ex.fields.is_valid(), - "Rule exception item must have fields property with a list of fields", - ex.ctx); + "Rule exception item must have fields property with a list of fields", + ex.ctx); validate_exception_info(source, ex); } define_info(m_rule_infos, info, m_cur_index++); } -void rule_loader::collector::append(configuration& cfg, rule_update_info& info) -{ +void rule_loader::collector::append(configuration& cfg, rule_update_info& info) { auto prev = m_rule_infos.at(info.name); THROW(!prev, ERROR_NO_PREVIOUS_RULE_APPEND, info.ctx); THROW(!info.has_any_value(), - "Appended rule must have exceptions or condition property", - // "Appended rule must have at least one field that can be appended to", // TODO replace with this and update testing - info.ctx); + "Appended rule must have exceptions or condition property", + // "Appended rule must have at least one field that can be appended to", // TODO replace + // with this and update testing + info.ctx); // note: source can be nullptr in case we've collected a // rule for which the source is unknown const falco_source* source = nullptr; - if (!prev->unknown_source) - { + if(!prev->unknown_source) { // note: if the source is not unknown, this should not return nullptr source = cfg.sources.at(prev->source); - THROW(!source, - std::string("Unknown source ") + prev->source, - info.ctx); + THROW(!source, std::string("Unknown source ") + prev->source, info.ctx); } - if (info.cond.has_value() && !info.cond->empty()) - { + if(info.cond.has_value() && !info.cond->empty()) { prev->cond += " "; prev->cond += *info.cond; } - if (info.output.has_value() && !info.output->empty()) - { + if(info.output.has_value() && !info.output->empty()) { prev->output += " "; prev->output += *info.output; } - if (info.desc.has_value() && !info.desc->empty()) - { + if(info.desc.has_value() && !info.desc->empty()) { prev->desc += " "; prev->desc += *info.desc; } - if (info.tags.has_value()) - { - for (auto &tag: *info.tags) - { + if(info.tags.has_value()) { + for(auto& tag : *info.tags) { prev->tags.insert(tag); } } - if (info.exceptions.has_value()) - { - for (auto &ex : *info.exceptions) - { - auto prev_ex = find_if(prev->exceptions.begin(), prev->exceptions.end(), - [&ex](const rule_loader::rule_exception_info& i) - { return i.name == ex.name; }); - if (prev_ex == prev->exceptions.end()) - { + if(info.exceptions.has_value()) { + for(auto& ex : *info.exceptions) { + auto prev_ex = find_if( + prev->exceptions.begin(), + prev->exceptions.end(), + [&ex](const rule_loader::rule_exception_info& i) { return i.name == ex.name; }); + if(prev_ex == prev->exceptions.end()) { THROW(!ex.fields.is_valid(), - "Rule exception must have fields property with a list of fields", - ex.ctx); + "Rule exception must have fields property with a list of fields", + ex.ctx); THROW(ex.values.empty(), - "Rule exception must have values property with a list of values", - ex.ctx); + "Rule exception must have values property with a list of values", + ex.ctx); validate_exception_info(source, ex); prev->exceptions.push_back(ex); - } - else - { + } else { THROW(ex.fields.is_valid(), - "Can not append exception fields to existing exception, only values", - ex.ctx); + "Can not append exception fields to existing exception, only values", + ex.ctx); THROW(ex.comps.is_valid(), - "Can not append exception comps to existing exception, only values", - ex.ctx); - prev_ex->values.insert( - prev_ex->values.end(), ex.values.begin(), ex.values.end()); + "Can not append exception comps to existing exception, only values", + ex.ctx); + prev_ex->values.insert(prev_ex->values.end(), ex.values.begin(), ex.values.end()); } } } @@ -319,80 +274,64 @@ void rule_loader::collector::append(configuration& cfg, rule_update_info& info) append_info(prev, info, m_cur_index++); } -void rule_loader::collector::selective_replace(configuration& cfg, rule_update_info& info) -{ +void rule_loader::collector::selective_replace(configuration& cfg, rule_update_info& info) { auto prev = m_rule_infos.at(info.name); THROW(!prev, ERROR_NO_PREVIOUS_RULE_REPLACE, info.ctx); THROW(!info.has_any_value(), - "The rule must have at least one field that can be replaced", - info.ctx); + "The rule must have at least one field that can be replaced", + info.ctx); // note: source can be nullptr in case we've collected a // rule for which the source is unknown const falco_source* source = nullptr; - if (!prev->unknown_source) - { + if(!prev->unknown_source) { // note: if the source is not unknown, this should not return nullptr source = cfg.sources.at(prev->source); - THROW(!source, - std::string("Unknown source ") + prev->source, - info.ctx); + THROW(!source, std::string("Unknown source ") + prev->source, info.ctx); } - if (info.cond.has_value()) - { + if(info.cond.has_value()) { prev->cond = *info.cond; } - if (info.output.has_value()) - { + if(info.output.has_value()) { prev->output = *info.output; } - if (info.desc.has_value()) - { + if(info.desc.has_value()) { prev->desc = *info.desc; } - if (info.tags.has_value()) - { + if(info.tags.has_value()) { prev->tags = *info.tags; } - if (info.exceptions.has_value()) - { + if(info.exceptions.has_value()) { prev->exceptions = *info.exceptions; } - if (info.priority.has_value()) - { + if(info.priority.has_value()) { prev->priority = *info.priority; } - if (info.enabled.has_value()) - { + if(info.enabled.has_value()) { prev->enabled = *info.enabled; } - if (info.warn_evttypes.has_value()) - { + if(info.warn_evttypes.has_value()) { prev->warn_evttypes = *info.warn_evttypes; } - if (info.skip_if_unknown_filter.has_value()) - { + if(info.skip_if_unknown_filter.has_value()) { prev->skip_if_unknown_filter = *info.skip_if_unknown_filter; } replace_info(prev, info, m_cur_index++); } -void rule_loader::collector::enable(configuration& cfg, rule_info& info) -{ +void rule_loader::collector::enable(configuration& cfg, rule_info& info) { auto prev = m_rule_infos.at(info.name); - THROW(!prev, - "Rule has 'enabled' key but no rule by that name already exists", - info.ctx); + THROW(!prev, "Rule has 'enabled' key but no rule by that name already exists", info.ctx); prev->enabled = info.enabled; } diff --git a/userspace/engine/rule_loader_collector.h b/userspace/engine/rule_loader_collector.h index d95bb8e6966..6abf862961c 100644 --- a/userspace/engine/rule_loader_collector.h +++ b/userspace/engine/rule_loader_collector.h @@ -21,56 +21,55 @@ limitations under the License. #include "rule_loader.h" #include "indexed_vector.h" -namespace rule_loader -{ +namespace rule_loader { /*! - \brief Collector for the ruleset loader of the falco engine + \brief Collector for the ruleset loader of the falco engine */ -class collector -{ +class collector { public: - collector(): m_cur_index(0) { } + collector(): m_cur_index(0) {} virtual ~collector() = default; collector(collector&&) = default; - collector& operator = (collector&&) = default; + collector& operator=(collector&&) = default; collector(const collector&) = delete; - collector& operator = (const collector&) = delete; + collector& operator=(const collector&) = delete; /*! - \brief Erases all the internal state and definitions + \brief Erases all the internal state and definitions */ virtual void clear(); /*! - \brief Returns the set of all defined required plugin versions + \brief Returns the set of all defined required plugin versions */ - virtual const std::vector& required_plugin_versions() const; + virtual const std::vector& + required_plugin_versions() const; /*! - \brief Returns the required engine versions + \brief Returns the required engine versions */ virtual const engine_version_info& required_engine_version() const; /*! - \brief Returns the list of defined lists + \brief Returns the list of defined lists */ virtual const indexed_vector& lists() const; /*! - \brief Returns the list of defined macros + \brief Returns the list of defined macros */ virtual const indexed_vector& macros() const; /*! - \brief Returns the list of defined rules + \brief Returns the list of defined rules */ virtual const indexed_vector& rules() const; /*! - \brief Defines an info block. If a similar info block is found - in the internal state (e.g. another rule with same name), then - the previous definition gets overwritten + \brief Defines an info block. If a similar info block is found + in the internal state (e.g. another rule with same name), then + the previous definition gets overwritten */ virtual void define(configuration& cfg, engine_version_info& info); virtual void define(configuration& cfg, plugin_version_info& info); @@ -79,21 +78,21 @@ class collector virtual void define(configuration& cfg, rule_info& info); /*! - \brief Appends an info block to an existing one. An exception - is thrown if no existing definition can be matched with the appended - one + \brief Appends an info block to an existing one. An exception + is thrown if no existing definition can be matched with the appended + one */ virtual void append(configuration& cfg, list_info& info); virtual void append(configuration& cfg, macro_info& info); virtual void append(configuration& cfg, rule_update_info& info); /*! - \brief Updates the 'enabled' flag of an existing definition + \brief Updates the 'enabled' flag of an existing definition */ virtual void enable(configuration& cfg, rule_info& info); /*! - \brief Selectively replaces some fields of an existing definition + \brief Selectively replaces some fields of an existing definition */ virtual void selective_replace(configuration& cfg, rule_update_info& info); @@ -106,4 +105,4 @@ class collector engine_version_info m_required_engine_version; }; -}; // namespace rule_loader +}; // namespace rule_loader diff --git a/userspace/engine/rule_loader_compile_output.h b/userspace/engine/rule_loader_compile_output.h index 9a2873d2c0c..6aed9389a30 100644 --- a/userspace/engine/rule_loader_compile_output.h +++ b/userspace/engine/rule_loader_compile_output.h @@ -20,20 +20,17 @@ limitations under the License. #include "indexed_vector.h" #include "falco_rule.h" -namespace rule_loader -{ - struct compile_output - { - compile_output() = default; - virtual ~compile_output() = default; - compile_output(compile_output&&) = default; - compile_output& operator = (compile_output&&) = default; - compile_output(const compile_output&) = default; - compile_output& operator = (const compile_output&) = default; - - indexed_vector lists; - indexed_vector macros; - indexed_vector rules; - }; +namespace rule_loader { +struct compile_output { + compile_output() = default; + virtual ~compile_output() = default; + compile_output(compile_output&&) = default; + compile_output& operator=(compile_output&&) = default; + compile_output(const compile_output&) = default; + compile_output& operator=(const compile_output&) = default; + + indexed_vector lists; + indexed_vector macros; + indexed_vector rules; }; - +}; // namespace rule_loader diff --git a/userspace/engine/rule_loader_compiler.cpp b/userspace/engine/rule_loader_compiler.cpp index 14ad031b0a5..d56b964ba67 100644 --- a/userspace/engine/rule_loader_compiler.cpp +++ b/userspace/engine/rule_loader_compiler.cpp @@ -24,117 +24,96 @@ limitations under the License. #include "rule_loader_compiler.h" #include "filter_warning_resolver.h" -#define MAX_VISIBILITY ((uint32_t) -1) - -#define THROW(cond, err, ctx) { if ((cond)) { throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_VALIDATE, (err), (ctx)); } } +#define MAX_VISIBILITY ((uint32_t) - 1) + +#define THROW(cond, err, ctx) \ + { \ + if((cond)) { \ + throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_VALIDATE, \ + (err), \ + (ctx)); \ + } \ + } static std::string s_container_info_fmt = "%container.info"; -static std::string s_default_extra_fmt = "container_id=%container.id container_name=%container.name"; +static std::string s_default_extra_fmt = + "container_id=%container.id container_name=%container.name"; using namespace libsinsp::filter; // todo(jasondellaluce): this breaks string escaping in lists and exceptions -static void quote_item(std::string& e) -{ - if (e.find(" ") != std::string::npos && e[0] != '"' && e[0] != '\'') - { +static void quote_item(std::string& e) { + if(e.find(" ") != std::string::npos && e[0] != '"' && e[0] != '\'') { e = '"' + e + '"'; } } -static void paren_item(std::string& e) -{ - if(e[0] != '(') - { +static void paren_item(std::string& e) { + if(e[0] != '(') { e = '(' + e + ')'; } } -static inline bool is_operator_for_list(const std::string& op) -{ +static inline bool is_operator_for_list(const std::string& op) { auto ops = libsinsp::filter::parser::supported_operators(true); return find(ops.begin(), ops.end(), op) != ops.end(); } -static bool is_format_valid(const falco_source& source, std::string fmt, std::string& err) -{ - try - { +static bool is_format_valid(const falco_source& source, std::string fmt, std::string& err) { + try { std::shared_ptr formatter; formatter = source.formatter_factory->create_formatter(fmt); return true; - } - catch(std::exception &e) - { + } catch(std::exception& e) { err = e.what(); return false; } } static void build_rule_exception_infos( - const std::vector& exceptions, - std::set& exception_fields, - std::string& condition) -{ + const std::vector& exceptions, + std::set& exception_fields, + std::string& condition) { std::string tmp; condition = "(" + condition + ")"; - for (const auto &ex : exceptions) - { + for(const auto& ex : exceptions) { std::string icond; - if(!ex.fields.is_list) - { - for (const auto &val : ex.values) - { - THROW(val.is_list, - "Expected values array to contain a list of strings", - ex.ctx) - icond += icond.empty() - ? ("(" + ex.fields.item + " " - + ex.comps.item + " (") - : ", "; + if(!ex.fields.is_list) { + for(const auto& val : ex.values) { + THROW(val.is_list, "Expected values array to contain a list of strings", ex.ctx) + icond += icond.empty() ? ("(" + ex.fields.item + " " + ex.comps.item + " (") : ", "; exception_fields.insert(ex.fields.item); tmp = val.item; quote_item(tmp); icond += tmp; } icond += icond.empty() ? "" : "))"; - } - else - { + } else { icond = "("; - for (const auto &values : ex.values) - { + for(const auto& values : ex.values) { THROW(ex.fields.items.size() != values.items.size(), - "Fields and values lists must have equal length", - ex.ctx); + "Fields and values lists must have equal length", + ex.ctx); icond += icond == "(" ? "" : " or "; icond += "("; uint32_t k = 0; std::string istr; - for (const auto &field : ex.fields.items) - { + for(const auto& field : ex.fields.items) { icond += k == 0 ? "" : " and "; - if (values.items[k].is_list) - { + if(values.items[k].is_list) { istr = "("; - for (const auto &v : values.items[k].items) - { + for(const auto& v : values.items[k].items) { tmp = v.item; quote_item(tmp); istr += istr == "(" ? "" : ", "; istr += tmp; } istr += ")"; - } - else - { + } else { istr = values.items[k].item; - if(is_operator_for_list(ex.comps.items[k].item)) - { + if(is_operator_for_list(ex.comps.items[k].item)) { paren_item(istr); - } - else - { + } else { quote_item(istr); } } @@ -146,8 +125,7 @@ static void build_rule_exception_infos( icond += ")"; } icond += ")"; - if (icond == "()") - { + if(icond == "()") { icond = ""; } } @@ -155,31 +133,26 @@ static void build_rule_exception_infos( } } -static inline rule_loader::list_info* list_info_from_name( - const rule_loader::collector& c, const std::string& name) -{ +static inline rule_loader::list_info* list_info_from_name(const rule_loader::collector& c, + const std::string& name) { auto ret = c.lists().at(name); - if (!ret) - { + if(!ret) { throw falco_exception("can't find internal list info at name: " + name); } return ret; } -static inline rule_loader::macro_info* macro_info_from_name( - const rule_loader::collector& c, const std::string& name) -{ +static inline rule_loader::macro_info* macro_info_from_name(const rule_loader::collector& c, + const std::string& name) { auto ret = c.macros().at(name); - if (!ret) - { + if(!ret) { throw falco_exception("can't find internal macro info at name: " + name); } return ret; } // todo(jasondellaluce): this breaks string escaping in lists -static bool resolve_list(std::string& cnd, const falco_list& list) -{ +static bool resolve_list(std::string& cnd, const falco_list& list) { static std::string blanks = " \t\n\r"; static std::string delims = blanks + "(),="; std::string tmp; @@ -187,31 +160,23 @@ static bool resolve_list(std::string& cnd, const falco_list& list) size_t start, end; bool used = false; start = cnd.find(list.name); - while (start != std::string::npos) - { + while(start != std::string::npos) { // the characters surrounding the name must // be delims of beginning/end of string end = start + list.name.length(); - if ((start == 0 || delims.find(cnd[start - 1]) != std::string::npos) - && (end >= cnd.length() || delims.find(cnd[end]) != std::string::npos)) - { + if((start == 0 || delims.find(cnd[start - 1]) != std::string::npos) && + (end >= cnd.length() || delims.find(cnd[end]) != std::string::npos)) { // shift pointers to consume all whitespaces - while (start > 0 - && blanks.find(cnd[start - 1]) != std::string::npos) - { + while(start > 0 && blanks.find(cnd[start - 1]) != std::string::npos) { start--; } - while (end < cnd.length() - && blanks.find(cnd[end]) != std::string::npos) - { + while(end < cnd.length() && blanks.find(cnd[end]) != std::string::npos) { end++; } // create substitution string by concatenating all values std::string sub = ""; - for (const auto &v : list.items) - { - if (!sub.empty()) - { + for(const auto& v : list.items) { + if(!sub.empty()) { sub += ", "; } tmp = v; @@ -220,26 +185,20 @@ static bool resolve_list(std::string& cnd, const falco_list& list) } // if substituted list is empty, we need to // remove a comma from the left or the right - if (sub.empty()) - { - if (start > 0 && cnd[start - 1] == ',') - { + if(sub.empty()) { + if(start > 0 && cnd[start - 1] == ',') { start--; - } - else if (end < cnd.length() && cnd[end] == ',') - { + } else if(end < cnd.length() && cnd[end] == ',') { end++; } } // compose new string with substitution new_cnd = ""; - if (start > 0) - { + if(start > 0) { new_cnd += cnd.substr(0, start) + " "; } new_cnd += sub + " "; - if (end <= cnd.length()) - { + if(end <= cnd.length()) { new_cnd += cnd.substr(end); } cnd = new_cnd; @@ -251,20 +210,16 @@ static bool resolve_list(std::string& cnd, const falco_list& list) return used; } -static inline void resolve_macros( - filter_macro_resolver& macro_resolver, - const indexed_vector& infos, - indexed_vector& macros, - std::shared_ptr& ast, - const std::string& condition, - uint32_t visibility, - const rule_loader::context &ctx) -{ +static inline void resolve_macros(filter_macro_resolver& macro_resolver, + const indexed_vector& infos, + indexed_vector& macros, + std::shared_ptr& ast, + const std::string& condition, + uint32_t visibility, + const rule_loader::context& ctx) { macro_resolver.clear(); - for (const auto &m : infos) - { - if (m.index < visibility) - { + for(const auto& m : infos) { + if(m.index < visibility) { auto macro = macros.at(m.name); macro_resolver.set_macro(m.name, macro->condition); } @@ -274,79 +229,61 @@ static inline void resolve_macros( // Note: only complaining about the first error or unknown macro const auto& errors_macros = macro_resolver.get_errors(); const auto& unresolved_macros = macro_resolver.get_unknown_macros(); - if(!errors_macros.empty() || !unresolved_macros.empty()) - { - auto errpos = !errors_macros.empty() - ? errors_macros.begin()->second - : unresolved_macros.begin()->second; + if(!errors_macros.empty() || !unresolved_macros.empty()) { + auto errpos = !errors_macros.empty() ? errors_macros.begin()->second + : unresolved_macros.begin()->second; std::string errmsg = !errors_macros.empty() - ? errors_macros.begin()->first - : ("Undefined macro '" + unresolved_macros.begin()->first + "' used in filter."); + ? errors_macros.begin()->first + : ("Undefined macro '" + unresolved_macros.begin()->first + + "' used in filter."); const rule_loader::context cond_ctx(errpos, condition, ctx); THROW(true, errmsg, cond_ctx); } - for (const auto &it : macro_resolver.get_resolved_macros()) - { + for(const auto& it : macro_resolver.get_resolved_macros()) { macros.at(it.first)->used = true; } } // note: there is no visibility order between filter conditions and lists -static std::shared_ptr parse_condition( - std::string condition, - indexed_vector& lists, - const rule_loader::context &ctx) -{ - for (auto &l : lists) - { - if (resolve_list(condition, l)) - { +static std::shared_ptr parse_condition(std::string condition, + indexed_vector& lists, + const rule_loader::context& ctx) { + for(auto& l : lists) { + if(resolve_list(condition, l)) { l.used = true; } } libsinsp::filter::parser p(condition); p.set_max_depth(1000); - try - { + try { std::shared_ptr res_ptr(p.parse()); return res_ptr; - } - catch (const sinsp_exception& e) - { + } catch(const sinsp_exception& e) { rule_loader::context parsectx(p.get_pos(), condition, ctx); - throw rule_loader::rule_load_exception( - falco::load_result::LOAD_ERR_COMPILE_CONDITION, - e.what(), - parsectx); + throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_COMPILE_CONDITION, + e.what(), + parsectx); } } -void rule_loader::compiler::compile_list_infos( - configuration& cfg, - const collector& col, - indexed_vector& out) const -{ +void rule_loader::compiler::compile_list_infos(configuration& cfg, + const collector& col, + indexed_vector& out) const { std::list used_names; falco_list infos; - for (const auto &list : col.lists()) - { + for(const auto& list : col.lists()) { infos.name = list.name; infos.items.clear(); - for (const auto &item : list.items) - { + for(const auto& item : list.items) { const auto ref = col.lists().at(item); - if (ref && ref->index < list.visibility) - { + if(ref && ref->index < list.visibility) { used_names.push_back(ref->name); - for (const auto &val : ref->items) - { + for(const auto& val : ref->items) { infos.items.push_back(val); } - } - else - { + } else { infos.items.push_back(item); } } @@ -354,21 +291,17 @@ void rule_loader::compiler::compile_list_infos( auto list_id = out.insert(infos, infos.name); out.at(list_id)->id = list_id; } - for (const auto &name : used_names) - { + for(const auto& name : used_names) { out.at(name)->used = true; } } // note: there is a visibility ordering between macros -void rule_loader::compiler::compile_macros_infos( - configuration& cfg, - const collector& col, - indexed_vector& lists, - indexed_vector& out) const -{ - for (const auto &m : col.macros()) - { +void rule_loader::compiler::compile_macros_infos(configuration& cfg, + const collector& col, + indexed_vector& lists, + indexed_vector& out) const { + for(const auto& m : col.macros()) { falco_macro entry; entry.name = m.name; entry.condition = parse_condition(m.cond, lists, m.cond_ctx); @@ -378,44 +311,50 @@ void rule_loader::compiler::compile_macros_infos( } filter_macro_resolver macro_resolver; - for (auto &m : out) - { + for(auto& m : out) { const auto* info = macro_info_from_name(col, m.name); - resolve_macros(macro_resolver, col.macros(), out, m.condition, info->cond, info->visibility, info->ctx); + resolve_macros(macro_resolver, + col.macros(), + out, + m.condition, + info->cond, + info->visibility, + info->ctx); } } -static bool err_is_unknown_type_or_field(const std::string& err) -{ - return err.find("nonexistent field") != std::string::npos - || err.find("invalid formatting token") != std::string::npos - || err.find("unknown event type") != std::string::npos; +static bool err_is_unknown_type_or_field(const std::string& err) { + return err.find("nonexistent field") != std::string::npos || + err.find("invalid formatting token") != std::string::npos || + err.find("unknown event type") != std::string::npos; } -bool rule_loader::compiler::compile_condition( - configuration& cfg, - filter_macro_resolver& macro_resolver, - indexed_vector& lists, - const indexed_vector& macros, - const std::string& condition, - std::shared_ptr filter_factory, - const rule_loader::context& cond_ctx, - const rule_loader::context& parent_ctx, - bool allow_unknown_fields, - indexed_vector& macros_out, - std::shared_ptr& ast_out, - std::shared_ptr& filter_out) const -{ +bool rule_loader::compiler::compile_condition(configuration& cfg, + filter_macro_resolver& macro_resolver, + indexed_vector& lists, + const indexed_vector& macros, + const std::string& condition, + std::shared_ptr filter_factory, + const rule_loader::context& cond_ctx, + const rule_loader::context& parent_ctx, + bool allow_unknown_fields, + indexed_vector& macros_out, + std::shared_ptr& ast_out, + std::shared_ptr& filter_out) const { std::set warn_codes; filter_warning_resolver warn_resolver; ast_out = parse_condition(condition, lists, cond_ctx); - resolve_macros(macro_resolver, macros, macros_out, ast_out, condition, MAX_VISIBILITY, parent_ctx); + resolve_macros(macro_resolver, + macros, + macros_out, + ast_out, + condition, + MAX_VISIBILITY, + parent_ctx); // check for warnings in the filtering condition - if(warn_resolver.run(ast_out.get(), warn_codes)) - { - for(const auto& w : warn_codes) - { + if(warn_resolver.run(ast_out.get(), warn_codes)) { + for(const auto& w : warn_codes) { cfg.res->add_warning(w, "", parent_ctx); } } @@ -423,134 +362,105 @@ bool rule_loader::compiler::compile_condition( // validate the rule's condition: we compile it into a sinsp filter // on-the-fly and we throw an exception with details on failure sinsp_filter_compiler compiler(filter_factory, ast_out.get()); - try - { + try { filter_out = compiler.compile(); - } - catch(const sinsp_exception& e) - { + } catch(const sinsp_exception& e) { // skip the rule silently if skip_if_unknown_filter is true and // we encountered some specific kind of errors std::string err = e.what(); rule_loader::context ctx(compiler.get_pos(), condition, cond_ctx); - if(err_is_unknown_type_or_field(err) && allow_unknown_fields) - { - cfg.res->add_warning( - falco::load_result::load_result::LOAD_UNKNOWN_FILTER, - err, - ctx); + if(err_is_unknown_type_or_field(err) && allow_unknown_fields) { + cfg.res->add_warning(falco::load_result::load_result::LOAD_UNKNOWN_FILTER, err, ctx); return false; } throw rule_loader::rule_load_exception( - falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION, - err, - ctx); + falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION, + err, + ctx); } - for (const auto &w : compiler.get_warnings()) - { + for(const auto& w : compiler.get_warnings()) { rule_loader::context ctx(w.pos, condition, cond_ctx); - cfg.res->add_warning( - falco::load_result::load_result::LOAD_COMPILE_CONDITION, - w.msg, - ctx); + cfg.res->add_warning(falco::load_result::load_result::LOAD_COMPILE_CONDITION, w.msg, ctx); } return true; } -void rule_loader::compiler::compile_rule_infos( - configuration& cfg, - const collector& col, - indexed_vector& lists, - indexed_vector& macros, - indexed_vector& out) const -{ +void rule_loader::compiler::compile_rule_infos(configuration& cfg, + const collector& col, + indexed_vector& lists, + indexed_vector& macros, + indexed_vector& out) const { std::string err, condition; filter_macro_resolver macro_resolver; - for(const auto& r : col.rules()) - { + for(const auto& r : col.rules()) { // skip the rule if it has an unknown source - if (r.unknown_source) - { + if(r.unknown_source) { continue; } // note: this should not be nullptr if the source is not unknown auto source = cfg.sources.at(r.source); - THROW(!source, - std::string("Unknown source at compile-time") + r.source, - r.ctx); + THROW(!source, std::string("Unknown source at compile-time") + r.source, r.ctx); // build filter AST by parsing the condition, building exceptions, // and resolving lists and macros falco_rule rule; condition = r.cond; - if (!r.exceptions.empty()) - { - build_rule_exception_infos( - r.exceptions, rule.exception_fields, condition); + if(!r.exceptions.empty()) { + build_rule_exception_infos(r.exceptions, rule.exception_fields, condition); } // build rule output message rule.output = r.output; - for (auto& extra : cfg.extra_output_format) - { - if (extra.m_source != "" && r.source != extra.m_source) - { + for(auto& extra : cfg.extra_output_format) { + if(extra.m_source != "" && r.source != extra.m_source) { continue; } - if (!std::includes(r.tags.begin(), r.tags.end(), - extra.m_tags.begin(), extra.m_tags.end())) - { + if(!std::includes(r.tags.begin(), + r.tags.end(), + extra.m_tags.begin(), + extra.m_tags.end())) { continue; } - if (extra.m_rule != "" && r.name != extra.m_rule) - { + if(extra.m_rule != "" && r.name != extra.m_rule) { continue; } - if (extra.m_replace_container_info) - { - if (rule.output.find(s_container_info_fmt) != std::string::npos) - { + if(extra.m_replace_container_info) { + if(rule.output.find(s_container_info_fmt) != std::string::npos) { rule.output = replace(rule.output, s_container_info_fmt, extra.m_format); - } - else - { + } else { rule.output = rule.output + " " + extra.m_format; } - } else - { + } else { rule.output = rule.output + " " + extra.m_format; } } - if (rule.output.find(s_container_info_fmt) != std::string::npos) - { + if(rule.output.find(s_container_info_fmt) != std::string::npos) { rule.output = replace(rule.output, s_container_info_fmt, s_default_extra_fmt); } // build extra output fields if required - for (auto const& extra : cfg.extra_output_fields) - { - if (extra.m_source != "" && r.source != extra.m_source) - { + for(auto const& extra : cfg.extra_output_fields) { + if(extra.m_source != "" && r.source != extra.m_source) { continue; } - if (!std::includes(r.tags.begin(), r.tags.end(), - extra.m_tags.begin(), extra.m_tags.end())) - { + if(!std::includes(r.tags.begin(), + r.tags.end(), + extra.m_tags.begin(), + extra.m_tags.end())) { continue; } - if (extra.m_rule != "" && r.name != extra.m_rule) - { + if(extra.m_rule != "" && r.name != extra.m_rule) { continue; } @@ -558,62 +468,52 @@ void rule_loader::compiler::compile_rule_infos( } // validate the rule's output - if(!is_format_valid(*cfg.sources.at(r.source), rule.output, err)) - { + if(!is_format_valid(*cfg.sources.at(r.source), rule.output, err)) { // skip the rule silently if skip_if_unknown_filter is true and // we encountered some specific kind of errors - if (err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter) - { - cfg.res->add_warning( - falco::load_result::load_result::LOAD_UNKNOWN_FILTER, - err, - r.output_ctx); + if(err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter) { + cfg.res->add_warning(falco::load_result::load_result::LOAD_UNKNOWN_FILTER, + err, + r.output_ctx); continue; } - throw rule_load_exception( - falco::load_result::load_result::LOAD_ERR_COMPILE_OUTPUT, - err, - r.output_ctx); + throw rule_load_exception(falco::load_result::load_result::LOAD_ERR_COMPILE_OUTPUT, + err, + r.output_ctx); } // validate the rule's extra fields if any - for (auto const& ef : rule.extra_output_fields) - { - if(!is_format_valid(*cfg.sources.at(r.source), ef.second.first, err)) - { - throw rule_load_exception( - falco::load_result::load_result::LOAD_ERR_COMPILE_OUTPUT, - err, - r.output_ctx); + for(auto const& ef : rule.extra_output_fields) { + if(!is_format_valid(*cfg.sources.at(r.source), ef.second.first, err)) { + throw rule_load_exception(falco::load_result::load_result::LOAD_ERR_COMPILE_OUTPUT, + err, + r.output_ctx); } } - if (!compile_condition(cfg, - macro_resolver, - lists, - col.macros(), - condition, - cfg.sources.at(r.source)->filter_factory, - r.cond_ctx, - r.ctx, - r.skip_if_unknown_filter, - macros, - rule.condition, - rule.filter)) - { + if(!compile_condition(cfg, + macro_resolver, + lists, + col.macros(), + condition, + cfg.sources.at(r.source)->filter_factory, + r.cond_ctx, + r.ctx, + r.skip_if_unknown_filter, + macros, + rule.condition, + rule.filter)) { continue; } // populate set of event types and emit an special warning - if(r.source == falco_common::syscall_source) - { + if(r.source == falco_common::syscall_source) { auto evttypes = libsinsp::filter::ast::ppm_event_codes(rule.condition.get()); - if ((evttypes.empty() || evttypes.size() > 100) && r.warn_evttypes) - { - cfg.res->add_warning( - falco::load_result::load_result::LOAD_NO_EVTTYPE, - "Rule matches too many evt.type values. This has a significant performance penalty.", - r.ctx); + if((evttypes.empty() || evttypes.size() > 100) && r.warn_evttypes) { + cfg.res->add_warning(falco::load_result::load_result::LOAD_NO_EVTTYPE, + "Rule matches too many evt.type values. This has a " + "significant performance penalty.", + r.ctx); } } @@ -628,48 +528,36 @@ void rule_loader::compiler::compile_rule_infos( } } -std::unique_ptr rule_loader::compiler::new_compile_output() -{ +std::unique_ptr rule_loader::compiler::new_compile_output() { return std::make_unique(); } -void rule_loader::compiler::compile( - configuration& cfg, - const collector& col, - compile_output& out) const -{ +void rule_loader::compiler::compile(configuration& cfg, + const collector& col, + compile_output& out) const { // expand all lists, macros, and rules - try - { + try { compile_list_infos(cfg, col, out.lists); compile_macros_infos(cfg, col, out.lists, out.macros); compile_rule_infos(cfg, col, out.lists, out.macros, out.rules); - } - catch(rule_load_exception &e) - { + } catch(rule_load_exception& e) { cfg.res->add_error(e.ec, e.msg, e.ctx); return; } // print info on any dangling lists or macros that were not used anywhere - for (const auto &m : out.macros) - { - if (!m.used) - { - cfg.res->add_warning( - falco::load_result::load_result::LOAD_UNUSED_MACRO, - "Macro not referred to by any other rule/macro", - macro_info_from_name(col, m.name)->ctx); + for(const auto& m : out.macros) { + if(!m.used) { + cfg.res->add_warning(falco::load_result::load_result::LOAD_UNUSED_MACRO, + "Macro not referred to by any other rule/macro", + macro_info_from_name(col, m.name)->ctx); } } - for (const auto &l : out.lists) - { - if (!l.used) - { - cfg.res->add_warning( - falco::load_result::LOAD_UNUSED_LIST, - "List not referred to by any other rule/macro", - list_info_from_name(col, l.name)->ctx); + for(const auto& l : out.lists) { + if(!l.used) { + cfg.res->add_warning(falco::load_result::LOAD_UNUSED_LIST, + "List not referred to by any other rule/macro", + list_info_from_name(col, l.name)->ctx); } } } diff --git a/userspace/engine/rule_loader_compiler.h b/userspace/engine/rule_loader_compiler.h index 63072aa8dc9..830eeda49d9 100644 --- a/userspace/engine/rule_loader_compiler.h +++ b/userspace/engine/rule_loader_compiler.h @@ -24,75 +24,66 @@ limitations under the License. #include "indexed_vector.h" #include "falco_rule.h" -namespace rule_loader -{ +namespace rule_loader { /*! - \brief Compiler for the ruleset loader of the falco engine + \brief Compiler for the ruleset loader of the falco engine */ -class compiler -{ +class compiler { public: compiler() = default; virtual ~compiler() = default; compiler(compiler&&) = default; - compiler& operator = (compiler&&) = default; + compiler& operator=(compiler&&) = default; compiler(const compiler&) = default; - compiler& operator = (const compiler&) = default; + compiler& operator=(const compiler&) = default; // Return a new result object, suitable for passing to // compile(). - virtual std::unique_ptr new_compile_output(); + virtual std::unique_ptr new_compile_output(); /*! - \brief Compiles a list of falco rules + \brief Compiles a list of falco rules */ - virtual void compile( - configuration& cfg, - const collector& col, - compile_output& out) const; + virtual void compile(configuration& cfg, const collector& col, compile_output& out) const; + protected: - /*! - \brief Compile a single condition expression, - including expanding macro and list references. + /*! + \brief Compile a single condition expression, + including expanding macro and list references. - returns true if the condition could be compiled, and sets - ast_out/filter_out with the compiled filter + ast. Returns false if - the condition could not be compiled and should be skipped. - */ - bool compile_condition( - configuration& cfg, - filter_macro_resolver& macro_resolver, - indexed_vector& lists, - const indexed_vector& macros, - const std::string& condition, - std::shared_ptr filter_factory, - const rule_loader::context& cond_ctx, - const rule_loader::context& parent_ctx, - bool allow_unknown_fields, - indexed_vector& macros_out, - std::shared_ptr& ast_out, - std::shared_ptr& filter_out) const; + returns true if the condition could be compiled, and sets + ast_out/filter_out with the compiled filter + ast. Returns false if + the condition could not be compiled and should be skipped. + */ + bool compile_condition(configuration& cfg, + filter_macro_resolver& macro_resolver, + indexed_vector& lists, + const indexed_vector& macros, + const std::string& condition, + std::shared_ptr filter_factory, + const rule_loader::context& cond_ctx, + const rule_loader::context& parent_ctx, + bool allow_unknown_fields, + indexed_vector& macros_out, + std::shared_ptr& ast_out, + std::shared_ptr& filter_out) const; private: - void compile_list_infos( - configuration& cfg, - const collector& col, - indexed_vector& out) const; + void compile_list_infos(configuration& cfg, + const collector& col, + indexed_vector& out) const; - void compile_macros_infos( - configuration& cfg, - const collector& col, - indexed_vector& lists, - indexed_vector& out) const; + void compile_macros_infos(configuration& cfg, + const collector& col, + indexed_vector& lists, + indexed_vector& out) const; - void compile_rule_infos( - configuration& cfg, - const collector& col, - indexed_vector& lists, - indexed_vector& macros, - indexed_vector& out) const; + void compile_rule_infos(configuration& cfg, + const collector& col, + indexed_vector& lists, + indexed_vector& macros, + indexed_vector& out) const; }; -}; // namespace rule_loader - +}; // namespace rule_loader diff --git a/userspace/engine/rule_loader_reader.cpp b/userspace/engine/rule_loader_reader.cpp index 50f045f9c63..146eed35400 100644 --- a/userspace/engine/rule_loader_reader.cpp +++ b/userspace/engine/rule_loader_reader.cpp @@ -28,26 +28,35 @@ limitations under the License. #include -#define THROW(cond, err, ctx) { if ((cond)) { throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_YAML_VALIDATE, (err), (ctx)); } } +#define THROW(cond, err, ctx) \ + { \ + if((cond)) { \ + throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_YAML_VALIDATE, \ + (err), \ + (ctx)); \ + } \ + } // Sinsp Filter grammar tokens taken from "libsinsp/filter/parser.h" // These regular expressions are used here to check for invalid macro/list names // todo(mrgian): to avoid code duplication we can move regex definitions in libsinsp/filter/parser.h // and include it here instead of redefining them. #define RGX_IDENTIFIER "([a-zA-Z]+[a-zA-Z0-9_]*)" -#define RGX_BARESTR "([^()\"'[:space:]=,]+)" +#define RGX_BARESTR "([^()\"'[:space:]=,]+)" static re2::RE2 s_rgx_identifier(RGX_IDENTIFIER, re2::RE2::POSIX); static re2::RE2 s_rgx_barestr(RGX_BARESTR, re2::RE2::POSIX); // Don't call this directly, call decode_val/decode_optional_val instead. -template -static void decode_val_generic(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx, bool optional) -{ +template +static void decode_val_generic(const YAML::Node& item, + const char* key, + T& out, + const rule_loader::context& ctx, + bool optional) { const YAML::Node& val = item[key]; - if(!val.IsDefined() && optional) - { + if(!val.IsDefined() && optional) { return; } @@ -61,46 +70,63 @@ static void decode_val_generic(const YAML::Node& item, const char *key, T& out, THROW(!YAML::convert::decode(val, out), "Can't decode YAML scalar value", valctx); } -template -static void decode_val_generic(const YAML::Node& item, const char *key, std::optional& out, const rule_loader::context& ctx, bool optional) -{ +template +static void decode_val_generic(const YAML::Node& item, + const char* key, + std::optional& out, + const rule_loader::context& ctx, + bool optional) { T decoded; decode_val_generic(item, key, decoded, ctx, optional); out = decoded; } -template -void rule_loader::reader::decode_val(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx) -{ +template +void rule_loader::reader::decode_val(const YAML::Node& item, + const char* key, + T& out, + const rule_loader::context& ctx) { bool optional = false; decode_val_generic(item, key, out, ctx, optional); } -template void rule_loader::reader::decode_val(const YAML::Node& item, const char *key, std::string& out, const rule_loader::context& ctx); +template void rule_loader::reader::decode_val(const YAML::Node& item, + const char* key, + std::string& out, + const rule_loader::context& ctx); -template -void rule_loader::reader::decode_optional_val(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx) -{ +template +void rule_loader::reader::decode_optional_val(const YAML::Node& item, + const char* key, + T& out, + const rule_loader::context& ctx) { bool optional = true; decode_val_generic(item, key, out, ctx, optional); } -template void rule_loader::reader::decode_optional_val(const YAML::Node& item, const char *key, std::string& out, const rule_loader::context& ctx); +template void rule_loader::reader::decode_optional_val( + const YAML::Node& item, + const char* key, + std::string& out, + const rule_loader::context& ctx); -template void rule_loader::reader::decode_optional_val(const YAML::Node& item, const char *key, bool& out, const rule_loader::context& ctx); +template void rule_loader::reader::decode_optional_val(const YAML::Node& item, + const char* key, + bool& out, + const rule_loader::context& ctx); // Don't call this directly, call decode_items/decode_tags instead. -template -static void decode_seq(const YAML::Node& item, const char *key, - std::function inserter, - const rule_loader::context &ctx, bool optional) -{ +template +static void decode_seq(const YAML::Node& item, + const char* key, + std::function inserter, + const rule_loader::context& ctx, + bool optional) { const YAML::Node& val = item[key]; - if(!val.IsDefined() && optional) - { + if(!val.IsDefined() && optional) { return; } @@ -110,8 +136,7 @@ static void decode_seq(const YAML::Node& item, const char *key, THROW(!val.IsSequence(), "Value is not a sequence", valctx); T value; - for(const YAML::Node& v : val) - { + for(const YAML::Node& v : val) { rule_loader::context ictx(v, rule_loader::context::LIST_ITEM, "", valctx); THROW(!v.IsScalar(), "sequence value is not scalar", ictx); THROW(!YAML::convert::decode(v, value), "Can't decode YAML sequence value", ictx); @@ -119,91 +144,91 @@ static void decode_seq(const YAML::Node& item, const char *key, } } -template -static void decode_items(const YAML::Node& item, std::vector& out, - const rule_loader::context& ctx) -{ +template +static void decode_items(const YAML::Node& item, + std::vector& out, + const rule_loader::context& ctx) { bool optional = false; - std::function inserter = [&out] (T value) { - out.push_back(value); - }; + std::function inserter = [&out](T value) { out.push_back(value); }; decode_seq(item, "items", inserter, ctx, optional); } -template -static void decode_tags(const YAML::Node& item, std::set& out, - const rule_loader::context& ctx) -{ +template +static void decode_tags(const YAML::Node& item, std::set& out, const rule_loader::context& ctx) { bool optional = true; - std::function inserter = [&out] (T value) { - out.insert(value); - }; + std::function inserter = [&out](T value) { out.insert(value); }; decode_seq(item, "tags", inserter, ctx, optional); } -template -static void decode_tags(const YAML::Node& item, std::optional>& out, - const rule_loader::context& ctx) -{ +template +static void decode_tags(const YAML::Node& item, + std::optional>& out, + const rule_loader::context& ctx) { std::set decoded; decode_tags(item, decoded, ctx); out = decoded; } static void decode_overrides(const YAML::Node& item, - std::set& overridable_append, - std::set& overridable_replace, - std::set& out_append, - std::set& out_replace, - const rule_loader::context& ctx) -{ + std::set& overridable_append, + std::set& overridable_replace, + std::set& out_append, + std::set& out_replace, + const rule_loader::context& ctx) { const YAML::Node& val = item["override"]; - if(!val.IsDefined()) - { + if(!val.IsDefined()) { return; } rule_loader::context overridectx(item, rule_loader::context::OVERRIDE, "", ctx); - for(YAML::const_iterator it=val.begin();it!=val.end();++it) - { + for(YAML::const_iterator it = val.begin(); it != val.end(); ++it) { std::string key = it->first.as(); std::string operation = it->second.as(); - bool is_overridable_append = overridable_append.find(it->first.as()) != overridable_append.end(); - bool is_overridable_replace = overridable_replace.find(it->first.as()) != overridable_replace.end(); - - if (operation == "append") - { - rule_loader::context keyctx(it->first, rule_loader::context::OVERRIDE, key, overridectx); - THROW(!is_overridable_append, std::string("Key '") + key + std::string("' cannot be appended to, use 'replace' instead"), keyctx); + bool is_overridable_append = + overridable_append.find(it->first.as()) != overridable_append.end(); + bool is_overridable_replace = + overridable_replace.find(it->first.as()) != overridable_replace.end(); + + if(operation == "append") { + rule_loader::context keyctx(it->first, + rule_loader::context::OVERRIDE, + key, + overridectx); + THROW(!is_overridable_append, + std::string("Key '") + key + + std::string("' cannot be appended to, use 'replace' instead"), + keyctx); out_append.insert(key); - } - else if (operation == "replace") - { - rule_loader::context keyctx(it->first, rule_loader::context::OVERRIDE, key, overridectx); - THROW(!is_overridable_replace, std::string("Key '") + key + std::string("' cannot be replaced"), keyctx); + } else if(operation == "replace") { + rule_loader::context keyctx(it->first, + rule_loader::context::OVERRIDE, + key, + overridectx); + THROW(!is_overridable_replace, + std::string("Key '") + key + std::string("' cannot be replaced"), + keyctx); out_replace.insert(key); - } - else - { - rule_loader::context operationctx(it->second, rule_loader::context::VALUE_FOR, key, overridectx); + } else { + rule_loader::context operationctx(it->second, + rule_loader::context::VALUE_FOR, + key, + overridectx); std::stringstream err_ss; err_ss << "Invalid override operation for key '" << key << "': '" << operation << "'. " - << "Allowed values are: "; - if (is_overridable_append) - { + << "Allowed values are: "; + if(is_overridable_append) { err_ss << "append "; } - if (is_overridable_replace) - { + if(is_overridable_replace) { err_ss << "replace "; } @@ -213,35 +238,34 @@ static void decode_overrides(const YAML::Node& item, } // Don't call this directly, call decode_exception_{fields,comps,values} instead -static void decode_exception_info_entry( - const YAML::Node& item, - const char *key, - rule_loader::rule_exception_info::entry& out, - const rule_loader::context& ctx, - bool optional) -{ +static void decode_exception_info_entry(const YAML::Node& item, + const char* key, + rule_loader::rule_exception_info::entry& out, + const rule_loader::context& ctx, + bool optional) { const YAML::Node& val = (key == NULL ? item : item[key]); - if(!val.IsDefined() && optional) - { + if(!val.IsDefined() && optional) { return; } THROW(!val.IsDefined(), std::string("Item has no mapping for key '") + key + "'", ctx); - rule_loader::context valctx(val, rule_loader::context::VALUE_FOR, (key == NULL ? "" : key), ctx); + rule_loader::context valctx(val, + rule_loader::context::VALUE_FOR, + (key == NULL ? "" : key), + ctx); - if (val.IsScalar()) - { + if(val.IsScalar()) { THROW(val.Scalar().empty(), "Value must be non-empty", valctx); out.is_list = false; - THROW(!YAML::convert::decode(val, out.item), "Could not decode scalar value", valctx); + THROW(!YAML::convert::decode(val, out.item), + "Could not decode scalar value", + valctx); } - if (val.IsSequence()) - { + if(val.IsSequence()) { out.is_list = true; - for(const YAML::Node& v : val) - { + for(const YAML::Node& v : val) { rule_loader::rule_exception_info::entry tmp; rule_loader::context lctx(v, rule_loader::context::EXCEPTION, "", valctx); @@ -253,48 +277,39 @@ static void decode_exception_info_entry( } } -static void decode_exception_fields( - const YAML::Node& item, - rule_loader::rule_exception_info::entry& out, - const rule_loader::context& ctx, - bool optional) -{ +static void decode_exception_fields(const YAML::Node& item, + rule_loader::rule_exception_info::entry& out, + const rule_loader::context& ctx, + bool optional) { decode_exception_info_entry(item, "fields", out, ctx, optional); } -static void decode_exception_comps( - const YAML::Node& item, - rule_loader::rule_exception_info::entry& out, - const rule_loader::context& ctx) -{ +static void decode_exception_comps(const YAML::Node& item, + rule_loader::rule_exception_info::entry& out, + const rule_loader::context& ctx) { bool optional = true; decode_exception_info_entry(item, "comps", out, ctx, optional); } -static void decode_exception_values( - const YAML::Node& item, - rule_loader::rule_exception_info::entry& out, - const rule_loader::context& ctx) -{ +static void decode_exception_values(const YAML::Node& item, + rule_loader::rule_exception_info::entry& out, + const rule_loader::context& ctx) { bool optional = false; decode_exception_info_entry(item, NULL, out, ctx, optional); } -static void read_rule_exceptions( - rule_loader::configuration& cfg, - const YAML::Node& item, - std::vector& exceptions, - const rule_loader::context& parent, - bool append) -{ +static void read_rule_exceptions(rule_loader::configuration& cfg, + const YAML::Node& item, + std::vector& exceptions, + const rule_loader::context& parent, + bool append) { const YAML::Node& exs = item["exceptions"]; // No exceptions property, or an exceptions property with // nothing in it, are allowed - if(!exs.IsDefined() || exs.IsNull()) - { + if(!exs.IsDefined() || exs.IsNull()) { return; } @@ -302,8 +317,7 @@ static void read_rule_exceptions( THROW(!exs.IsSequence(), "Rule exceptions must be a sequence", exes_ctx); - for (auto &ex : exs) - { + for(auto& ex : exs) { // Make a temp context to verify simple properties // about the exception. std::string name; @@ -318,11 +332,12 @@ static void read_rule_exceptions( v_ex.name = name; // Check if an exception with the same name has already been defined - for (auto &exception : exceptions) - { - if(v_ex.name == exception.name) - { - cfg.res->add_warning(falco::load_result::LOAD_EXCEPTION_NAME_NOT_UNIQUE, "Multiple definitions of exception '" + v_ex.name + "' in the same rule", ex_ctx); + for(auto& exception : exceptions) { + if(v_ex.name == exception.name) { + cfg.res->add_warning( + falco::load_result::LOAD_EXCEPTION_NAME_NOT_UNIQUE, + "Multiple definitions of exception '" + v_ex.name + "' in the same rule", + ex_ctx); } } @@ -332,128 +347,142 @@ static void read_rule_exceptions( decode_exception_fields(ex, v_ex.fields, ex_ctx, append); decode_exception_comps(ex, v_ex.comps, ex_ctx); const YAML::Node& exvals = ex["values"]; - if (exvals.IsDefined()) - { - rule_loader::context vals_ctx(exvals, rule_loader::context::EXCEPTION_VALUES, "", ex_ctx); - THROW(!exvals.IsSequence(), - "Rule exception values must be a sequence", vals_ctx); - for (const auto &val : exvals) - { + if(exvals.IsDefined()) { + rule_loader::context vals_ctx(exvals, + rule_loader::context::EXCEPTION_VALUES, + "", + ex_ctx); + THROW(!exvals.IsSequence(), "Rule exception values must be a sequence", vals_ctx); + for(const auto& val : exvals) { rule_loader::context vctx(val, rule_loader::context::EXCEPTION_VALUE, "", vals_ctx); rule_loader::rule_exception_info::entry v_ex_val; decode_exception_values(val, v_ex_val, vctx); v_ex.values.push_back(v_ex_val); } - } - else if (append) - { - cfg.res->add_warning(falco::load_result::LOAD_APPEND_NO_VALUES, "Overriding/appending exception with no values", ex_ctx); + } else if(append) { + cfg.res->add_warning(falco::load_result::LOAD_APPEND_NO_VALUES, + "Overriding/appending exception with no values", + ex_ctx); } exceptions.push_back(v_ex); } } static void read_rule_exceptions( - rule_loader::configuration& cfg, - const YAML::Node& item, - std::optional>& exceptions, - const rule_loader::context& parent, - bool append) -{ + rule_loader::configuration& cfg, + const YAML::Node& item, + std::optional>& exceptions, + const rule_loader::context& parent, + bool append) { std::vector decoded; read_rule_exceptions(cfg, item, decoded, parent, append); exceptions = decoded; } -inline static bool check_update_expected(std::set& expected_keys, const std::set& overrides, const std::string& override_type, const std::string& key, const rule_loader::context& ctx) -{ - if (overrides.find(key) == overrides.end()) - { +inline static bool check_update_expected(std::set& expected_keys, + const std::set& overrides, + const std::string& override_type, + const std::string& key, + const rule_loader::context& ctx) { + if(overrides.find(key) == overrides.end()) { return false; } - + THROW(expected_keys.find(key) == expected_keys.end(), - std::string("An ") + override_type + " override for '" + key + "' was specified but '" + key + "' is not defined", ctx); + std::string("An ") + override_type + " override for '" + key + "' was specified but '" + + key + "' is not defined", + ctx); expected_keys.erase(key); return true; } -void rule_loader::reader::read_item( - rule_loader::configuration& cfg, - rule_loader::collector& collector, - const YAML::Node& item, - const rule_loader::context& parent) -{ +void rule_loader::reader::read_item(rule_loader::configuration& cfg, + rule_loader::collector& collector, + const YAML::Node& item, + const rule_loader::context& parent) { { rule_loader::context tmp(item, rule_loader::context::RULES_CONTENT_ITEM, "", parent); - THROW(!item.IsMap(), "Unexpected element type. " - "Each element should be a yaml associative array.", tmp); + THROW(!item.IsMap(), + "Unexpected element type. " + "Each element should be a yaml associative array.", + tmp); } - if (item["required_engine_version"].IsDefined()) - { + if(item["required_engine_version"].IsDefined()) { rule_loader::context ctx(item, rule_loader::context::REQUIRED_ENGINE_VERSION, "", parent); rule_loader::engine_version_info v(ctx); - - try - { + + try { // Convert convert to an uint (more restrictive than converting to a string) uint32_t ver; decode_val(item, "required_engine_version", ver, ctx); // Build proper semver representation v.version = rule_loader::reader::get_implicit_engine_version(ver); - } - catch(std::exception& e) - { + } catch(std::exception& e) { // Convert to string std::string ver; decode_val(item, "required_engine_version", ver, ctx); v.version = sinsp_version(ver); - THROW(!v.version.is_valid(), "Unable to parse engine version '" + ver + "' as a semver string. Expected \"x.y.z\" semver format.", ctx); + THROW(!v.version.is_valid(), + "Unable to parse engine version '" + ver + + "' as a semver string. Expected \"x.y.z\" semver format.", + ctx); } collector.define(cfg, v); - } - else if(item["required_plugin_versions"].IsDefined()) - { + } else if(item["required_plugin_versions"].IsDefined()) { const YAML::Node& req_plugin_vers = item["required_plugin_versions"]; - rule_loader::context ctx(req_plugin_vers, rule_loader::context::REQUIRED_PLUGIN_VERSIONS, "", parent); + rule_loader::context ctx(req_plugin_vers, + rule_loader::context::REQUIRED_PLUGIN_VERSIONS, + "", + parent); THROW(!req_plugin_vers.IsSequence(), - "Value of required_plugin_versions must be a sequence", - ctx); + "Value of required_plugin_versions must be a sequence", + ctx); - for(const YAML::Node& plugin : req_plugin_vers) - { + for(const YAML::Node& plugin : req_plugin_vers) { rule_loader::plugin_version_info::requirement r; // Use a temp context until we can get a name - rule_loader::context tmp(plugin, rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ENTRY, "", ctx); + rule_loader::context tmp(plugin, + rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ENTRY, + "", + ctx); THROW(!plugin.IsMap(), "Plugin version must be a mapping", tmp); decode_val(plugin, "name", r.name, tmp); - rule_loader::context pctx(plugin, rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ENTRY, r.name, ctx); + rule_loader::context pctx(plugin, + rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ENTRY, + r.name, + ctx); rule_loader::plugin_version_info v(pctx); decode_val(plugin, "version", r.version, pctx); v.alternatives.push_back(r); const YAML::Node& alternatives = plugin["alternatives"]; - if(alternatives.IsDefined()) - { + if(alternatives.IsDefined()) { THROW(!alternatives.IsSequence(), - "Value of plugin version alternatives must be a sequence", - pctx); - for (const auto &req : alternatives) - { - tmp = rule_loader::context(req, rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ALTERNATIVE, "", pctx); + "Value of plugin version alternatives must be a sequence", + pctx); + for(const auto& req : alternatives) { + tmp = rule_loader::context( + req, + rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ALTERNATIVE, + "", + pctx); THROW(!req.IsMap(), "Plugin version alternative must be a mapping", tmp); decode_val(req, "name", r.name, tmp); - tmp = rule_loader::context(req, rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ALTERNATIVE, r.name, pctx); + tmp = rule_loader::context( + req, + rule_loader::context::REQUIRED_PLUGIN_VERSIONS_ALTERNATIVE, + r.name, + pctx); decode_val(req, "version", r.version, tmp); v.alternatives.push_back(r); } @@ -461,9 +490,7 @@ void rule_loader::reader::read_item( collector.define(cfg, v); } - } - else if(item["list"].IsDefined()) - { + } else if(item["list"].IsDefined()) { std::string name; // Using tmp context until name is decoded rule_loader::context tmp(item, rule_loader::context::LIST, "", parent); @@ -472,9 +499,11 @@ void rule_loader::reader::read_item( rule_loader::context ctx(item, rule_loader::context::LIST, name, parent); bool invalid_name = !re2::RE2::FullMatch(name, s_rgx_barestr); - if(invalid_name) - { - cfg.res->add_warning(falco::load_result::LOAD_INVALID_LIST_NAME, "List has an invalid name. List names should match a regular expression: " RGX_BARESTR, ctx); + if(invalid_name) { + cfg.res->add_warning(falco::load_result::LOAD_INVALID_LIST_NAME, + "List has an invalid name. List names should match a regular " + "expression: " RGX_BARESTR, + ctx); } rule_loader::list_info v(ctx); @@ -484,33 +513,27 @@ void rule_loader::reader::read_item( decode_items(item, v.items, ctx); decode_optional_val(item, "append", append, ctx); - if(append) - { + if(append) { cfg.res->add_warning(falco::load_result::LOAD_DEPRECATED_ITEM, WARNING_APPEND, ctx); } std::set override_append, override_replace; - std::set overridable {"items"}; + std::set overridable{"items"}; decode_overrides(item, overridable, overridable, override_append, override_replace, ctx); bool has_overrides = !override_append.empty() || !override_replace.empty(); THROW(append && has_overrides, ERROR_OVERRIDE_APPEND, ctx); - // Since a list only has items, if we have chosen to append them we can append the entire object - // otherwise we just want to redefine the list. + // Since a list only has items, if we have chosen to append them we can append the entire + // object otherwise we just want to redefine the list. append |= override_append.find("items") != override_append.end(); - if(append) - { + if(append) { collector.append(cfg, v); - } - else - { + } else { collector.define(cfg, v); } - } - else if(item["macro"].IsDefined()) - { + } else if(item["macro"].IsDefined()) { std::string name; // Using tmp context until name is decoded rule_loader::context tmp(item, rule_loader::context::MACRO, "", parent); @@ -519,9 +542,11 @@ void rule_loader::reader::read_item( rule_loader::context ctx(item, rule_loader::context::MACRO, name, parent); bool invalid_name = !re2::RE2::FullMatch(name, s_rgx_identifier); - if(invalid_name) - { - cfg.res->add_warning(falco::load_result::LOAD_INVALID_MACRO_NAME, "Macro has an invalid name. Macro names should match a regular expression: " RGX_IDENTIFIER, ctx); + if(invalid_name) { + cfg.res->add_warning(falco::load_result::LOAD_INVALID_MACRO_NAME, + "Macro has an invalid name. Macro names should match a regular " + "expression: " RGX_IDENTIFIER, + ctx); } rule_loader::macro_info v(ctx); @@ -531,36 +556,33 @@ void rule_loader::reader::read_item( decode_val(item, "condition", v.cond, ctx); // Now set the proper context for the condition now that we know it exists - v.cond_ctx = rule_loader::context(item["condition"], rule_loader::context::MACRO_CONDITION, "", ctx); + v.cond_ctx = rule_loader::context(item["condition"], + rule_loader::context::MACRO_CONDITION, + "", + ctx); decode_optional_val(item, "append", append, ctx); - if(append) - { + if(append) { cfg.res->add_warning(falco::load_result::LOAD_DEPRECATED_ITEM, WARNING_APPEND, ctx); } std::set override_append, override_replace; - std::set overridable {"condition"}; + std::set overridable{"condition"}; decode_overrides(item, overridable, overridable, override_append, override_replace, ctx); bool has_overrides = !override_append.empty() || !override_replace.empty(); THROW((append && has_overrides), ERROR_OVERRIDE_APPEND, ctx); - // Since a macro only has a condition, if we have chosen to append to it we can append the entire object - // otherwise we just want to redefine the macro. + // Since a macro only has a condition, if we have chosen to append to it we can append the + // entire object otherwise we just want to redefine the macro. append |= override_append.find("condition") != override_append.end(); - if(append) - { + if(append) { collector.append(cfg, v); - } - else - { + } else { collector.define(cfg, v); } - } - else if(item["rule"].IsDefined()) - { + } else if(item["rule"].IsDefined()) { std::string name; // Using tmp context until name is decoded @@ -571,126 +593,161 @@ void rule_loader::reader::read_item( bool has_append_flag = false; decode_optional_val(item, "append", has_append_flag, ctx); - if(has_append_flag) - { + if(has_append_flag) { cfg.res->add_warning(falco::load_result::LOAD_DEPRECATED_ITEM, WARNING_APPEND, ctx); } std::set override_append, override_replace; - std::set overridable_append {"condition", "output", "desc", "tags", "exceptions"}; - std::set overridable_replace { - "condition", "output", "desc", "priority", "tags", "exceptions", "enabled", "warn_evttypes", "skip-if-unknown-filter"}; - decode_overrides(item, overridable_append, overridable_replace, override_append, override_replace, ctx); + std::set overridable_append{"condition", + "output", + "desc", + "tags", + "exceptions"}; + std::set overridable_replace{"condition", + "output", + "desc", + "priority", + "tags", + "exceptions", + "enabled", + "warn_evttypes", + "skip-if-unknown-filter"}; + decode_overrides(item, + overridable_append, + overridable_replace, + override_append, + override_replace, + ctx); bool has_overrides_append = !override_append.empty(); bool has_overrides_replace = !override_replace.empty(); bool has_overrides = has_overrides_append || has_overrides_replace; THROW((has_append_flag && has_overrides), ERROR_OVERRIDE_APPEND, ctx); - if(has_overrides) - { + if(has_overrides) { std::set expected_keys; - for (auto& key : overridable_append) - { - if (item[key].IsDefined()) - { + for(auto& key : overridable_append) { + if(item[key].IsDefined()) { expected_keys.insert(key); } } - for (auto& key : overridable_replace) - { - if (item[key].IsDefined()) - { + for(auto& key : overridable_replace) { + if(item[key].IsDefined()) { expected_keys.insert(key); } } // expected_keys is (appendable U replaceable) ^ (defined) - - if (has_overrides_append) - { + + if(has_overrides_append) { rule_loader::rule_update_info v(ctx); v.name = name; - if (check_update_expected(expected_keys, override_append, "append", "condition", ctx)) - { + if(check_update_expected(expected_keys, + override_append, + "append", + "condition", + ctx)) { decode_val(item, "condition", v.cond, ctx); } - if (check_update_expected(expected_keys, override_append, "append", "exceptions", ctx)) - { + if(check_update_expected(expected_keys, + override_append, + "append", + "exceptions", + ctx)) { read_rule_exceptions(cfg, item, v.exceptions, ctx, true); } - if (check_update_expected(expected_keys, override_append, "append", "output", ctx)) - { + if(check_update_expected(expected_keys, override_append, "append", "output", ctx)) { decode_val(item, "output", v.output, ctx); } - if (check_update_expected(expected_keys, override_append, "append", "desc", ctx)) - { + if(check_update_expected(expected_keys, override_append, "append", "desc", ctx)) { decode_val(item, "desc", v.desc, ctx); } - if (check_update_expected(expected_keys, override_append, "append", "tags", ctx)) - { + if(check_update_expected(expected_keys, override_append, "append", "tags", ctx)) { decode_tags(item, v.tags, ctx); } - + collector.append(cfg, v); } - if (has_overrides_replace) - { + if(has_overrides_replace) { rule_loader::rule_update_info v(ctx); v.name = name; - if (check_update_expected(expected_keys, override_replace, "replace", "condition", ctx)) - { + if(check_update_expected(expected_keys, + override_replace, + "replace", + "condition", + ctx)) { decode_val(item, "condition", v.cond, ctx); } - if (check_update_expected(expected_keys, override_replace, "replace", "exceptions", ctx)) - { + if(check_update_expected(expected_keys, + override_replace, + "replace", + "exceptions", + ctx)) { read_rule_exceptions(cfg, item, v.exceptions, ctx, false); } - if (check_update_expected(expected_keys, override_replace, "replace", "output", ctx)) - { + if(check_update_expected(expected_keys, + override_replace, + "replace", + "output", + ctx)) { decode_val(item, "output", v.output, ctx); } - if (check_update_expected(expected_keys, override_replace, "replace", "desc", ctx)) - { + if(check_update_expected(expected_keys, override_replace, "replace", "desc", ctx)) { decode_val(item, "desc", v.desc, ctx); } - if (check_update_expected(expected_keys, override_replace, "replace", "tags", ctx)) - { + if(check_update_expected(expected_keys, override_replace, "replace", "tags", ctx)) { decode_tags(item, v.tags, ctx); } - if (check_update_expected(expected_keys, override_replace, "replace", "priority", ctx)) - { + if(check_update_expected(expected_keys, + override_replace, + "replace", + "priority", + ctx)) { std::string priority; decode_val(item, "priority", priority, ctx); - rule_loader::context prictx(item["priority"], rule_loader::context::RULE_PRIORITY, "", ctx); + rule_loader::context prictx(item["priority"], + rule_loader::context::RULE_PRIORITY, + "", + ctx); falco_common::priority_type parsed_priority; - THROW(!falco_common::parse_priority(priority, parsed_priority), "Invalid priority", prictx); + THROW(!falco_common::parse_priority(priority, parsed_priority), + "Invalid priority", + prictx); v.priority = parsed_priority; } - if (check_update_expected(expected_keys, override_replace, "replace", "enabled", ctx)) - { + if(check_update_expected(expected_keys, + override_replace, + "replace", + "enabled", + ctx)) { decode_val(item, "enabled", v.enabled, ctx); } - if (check_update_expected(expected_keys, override_replace, "replace", "warn_evttypes", ctx)) - { + if(check_update_expected(expected_keys, + override_replace, + "replace", + "warn_evttypes", + ctx)) { decode_val(item, "warn_evttypes", v.warn_evttypes, ctx); } - if (check_update_expected(expected_keys, override_replace, "replace", "skip-if-unknown-filter", ctx)) - { + if(check_update_expected(expected_keys, + override_replace, + "replace", + "skip-if-unknown-filter", + ctx)) { decode_val(item, "skip-if-unknown-filter", v.skip_if_unknown_filter, ctx); } @@ -698,36 +755,36 @@ void rule_loader::reader::read_item( } // if any expected key has not been defined throw an error - for (const auto &key : expected_keys) { + for(const auto& key : expected_keys) { rule_loader::context keyctx(item[key], rule_loader::context::OVERRIDE, key, ctx); - THROW(true, "Unexpected key '" + key + "': no corresponding entry under 'override' is defined.", keyctx); + THROW(true, + "Unexpected key '" + key + + "': no corresponding entry under 'override' is defined.", + keyctx); } - } - else if(has_append_flag) - { + } else if(has_append_flag) { rule_loader::rule_update_info v(ctx); v.name = name; - if(item["condition"].IsDefined()) - { - v.cond_ctx = rule_loader::context(item["condition"], rule_loader::context::RULE_CONDITION, "", ctx); + if(item["condition"].IsDefined()) { + v.cond_ctx = rule_loader::context(item["condition"], + rule_loader::context::RULE_CONDITION, + "", + ctx); decode_val(item, "condition", v.cond, ctx); } - if(item["exceptions"].IsDefined()) - { + if(item["exceptions"].IsDefined()) { read_rule_exceptions(cfg, item, v.exceptions, ctx, true); } // TODO restore this error and update testing - //THROW((!v.cond.has_value() && !v.exceptions.has_value()), + // THROW((!v.cond.has_value() && !v.exceptions.has_value()), // "Appended rule must have exceptions or condition property", // v.ctx); collector.append(cfg, v); - } - else - { + } else { rule_loader::rule_info v(ctx); v.name = name; v.enabled = true; @@ -739,34 +796,41 @@ void rule_loader::reader::read_item( // have an enabled property. Use the enabled // property to set the enabled status of an // earlier rule. - if (!item["condition"].IsDefined() && - !item["output"].IsDefined() && - !item["desc"].IsDefined() && - !item["priority"].IsDefined()) - { + if(!item["condition"].IsDefined() && !item["output"].IsDefined() && + !item["desc"].IsDefined() && !item["priority"].IsDefined()) { decode_val(item, "enabled", v.enabled, ctx); - cfg.res->add_warning(falco::load_result::LOAD_DEPRECATED_ITEM, WARNING_ENABLED, ctx); + cfg.res->add_warning(falco::load_result::LOAD_DEPRECATED_ITEM, + WARNING_ENABLED, + ctx); collector.enable(cfg, v); - } - else - { + } else { std::string priority; // All of these are required decode_val(item, "condition", v.cond, ctx); - v.cond_ctx = rule_loader::context(item["condition"], rule_loader::context::RULE_CONDITION, "", ctx); + v.cond_ctx = rule_loader::context(item["condition"], + rule_loader::context::RULE_CONDITION, + "", + ctx); decode_val(item, "output", v.output, ctx); - v.output_ctx = rule_loader::context(item["output"], rule_loader::context::RULE_OUTPUT, "", ctx); + v.output_ctx = rule_loader::context(item["output"], + rule_loader::context::RULE_OUTPUT, + "", + ctx); decode_val(item, "desc", v.desc, ctx); decode_val(item, "priority", priority, ctx); v.output = trim(v.output); v.source = falco_common::syscall_source; - rule_loader::context prictx(item["priority"], rule_loader::context::RULE_PRIORITY, "", ctx); + rule_loader::context prictx(item["priority"], + rule_loader::context::RULE_PRIORITY, + "", + ctx); THROW(!falco_common::parse_priority(priority, v.priority), - "Invalid priority", prictx); + "Invalid priority", + prictx); decode_optional_val(item, "source", v.source, ctx); decode_optional_val(item, "enabled", v.enabled, ctx); decode_optional_val(item, "warn_evttypes", v.warn_evttypes, ctx); @@ -776,85 +840,65 @@ void rule_loader::reader::read_item( collector.define(cfg, v); } } - } - else - { + } else { rule_loader::context ctx(item, rule_loader::context::RULES_CONTENT_ITEM, "", parent); cfg.res->add_warning(falco::load_result::LOAD_UNKNOWN_ITEM, "Unknown top level item", ctx); } } -bool rule_loader::reader::read(rule_loader::configuration& cfg, collector& collector, const nlohmann::json& schema) -{ +bool rule_loader::reader::read(rule_loader::configuration& cfg, + collector& collector, + const nlohmann::json& schema) { std::vector docs; yaml_helper reader; std::vector schema_warnings; rule_loader::context ctx(cfg.name); - try - { + try { docs = reader.loadall_from_string(cfg.content, schema, &schema_warnings); - } - catch (YAML::ParserException& e) - { + } catch(YAML::ParserException& e) { rule_loader::context ictx(e.mark, ctx); cfg.res->add_error(falco::load_result::LOAD_ERR_YAML_PARSE, e.what(), ictx); return false; - } - catch (std::exception& e) - { + } catch(std::exception& e) { cfg.res->add_error(falco::load_result::LOAD_ERR_YAML_PARSE, e.what(), ctx); return false; - } - catch (...) - { - cfg.res->add_error(falco::load_result::LOAD_ERR_YAML_PARSE, "unknown YAML parsing error", ctx); + } catch(...) { + cfg.res->add_error(falco::load_result::LOAD_ERR_YAML_PARSE, + "unknown YAML parsing error", + ctx); return false; } cfg.res->set_schema_validation_status(schema_warnings); - for (auto doc = docs.begin(); doc != docs.end(); doc++) - { - if (doc->IsDefined() && !doc->IsNull()) - { + for(auto doc = docs.begin(); doc != docs.end(); doc++) { + if(doc->IsDefined() && !doc->IsNull()) { try { - THROW(!doc->IsMap() && !doc->IsSequence(), - "Rules content is not yaml", - ctx); - - THROW(!doc->IsSequence(), - "Rules content is not yaml array of objects", - ctx); - - for (auto it = doc->begin(); it != doc->end(); it++) - { - if (!it->IsNull()) - { + THROW(!doc->IsMap() && !doc->IsSequence(), "Rules content is not yaml", ctx); + + THROW(!doc->IsSequence(), "Rules content is not yaml array of objects", ctx); + + for(auto it = doc->begin(); it != doc->end(); it++) { + if(!it->IsNull()) { read_item(cfg, collector, *it, ctx); } } - } - catch (rule_loader::rule_load_exception &e) - { + } catch(rule_loader::rule_load_exception& e) { cfg.res->add_error(e.ec, e.msg, e.ctx); // Although we *could* continue on to the next doc, // as it's effectively a new rules file, for // consistency we stop at the first error. return false; - } - catch (YAML::ParserException& e) - { + } catch(YAML::ParserException& e) { rule_loader::context ictx(e.mark, ctx); cfg.res->add_error(falco::load_result::LOAD_ERR_YAML_VALIDATE, e.what(), ictx); return false; - } - catch (std::exception& e) - { + } catch(std::exception& e) { cfg.res->add_error(falco::load_result::LOAD_ERR_VALIDATE, e.what(), ctx); return false; - } - catch (...) - { - cfg.res->add_error(falco::load_result::LOAD_ERR_VALIDATE, "unknown validation error", ctx); + } catch(...) { + cfg.res->add_error(falco::load_result::LOAD_ERR_VALIDATE, + "unknown validation error", + ctx); return false; } } diff --git a/userspace/engine/rule_loader_reader.h b/userspace/engine/rule_loader_reader.h index d105d0372e3..3edfded67f8 100644 --- a/userspace/engine/rule_loader_reader.h +++ b/userspace/engine/rule_loader_reader.h @@ -23,53 +23,55 @@ limitations under the License. #include #include "falco_engine_version.h" -namespace rule_loader -{ +namespace rule_loader { /*! \brief Reads the contents of a ruleset */ -class reader -{ +class reader { public: - reader() = default; - virtual ~reader() = default; - reader(reader&&) = default; - reader& operator = (reader&&) = default; + reader() = default; + virtual ~reader() = default; + reader(reader&&) = default; + reader& operator=(reader&&) = default; reader(const reader&) = default; - reader& operator = (const reader&) = default; + reader& operator=(const reader&) = default; - /*! - \brief Reads the contents of a ruleset and uses a collector to store - thew new definitions + /*! + \brief Reads the contents of a ruleset and uses a collector to store + thew new definitions */ - virtual bool read(configuration& cfg, collector& loader, const nlohmann::json& schema={}); - - /*! - \brief Engine version used to be represented as a simple progressive + virtual bool read(configuration& cfg, collector& loader, const nlohmann::json& schema = {}); + + /*! + \brief Engine version used to be represented as a simple progressive number. With the new semver schema, the number now represents - the semver minor number. This function converts the legacy version + the semver minor number. This function converts the legacy version number to the new semver schema. - */ - static inline sinsp_version get_implicit_engine_version(uint32_t minor) - { - return sinsp_version(std::to_string(FALCO_ENGINE_VERSION_MAJOR) + "." - + std::to_string(minor) + "." - + std::to_string(FALCO_ENGINE_VERSION_PATCH)); + */ + static inline sinsp_version get_implicit_engine_version(uint32_t minor) { + return sinsp_version(std::to_string(FALCO_ENGINE_VERSION_MAJOR) + "." + + std::to_string(minor) + "." + + std::to_string(FALCO_ENGINE_VERSION_PATCH)); } - template - static void decode_val(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx); + template + static void decode_val(const YAML::Node& item, + const char* key, + T& out, + const rule_loader::context& ctx); - template - static void decode_optional_val(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx); + template + static void decode_optional_val(const YAML::Node& item, + const char* key, + T& out, + const rule_loader::context& ctx); protected: - virtual void read_item(rule_loader::configuration& cfg, - rule_loader::collector& collector, - const YAML::Node& item, - const rule_loader::context& parent); + rule_loader::collector& collector, + const YAML::Node& item, + const rule_loader::context& parent); }; -}; // namespace rule_loader +}; // namespace rule_loader diff --git a/userspace/engine/rule_loading_messages.h b/userspace/engine/rule_loading_messages.h index 5962fb0a406..94695a0de8b 100644 --- a/userspace/engine/rule_loading_messages.h +++ b/userspace/engine/rule_loading_messages.h @@ -4,20 +4,30 @@ // Warnings //////////////// -#define WARNING_APPEND "'append' key is deprecated. Add an 'append' entry (e.g. 'condition: append') under 'override' instead." +#define WARNING_APPEND \ + "'append' key is deprecated. Add an 'append' entry (e.g. 'condition: append') under " \ + "'override' instead." -#define WARNING_ENABLED "The standalone 'enabled' key usage is deprecated. The correct approach requires also a 'replace' entry under the 'override' key (i.e. 'enabled: replace')." +#define WARNING_ENABLED \ + "The standalone 'enabled' key usage is deprecated. The correct approach requires also a " \ + "'replace' entry under the 'override' key (i.e. 'enabled: replace')." //////////////// // Errors //////////////// -#define ERROR_OVERRIDE_APPEND "Keys 'override' and 'append: true' cannot be used together. Add an 'append' entry (e.g. 'condition: append') under 'override' instead." +#define ERROR_OVERRIDE_APPEND \ + "Keys 'override' and 'append: true' cannot be used together. Add an 'append' entry (e.g. " \ + "'condition: append') under 'override' instead." -#define ERROR_NO_PREVIOUS_MACRO "Macro uses 'append' or 'override.condition: append' but no macro by that name already exists" +#define ERROR_NO_PREVIOUS_MACRO \ + "Macro uses 'append' or 'override.condition: append' but no macro by that name already exists" -#define ERROR_NO_PREVIOUS_LIST "List uses 'append' or 'override.items: append' but no list by that name already exists" +#define ERROR_NO_PREVIOUS_LIST \ + "List uses 'append' or 'override.items: append' but no list by that name already exists" -#define ERROR_NO_PREVIOUS_RULE_APPEND "Rule uses 'append' or 'override.: append' but no rule by that name already exists" +#define ERROR_NO_PREVIOUS_RULE_APPEND \ + "Rule uses 'append' or 'override.: append' but no rule by that name already exists" -#define ERROR_NO_PREVIOUS_RULE_REPLACE "An 'override.: replace' to a rule was requested but no rule by that name already exists" +#define ERROR_NO_PREVIOUS_RULE_REPLACE \ + "An 'override.: replace' to a rule was requested but no rule by that name already exists" diff --git a/userspace/engine/stats_manager.cpp b/userspace/engine/stats_manager.cpp index 79f61a2a1ef..ced0c027672 100644 --- a/userspace/engine/stats_manager.cpp +++ b/userspace/engine/stats_manager.cpp @@ -18,72 +18,53 @@ limitations under the License. #include "stats_manager.h" #include "falco_common.h" -stats_manager::stats_manager() - : m_total(0) -{ -} +stats_manager::stats_manager(): m_total(0) {} -stats_manager::~stats_manager() -{ +stats_manager::~stats_manager() { clear(); } -void stats_manager::clear() -{ +void stats_manager::clear() { m_total = 0; m_by_rule_id.clear(); m_by_priority.clear(); } -void stats_manager::format( - const indexed_vector& rules, - std::string& out) const -{ +void stats_manager::format(const indexed_vector& rules, std::string& out) const { std::string fmt; out = "Events detected: " + to_string(m_total) + "\n"; out += "Rule counts by severity:\n"; - for (size_t i = 0; i < m_by_priority.size(); i++) - { + for(size_t i = 0; i < m_by_priority.size(); i++) { auto val = m_by_priority[i]->load(); - if (val > 0) - { - falco_common::format_priority( - (falco_common::priority_type) i, fmt, true); + if(val > 0) { + falco_common::format_priority((falco_common::priority_type)i, fmt, true); transform(fmt.begin(), fmt.end(), fmt.begin(), ::toupper); out += " " + fmt + ": " + std::to_string(val) + "\n"; } } out += "Triggered rules by rule name:\n"; - for (size_t i = 0; i < m_by_rule_id.size(); i++) - { + for(size_t i = 0; i < m_by_rule_id.size(); i++) { auto val = m_by_rule_id[i]->load(); - if (val > 0) - { + if(val > 0) { out += " " + rules.at(i)->name + ": " + std::to_string(val) + "\n"; } } } -void stats_manager::on_rule_loaded(const falco_rule& rule) -{ - while (m_by_rule_id.size() <= rule.id) - { +void stats_manager::on_rule_loaded(const falco_rule& rule) { + while(m_by_rule_id.size() <= rule.id) { m_by_rule_id.emplace_back(std::make_unique>(0)); } - while (m_by_priority.size() <= (size_t) rule.priority) - { + while(m_by_priority.size() <= (size_t)rule.priority) { m_by_priority.emplace_back(std::make_unique>(0)); } } -void stats_manager::on_event(const falco_rule& rule) -{ - if (m_by_rule_id.size() <= rule.id - || m_by_priority.size() <= (size_t) rule.priority) - { +void stats_manager::on_event(const falco_rule& rule) { + if(m_by_rule_id.size() <= rule.id || m_by_priority.size() <= (size_t)rule.priority) { throw falco_exception("rule id or priority out of bounds"); } m_total.fetch_add(1, std::memory_order_relaxed); m_by_rule_id[rule.id]->fetch_add(1, std::memory_order_relaxed); - m_by_priority[(size_t) rule.priority]->fetch_add(1, std::memory_order_relaxed); + m_by_priority[(size_t)rule.priority]->fetch_add(1, std::memory_order_relaxed); } diff --git a/userspace/engine/stats_manager.h b/userspace/engine/stats_manager.h index c7c2a5c0ffb..1d262787356 100644 --- a/userspace/engine/stats_manager.h +++ b/userspace/engine/stats_manager.h @@ -25,61 +25,52 @@ limitations under the License. #include "indexed_vector.h" /*! - \brief Manager for the internal statistics of the rule engine. - The on_event() is thread-safe and non-blocking, and it can be used - concurrently across many callers in parallel. - All the other methods are not thread safe. + \brief Manager for the internal statistics of the rule engine. + The on_event() is thread-safe and non-blocking, and it can be used + concurrently across many callers in parallel. + All the other methods are not thread safe. */ -class stats_manager -{ +class stats_manager { public: stats_manager(); virtual ~stats_manager(); /*! - \brief Erases the internal state and statistics data + \brief Erases the internal state and statistics data */ virtual void clear(); /*! - \brief Callback for when a new rule is loaded in the engine. - Rules must be passed through this method before submitting them as - an argument of on_event(). + \brief Callback for when a new rule is loaded in the engine. + Rules must be passed through this method before submitting them as + an argument of on_event(). */ virtual void on_rule_loaded(const falco_rule& rule); /*! - \brief Callback for when a given rule matches an event. - This method is thread-safe. - \throws falco_exception if rule has not been passed to - on_rule_loaded() first + \brief Callback for when a given rule matches an event. + This method is thread-safe. + \throws falco_exception if rule has not been passed to + on_rule_loaded() first */ virtual void on_event(const falco_rule& rule); /*! - \brief Formats the internal statistics into the out string. + \brief Formats the internal statistics into the out string. */ - virtual void format( - const indexed_vector& rules, - std::string& out) const; + virtual void format(const indexed_vector& rules, std::string& out) const; // Getter functions - inline const std::atomic& get_total() const - { - return m_total; - } + inline const std::atomic& get_total() const { return m_total; } - inline const std::vector>>& get_by_priority() const - { + inline const std::vector>>& get_by_priority() const { return m_by_priority; } - inline const std::vector>>& get_by_rule_id() const - { + inline const std::vector>>& get_by_rule_id() const { return m_by_rule_id; } - private: std::atomic m_total; std::vector>> m_by_priority; diff --git a/userspace/engine/yaml_helper.h b/userspace/engine/yaml_helper.h index 1220fad0b92..8f9ed08a09e 100644 --- a/userspace/engine/yaml_helper.h +++ b/userspace/engine/yaml_helper.h @@ -48,23 +48,23 @@ class yaml_visitor { using Callback = std::function; explicit yaml_visitor(Callback cb): seen(), cb(std::move(cb)) {} - void operator()(YAML::Node &cur) { + void operator()(YAML::Node& cur) { seen.push_back(cur); - if (cur.IsMap()) { - for (YAML::detail::iterator_value pair : cur) { + if(cur.IsMap()) { + for(YAML::detail::iterator_value pair : cur) { descend(pair.second); } - } else if (cur.IsSequence()) { - for (YAML::detail::iterator_value child : cur) { + } else if(cur.IsSequence()) { + for(YAML::detail::iterator_value child : cur) { descend(child); } - } else if (cur.IsScalar()) { + } else if(cur.IsScalar()) { cb(cur); } } - void descend(YAML::Node &target) { - if (std::find(seen.begin(), seen.end(), target) == seen.end()) { + void descend(YAML::Node& target) { + if(std::find(seen.begin(), seen.end(), target) == seen.end()) { (*this)(target); } } @@ -78,8 +78,7 @@ class yaml_visitor { /** * @brief An helper class for reading and editing YAML documents */ -class yaml_helper -{ +class yaml_helper { public: inline static const std::string configs_key = "config_files"; inline static const std::string validation_ok = "ok"; @@ -87,25 +86,22 @@ class yaml_helper inline static const std::string validation_none = "none"; /** - * Load all the YAML document represented by the input string. - * Since this is used by rule loader, does not process env vars. - */ - std::vector loadall_from_string(const std::string& input, const nlohmann::json& schema={}, std::vector *schema_warnings=nullptr) - { + * Load all the YAML document represented by the input string. + * Since this is used by rule loader, does not process env vars. + */ + std::vector loadall_from_string( + const std::string& input, + const nlohmann::json& schema = {}, + std::vector* schema_warnings = nullptr) { auto nodes = YAML::LoadAll(input); - if (schema_warnings) - { + if(schema_warnings) { schema_warnings->clear(); - if(!schema.empty()) - { + if(!schema.empty()) { // Validate each node. - for(const auto& node : nodes) - { + for(const auto& node : nodes) { validate_node(node, schema, schema_warnings); } - } - else - { + } else { schema_warnings->push_back(validation_none); } } @@ -113,50 +109,48 @@ class yaml_helper } /** - * Load the YAML document represented by the input string. - */ - void load_from_string(const std::string& input, const nlohmann::json& schema={}, std::vector *schema_warnings=nullptr) - { + * Load the YAML document represented by the input string. + */ + void load_from_string(const std::string& input, + const nlohmann::json& schema = {}, + std::vector* schema_warnings = nullptr) { m_root = YAML::Load(input); pre_process_env_vars(m_root); - if (schema_warnings) - { + if(schema_warnings) { schema_warnings->clear(); - if(!schema.empty()) - { + if(!schema.empty()) { validate_node(m_root, schema, schema_warnings); - } - else - { + } else { schema_warnings->push_back(validation_none); } } } /** - * Load the YAML document from the given file path. - */ - void load_from_file(const std::string& path, const nlohmann::json& schema={}, std::vector *schema_warnings=nullptr) - { + * Load the YAML document from the given file path. + */ + void load_from_file(const std::string& path, + const nlohmann::json& schema = {}, + std::vector* schema_warnings = nullptr) { m_root = load_from_file_int(path, schema, schema_warnings); } - void include_config_file(const std::string& include_file_path, const nlohmann::json& schema={}, std::vector *schema_warnings=nullptr) - { + void include_config_file(const std::string& include_file_path, + const nlohmann::json& schema = {}, + std::vector* schema_warnings = nullptr) { auto loaded_nodes = load_from_file_int(include_file_path, schema, schema_warnings); - for(auto n : loaded_nodes) - { + for(auto n : loaded_nodes) { /* * To avoid recursion hell, * we don't support `config_files` directives from included config files * (that use load_from_file_int recursively). */ - const auto &key = n.first.Scalar(); - if (key == configs_key) - { - throw std::runtime_error( - "Config error: '" + configs_key + "' directive in included config file " + include_file_path + "."); + const auto& key = n.first.Scalar(); + if(key == configs_key) { + throw std::runtime_error("Config error: '" + configs_key + + "' directive in included config file " + + include_file_path + "."); } // We allow to override keys. // We don't need to use `get_node()` here, @@ -168,21 +162,16 @@ class yaml_helper /** * Clears the internal loaded document. */ - void clear() - { - m_root = YAML::Node(); - } + void clear() { m_root = YAML::Node(); } /** - * Get a scalar value from the node identified by key. - */ + * Get a scalar value from the node identified by key. + */ template - const T get_scalar(const std::string& key, const T& default_value) const - { + const T get_scalar(const std::string& key, const T& default_value) const { YAML::Node node; get_node(node, key); - if(node.IsDefined()) - { + if(node.IsDefined()) { return node.as(default_value); } return default_value; @@ -192,8 +181,7 @@ class yaml_helper * Set the node identified by key to value. */ template - void set_scalar(const std::string& key, const T& value) - { + void set_scalar(const std::string& key, const T& value) { YAML::Node node; get_node(node, key, true); node = value; @@ -202,66 +190,60 @@ class yaml_helper /** * Set the node identified by key to an object value */ - void set_object(const std::string& key, const YAML::Node& value) - { + void set_object(const std::string& key, const YAML::Node& value) { YAML::Node node; get_node(node, key, true); node = value; } /** - * Get the sequence value from the node identified by key. - */ + * Get the sequence value from the node identified by key. + */ template - void get_sequence(T& ret, const std::string& key) const - { + void get_sequence(T& ret, const std::string& key) const { YAML::Node node; get_node(node, key); return get_sequence_from_node(ret, node); } /** - * Return true if the node identified by key is defined. - */ - bool is_defined(const std::string& key) const - { + * Return true if the node identified by key is defined. + */ + bool is_defined(const std::string& key) const { YAML::Node node; get_node(node, key); return node.IsDefined(); } - std::string dump() const - { + std::string dump() const { YAML::Emitter emitter; emitter << YAML::DoubleQuoted << YAML::Flow << YAML::LowerNull << YAML::BeginSeq << m_root; - return emitter.c_str() + 1; // drop initial '[' char + return emitter.c_str() + 1; // drop initial '[' char } private: YAML::Node m_root; - YAML::Node load_from_file_int(const std::string& path, const nlohmann::json& schema, std::vector *schema_warnings) - { + YAML::Node load_from_file_int(const std::string& path, + const nlohmann::json& schema, + std::vector* schema_warnings) { auto root = YAML::LoadFile(path); pre_process_env_vars(root); - if (schema_warnings) - { + if(schema_warnings) { schema_warnings->clear(); - if(!schema.empty()) - { + if(!schema.empty()) { validate_node(root, schema, schema_warnings); - } - else - { + } else { schema_warnings->push_back(validation_none); } } return root; } - void validate_node(const YAML::Node &node, const nlohmann::json& schema, std::vector *schema_warnings) - { + void validate_node(const YAML::Node& node, + const nlohmann::json& schema, + std::vector* schema_warnings) { // Validate the yaml against our json schema valijson::Schema schemaDef; valijson::SchemaParser schemaParser; @@ -271,20 +253,17 @@ class yaml_helper valijson::adapters::NlohmannJsonAdapter schemaAdapter(schema); schemaParser.populateSchema(schemaAdapter, schemaDef); - if (!validator.validate(schemaDef, configAdapter, &validationResults)) - { + if(!validator.validate(schemaDef, configAdapter, &validationResults)) { valijson::ValidationResults::Error error; // report only the top-most error - while (validationResults.popError(error)) - { - schema_warnings->push_back(std::string(validation_failed + " for ") - + std::accumulate(error.context.begin(), error.context.end(), std::string("")) - + ": " - + error.description); + while(validationResults.popError(error)) { + schema_warnings->push_back(std::string(validation_failed + " for ") + + std::accumulate(error.context.begin(), + error.context.end(), + std::string("")) + + ": " + error.description); } - } - else - { + } else { schema_warnings->push_back(validation_ok); } } @@ -295,63 +274,51 @@ class yaml_helper * and resolve any "${env_var}" to its value; * moreover, any "$${str}" is resolved to simply "${str}". */ - void pre_process_env_vars(YAML::Node& root) - { - yaml_visitor([](YAML::Node &scalar) { - auto value = scalar.as(); - auto start_pos = value.find('$'); - while (start_pos != std::string::npos) - { - auto substr = value.substr(start_pos); - // Case 1 -> ${} - if (substr.rfind("${", 0) == 0) - { - auto end_pos = substr.find('}'); - if (end_pos != std::string::npos) - { - // Eat "${" and "}" when getting the env var name - auto env_str = substr.substr(2, end_pos - 2); - const char* env_value = std::getenv(env_str.c_str()); // Get the environment variable value - if(env_value) - { - // env variable name + "${}" - value.replace(start_pos, env_str.length() + 3, env_value); - } - else - { - value.erase(start_pos, env_str.length() + 3); - } - } - else - { - // There are no "}" chars anymore; just break leaving rest of value untouched. - break; - } - } - // Case 2 -> $${} - else if (substr.rfind("$${", 0) == 0) - { - auto end_pos = substr.find('}'); - if (end_pos != std::string::npos) - { - // Consume first "$" token - value.erase(start_pos, 1); - } - else - { - // There are no "}" chars anymore; just break leaving rest of value untouched. - break; + void pre_process_env_vars(YAML::Node& root) { + yaml_visitor([](YAML::Node& scalar) { + auto value = scalar.as(); + auto start_pos = value.find('$'); + while(start_pos != std::string::npos) { + auto substr = value.substr(start_pos); + // Case 1 -> ${} + if(substr.rfind("${", 0) == 0) { + auto end_pos = substr.find('}'); + if(end_pos != std::string::npos) { + // Eat "${" and "}" when getting the env var name + auto env_str = substr.substr(2, end_pos - 2); + const char* env_value = + std::getenv(env_str.c_str()); // Get the environment variable value + if(env_value) { + // env variable name + "${}" + value.replace(start_pos, env_str.length() + 3, env_value); + } else { + value.erase(start_pos, env_str.length() + 3); } - start_pos++; // consume the second '$' token + } else { + // There are no "}" chars anymore; just break leaving rest of value + // untouched. + break; } - else - { - start_pos += substr.length(); + } + // Case 2 -> $${} + else if(substr.rfind("$${", 0) == 0) { + auto end_pos = substr.find('}'); + if(end_pos != std::string::npos) { + // Consume first "$" token + value.erase(start_pos, 1); + } else { + // There are no "}" chars anymore; just break leaving rest of value + // untouched. + break; } - start_pos = value.find("$", start_pos); + start_pos++; // consume the second '$' token + } else { + start_pos += substr.length(); } - scalar = value; - })(root); + start_pos = value.find("$", start_pos); + } + scalar = value; + })(root); } /** @@ -365,101 +332,79 @@ class yaml_helper * * If can_append is true, an empty NodeKey will append a new entry * to the sequence, it is rejected otherwise. - * + * * Some examples of accepted key strings: * - NodeName * - ListValue[3].subvalue * - MatrixValue[1][3] * - value1.subvalue2.subvalue3 */ - void get_node(YAML::Node &ret, const std::string &key, bool can_append=false) const - { - try - { + void get_node(YAML::Node& ret, const std::string& key, bool can_append = false) const { + try { char c; bool should_shift; std::string nodeKey; ret.reset(m_root); - for(std::string::size_type i = 0; i < key.size(); ++i) - { + for(std::string::size_type i = 0; i < key.size(); ++i) { c = key[i]; should_shift = c == '.' || c == '[' || i == key.size() - 1; - if (c != '.' && c != '[') - { - if (i > 0 && nodeKey.empty() && key[i - 1] != '.') - { - throw std::runtime_error( - "Parsing error: expected '.' character at pos " - + std::to_string(i - 1)); + if(c != '.' && c != '[') { + if(i > 0 && nodeKey.empty() && key[i - 1] != '.') { + throw std::runtime_error("Parsing error: expected '.' character at pos " + + std::to_string(i - 1)); } nodeKey += c; } - if (should_shift) - { - if (nodeKey.empty()) - { - throw std::runtime_error( - "Parsing error: unexpected character at pos " - + std::to_string(i)); + if(should_shift) { + if(nodeKey.empty()) { + throw std::runtime_error("Parsing error: unexpected character at pos " + + std::to_string(i)); } ret.reset(ret[nodeKey]); nodeKey.clear(); } - if (c == '[') - { + if(c == '[') { auto close_param_idx = key.find(']', i); std::string idx_str = key.substr(i + 1, close_param_idx - i - 1); int nodeIdx; bool ret_appendable = !ret.IsDefined() || ret.IsSequence(); - if (idx_str.empty() && ret_appendable && can_append) - { + if(idx_str.empty() && ret_appendable && can_append) { YAML::Node newNode; ret.push_back(newNode); nodeIdx = ret.size() - 1; - } - else - { - try - { + } else { + try { nodeIdx = std::stoi(idx_str); - } - catch(const std::exception& e) - { - throw std::runtime_error("Parsing error: expected a numeric index, found '" + idx_str + "'"); + } catch(const std::exception& e) { + throw std::runtime_error( + "Parsing error: expected a numeric index, found '" + idx_str + + "'"); } } ret.reset(ret[nodeIdx]); i = close_param_idx; - if (i < key.size() - 1 && key[i + 1] == '.') - { + if(i < key.size() - 1 && key[i + 1] == '.') { i++; } } } - } - catch(const std::exception& e) - { - throw std::runtime_error("Config error at key \"" + key + "\": " + std::string(e.what())); + } catch(const std::exception& e) { + throw std::runtime_error("Config error at key \"" + key + + "\": " + std::string(e.what())); } } template - void get_sequence_from_node(T& ret, const YAML::Node& node) const - { - if(node.IsDefined()) - { - if(node.IsSequence()) - { - for(const YAML::Node& item : node) - { + void get_sequence_from_node(T& ret, const YAML::Node& node) const { + if(node.IsDefined()) { + if(node.IsSequence()) { + for(const YAML::Node& item : node) { ret.insert(ret.end(), item.as()); } - } - else if(node.IsScalar()) - { + } else if(node.IsScalar()) { ret.insert(ret.end(), node.as()); } } @@ -468,55 +413,45 @@ class yaml_helper // define a yaml-cpp conversion function for nlohmann json objects namespace YAML { - template<> - struct convert { - static bool decode(const Node& node, nlohmann::json& res) - { - int int_val; - double double_val; - bool bool_val; - std::string str_val; - - switch (node.Type()) { - case YAML::NodeType::Map: - for (auto &&it: node) - { - nlohmann::json sub{}; - YAML::convert::decode(it.second, sub); - res[it.first.as()] = sub; - } - break; - case YAML::NodeType::Sequence: - for (auto &&it : node) - { - nlohmann::json sub{}; - YAML::convert::decode(it, sub); - res.emplace_back(sub); - } - break; - case YAML::NodeType::Scalar: - if (YAML::convert::decode(node, int_val)) - { - res = int_val; - } - else if (YAML::convert::decode(node, double_val)) - { - res = double_val; - } - else if (YAML::convert::decode(node, bool_val)) - { - res = bool_val; - } - else if (YAML::convert::decode(node, str_val)) - { - res = str_val; - } - default: - break; +template<> +struct convert { + static bool decode(const Node& node, nlohmann::json& res) { + int int_val; + double double_val; + bool bool_val; + std::string str_val; + + switch(node.Type()) { + case YAML::NodeType::Map: + for(auto&& it : node) { + nlohmann::json sub{}; + YAML::convert::decode(it.second, sub); + res[it.first.as()] = sub; } - - return true; + break; + case YAML::NodeType::Sequence: + for(auto&& it : node) { + nlohmann::json sub{}; + YAML::convert::decode(it, sub); + res.emplace_back(sub); + } + break; + case YAML::NodeType::Scalar: + if(YAML::convert::decode(node, int_val)) { + res = int_val; + } else if(YAML::convert::decode(node, double_val)) { + res = double_val; + } else if(YAML::convert::decode(node, bool_val)) { + res = bool_val; + } else if(YAML::convert::decode(node, str_val)) { + res = str_val; + } + default: + break; } - // The "encode" function is not needed here, in fact you can simply YAML::load any json string. - }; -} + + return true; + } + // The "encode" function is not needed here, in fact you can simply YAML::load any json string. +}; +} // namespace YAML diff --git a/userspace/falco/CMakeLists.txt b/userspace/falco/CMakeLists.txt index 0758b245fef..13849e6fe9a 100644 --- a/userspace/falco/CMakeLists.txt +++ b/userspace/falco/CMakeLists.txt @@ -2,138 +2,126 @@ # # Copyright (C) 2023 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 +# 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. +# 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. # configure_file(config_falco.h.in config_falco.h) -add_library(falco_application STATIC - app/app.cpp - app/options.cpp - app/restart_handler.cpp - app/actions/helpers_generic.cpp - app/actions/helpers_inspector.cpp - app/actions/configure_interesting_sets.cpp - app/actions/create_signal_handlers.cpp - app/actions/pidfile.cpp - app/actions/init_falco_engine.cpp - app/actions/init_inspectors.cpp - app/actions/init_outputs.cpp - app/actions/list_fields.cpp - app/actions/list_plugins.cpp - app/actions/load_config.cpp - app/actions/load_plugins.cpp - app/actions/load_rules_files.cpp - app/actions/process_events.cpp - app/actions/print_generated_gvisor_config.cpp - app/actions/print_help.cpp - app/actions/print_ignored_events.cpp - app/actions/print_kernel_version.cpp - app/actions/print_plugin_info.cpp - app/actions/print_support.cpp - app/actions/print_syscall_events.cpp - app/actions/print_version.cpp - app/actions/print_page_size.cpp - app/actions/configure_syscall_buffer_size.cpp - app/actions/configure_syscall_buffer_num.cpp - app/actions/select_event_sources.cpp - app/actions/start_grpc_server.cpp - app/actions/start_webserver.cpp - app/actions/validate_rules_files.cpp - app/actions/create_requested_paths.cpp - app/actions/close_inspectors.cpp - app/actions/print_config_schema.cpp - app/actions/print_rule_schema.cpp - configuration.cpp - falco_outputs.cpp - outputs_file.cpp - outputs_stdout.cpp - event_drops.cpp - stats_writer.cpp - versions_info.cpp +add_library( + falco_application STATIC + app/app.cpp + app/options.cpp + app/restart_handler.cpp + app/actions/helpers_generic.cpp + app/actions/helpers_inspector.cpp + app/actions/configure_interesting_sets.cpp + app/actions/create_signal_handlers.cpp + app/actions/pidfile.cpp + app/actions/init_falco_engine.cpp + app/actions/init_inspectors.cpp + app/actions/init_outputs.cpp + app/actions/list_fields.cpp + app/actions/list_plugins.cpp + app/actions/load_config.cpp + app/actions/load_plugins.cpp + app/actions/load_rules_files.cpp + app/actions/process_events.cpp + app/actions/print_generated_gvisor_config.cpp + app/actions/print_help.cpp + app/actions/print_ignored_events.cpp + app/actions/print_kernel_version.cpp + app/actions/print_plugin_info.cpp + app/actions/print_support.cpp + app/actions/print_syscall_events.cpp + app/actions/print_version.cpp + app/actions/print_page_size.cpp + app/actions/configure_syscall_buffer_size.cpp + app/actions/configure_syscall_buffer_num.cpp + app/actions/select_event_sources.cpp + app/actions/start_grpc_server.cpp + app/actions/start_webserver.cpp + app/actions/validate_rules_files.cpp + app/actions/create_requested_paths.cpp + app/actions/close_inspectors.cpp + app/actions/print_config_schema.cpp + app/actions/print_rule_schema.cpp + configuration.cpp + falco_outputs.cpp + outputs_file.cpp + outputs_stdout.cpp + event_drops.cpp + stats_writer.cpp + versions_info.cpp ) -set( - FALCO_INCLUDE_DIRECTORIES - "${PROJECT_SOURCE_DIR}/userspace/engine" - "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}" - "${PROJECT_BINARY_DIR}/driver/src" - "${CXXOPTS_INCLUDE_DIR}" +set(FALCO_INCLUDE_DIRECTORIES + "${PROJECT_SOURCE_DIR}/userspace/engine" "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" "${PROJECT_BINARY_DIR}/driver/src" "${CXXOPTS_INCLUDE_DIR}" ) -set( - FALCO_DEPENDENCIES - cxxopts -) +set(FALCO_DEPENDENCIES cxxopts) -set( - FALCO_LIBRARIES - falco_engine - sinsp - yaml-cpp -) +set(FALCO_LIBRARIES falco_engine sinsp yaml-cpp) if(NOT WIN32) - target_sources(falco_application - PRIVATE - outputs_program.cpp - outputs_syslog.cpp - ) + target_sources(falco_application PRIVATE outputs_program.cpp outputs_syslog.cpp) endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD) - target_sources(falco_application - PRIVATE - outputs_grpc.cpp - outputs_http.cpp - falco_metrics.cpp - webserver.cpp - grpc_context.cpp - grpc_request_context.cpp - grpc_server.cpp - grpc_context.cpp - ${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc - ${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc - ${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc - ${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc - ${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc - ) - - list( - APPEND FALCO_INCLUDE_DIRECTORIES - "${OPENSSL_INCLUDE_DIR}" - "${GRPC_INCLUDE}" - "${GRPCPP_INCLUDE}" - "${PROTOBUF_INCLUDE}" - "${CARES_INCLUDE}" - ) - - if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND USE_BUNDLED_GRPC) - list(APPEND FALCO_DEPENDENCIES grpc) - list(APPEND FALCO_LIBRARIES "${GRPC_LIBRARIES}") - endif() - - list( - APPEND FALCO_LIBRARIES - httplib::httplib - "${GRPCPP_LIB}" - "${GRPC_LIB}" - "${GPR_LIB}" - "${PROTOBUF_LIB}" - "${CARES_LIB}" - "${OPENSSL_LIBRARIES}" - ) + target_sources( + falco_application + PRIVATE outputs_grpc.cpp + outputs_http.cpp + falco_metrics.cpp + webserver.cpp + grpc_context.cpp + grpc_request_context.cpp + grpc_server.cpp + grpc_context.cpp + ${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc + ${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc + ${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc + ${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc + ${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc + ) + + list( + APPEND + FALCO_INCLUDE_DIRECTORIES + "${OPENSSL_INCLUDE_DIR}" + "${GRPC_INCLUDE}" + "${GRPCPP_INCLUDE}" + "${PROTOBUF_INCLUDE}" + "${CARES_INCLUDE}" + ) + + if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND USE_BUNDLED_GRPC) + list(APPEND FALCO_DEPENDENCIES grpc) + list(APPEND FALCO_LIBRARIES "${GRPC_LIBRARIES}") + endif() + + list( + APPEND + FALCO_LIBRARIES + httplib::httplib + "${GRPCPP_LIB}" + "${GRPC_LIB}" + "${GPR_LIB}" + "${PROTOBUF_LIB}" + "${CARES_LIB}" + "${OPENSSL_LIBRARIES}" + ) endif() -if (EMSCRIPTEN) +if(EMSCRIPTEN) target_compile_options(falco_application PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0") endif() @@ -141,81 +129,78 @@ target_compile_definitions(falco_application PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) add_dependencies(falco_application ${FALCO_DEPENDENCIES}) -target_link_libraries( - falco_application - ${FALCO_LIBRARIES} -) +target_link_libraries(falco_application ${FALCO_LIBRARIES}) -target_include_directories( - falco_application - PUBLIC - ${FALCO_INCLUDE_DIRECTORIES} -) +target_include_directories(falco_application PUBLIC ${FALCO_INCLUDE_DIRECTORIES}) add_executable(falco falco.cpp) add_dependencies(falco falco_application ${FALCO_DEPENDENCIES}) target_link_libraries(falco falco_application ${FALCO_LIBRARIES}) target_include_directories(falco PUBLIC ${FALCO_INCLUDE_DIRECTORIES}) -if (EMSCRIPTEN) - target_compile_options(falco PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0") - target_link_options(falco PRIVATE "-sALLOW_MEMORY_GROWTH=1") - target_link_options(falco PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0") - target_link_options(falco PRIVATE "-sMODULARIZE=1") - target_link_options(falco PRIVATE "-sEXPORT_ES6=1") - target_link_options(falco PRIVATE "-sEXPORTED_RUNTIME_METHODS=['FS', 'callMain']") - target_link_options(falco PRIVATE "-sEXPORTED_FUNCTIONS=['_main','_htons','_ntohs']") +if(EMSCRIPTEN) + target_compile_options(falco PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0") + target_link_options(falco PRIVATE "-sALLOW_MEMORY_GROWTH=1") + target_link_options(falco PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0") + target_link_options(falco PRIVATE "-sMODULARIZE=1") + target_link_options(falco PRIVATE "-sEXPORT_ES6=1") + target_link_options(falco PRIVATE "-sEXPORTED_RUNTIME_METHODS=['FS', 'callMain']") + target_link_options(falco PRIVATE "-sEXPORTED_FUNCTIONS=['_main','_htons','_ntohs']") endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD) - add_custom_command( - OUTPUT - ${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc - ${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.h - ${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc - ${CMAKE_CURRENT_BINARY_DIR}/version.pb.h - ${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc - ${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.h - ${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc - ${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.h - ${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc - ${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h - COMMENT "Generate gRPC API" - # Falco gRPC Version API - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.proto - COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/version.proto - COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} - ${CMAKE_CURRENT_SOURCE_DIR}/version.proto - # Falco gRPC Outputs API - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto - COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto - ${CMAKE_CURRENT_SOURCE_DIR}/schema.proto - COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} - ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - ) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc + ${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.h + ${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc + ${CMAKE_CURRENT_BINARY_DIR}/version.pb.h + ${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc + ${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.h + ${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc + ${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.h + ${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc + ${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h + COMMENT "Generate gRPC API" + # Falco gRPC Version API + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.proto + COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. + ${CMAKE_CURRENT_SOURCE_DIR}/version.proto + COMMAND + ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. + --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} ${CMAKE_CURRENT_SOURCE_DIR}/version.proto + # Falco gRPC Outputs API + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto + COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. + ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto ${CMAKE_CURRENT_SOURCE_DIR}/schema.proto + COMMAND + ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. + --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) endif() # strip the Falco binary when releasing using musl if(MUSL_OPTIMIZED_BUILD AND CMAKE_BUILD_TYPE STREQUAL "release") - add_custom_command( - TARGET falco - POST_BUILD - COMMAND ${CMAKE_STRIP} --strip-unneeded falco - COMMENT "Strip the Falco binary when releasing the musl build" - ) + add_custom_command( + TARGET falco + POST_BUILD + COMMAND ${CMAKE_STRIP} --strip-unneeded falco + COMMENT "Strip the Falco binary when releasing the musl build" + ) endif() -if (EMSCRIPTEN) - install(FILES - "$/falco.js" - "$/falco.wasm" +if(EMSCRIPTEN) + install( + FILES "$/falco.js" "$/falco.wasm" DESTINATION ${FALCO_BIN_DIR} - COMPONENT "${FALCO_COMPONENT_NAME}") -elseif (WIN32) - install(TARGETS falco + COMPONENT "${FALCO_COMPONENT_NAME}" + ) +elseif(WIN32) + install( + TARGETS falco DESTINATION bin - COMPONENT "${FALCO_COMPONENT_NAME}") + COMPONENT "${FALCO_COMPONENT_NAME}" + ) else() install(TARGETS falco RUNTIME DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}") endif() diff --git a/userspace/falco/app/actions/actions.h b/userspace/falco/app/actions/actions.h index 8882d33b5a2..d0376a131d8 100644 --- a/userspace/falco/app/actions/actions.h +++ b/userspace/falco/app/actions/actions.h @@ -60,6 +60,6 @@ falco::app::run_result unregister_signal_handlers(falco::app::state& s); falco::app::run_result validate_rules_files(falco::app::state& s); falco::app::run_result close_inspectors(falco::app::state& s); -}; // namespace actions -}; // namespace app -}; // namespace falco +}; // namespace actions +}; // namespace app +}; // namespace falco diff --git a/userspace/falco/app/actions/close_inspectors.cpp b/userspace/falco/app/actions/close_inspectors.cpp index 54344ecc010..2f5a40bffa0 100644 --- a/userspace/falco/app/actions/close_inspectors.cpp +++ b/userspace/falco/app/actions/close_inspectors.cpp @@ -21,21 +21,17 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::close_inspectors(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::close_inspectors(falco::app::state& s) { falco_logger::log(falco_logger::level::DEBUG, "closing inspectors"); - if (s.offline_inspector != nullptr) - { + if(s.offline_inspector != nullptr) { s.offline_inspector->close(); } - for (const auto &src : s.loaded_sources) - { + for(const auto& src : s.loaded_sources) { auto src_info = s.source_infos.at(src); - if (src_info->inspector != nullptr) - { + if(src_info->inspector != nullptr) { src_info->inspector->close(); } } diff --git a/userspace/falco/app/actions/configure_interesting_sets.cpp b/userspace/falco/app/actions/configure_interesting_sets.cpp index 463db87ac93..914073007b9 100644 --- a/userspace/falco/app/actions/configure_interesting_sets.cpp +++ b/userspace/falco/app/actions/configure_interesting_sets.cpp @@ -23,112 +23,115 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -static void extract_base_syscalls_names( - const std::unordered_set& base_syscalls_names, - std::unordered_set& user_positive_names, - std::unordered_set& user_negative_names) -{ - for (const std::string &ev : base_syscalls_names) - { - if (!ev.empty()) - { - if (ev.at(0) == '!') - { +static void extract_base_syscalls_names(const std::unordered_set& base_syscalls_names, + std::unordered_set& user_positive_names, + std::unordered_set& user_negative_names) { + for(const std::string& ev : base_syscalls_names) { + if(!ev.empty()) { + if(ev.at(0) == '!') { user_negative_names.insert(ev.substr(1, ev.size())); - } - else - { + } else { user_positive_names.insert(ev); } } } } -static void check_for_rules_unsupported_events(falco::app::state& s, const libsinsp::events::set& rules_sc_set) -{ +static void check_for_rules_unsupported_events( + falco::app::state& s, + const libsinsp::events::set& rules_sc_set) { /* Unsupported events are those events that are used in the rules * but that are not part of the selected event set. For now, this * is expected to happen only for high volume syscalls for * performance reasons. */ auto unsupported_sc_set = rules_sc_set.diff(s.selected_sc_set); - if (unsupported_sc_set.empty()) - { + if(unsupported_sc_set.empty()) { return; } - /* Get the names of the events (syscall and non syscall events) that were not activated and print them. */ + /* Get the names of the events (syscall and non syscall events) that were not activated and + * print them. */ auto names = libsinsp::events::sc_set_to_event_names(unsupported_sc_set); - std::cerr << "Loaded rules match syscalls that are not activated (e.g. were removed via config settings such as no -A flag or negative base_syscalls elements) or unsupported with current configuration: warning (unsupported-evttype): " + concat_set_in_order(names) << std::endl; - std::cerr << "If syscalls in rules include high volume syscalls (-> activate via `-A` flag), else syscalls may have been removed via base_syscalls option or might be associated with syscalls undefined on your architecture (https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html)" << std::endl; + std::cerr << "Loaded rules match syscalls that are not activated (e.g. were removed via config " + "settings such as no -A flag or negative base_syscalls elements) or unsupported " + "with current configuration: warning (unsupported-evttype): " + + concat_set_in_order(names) + << std::endl; + std::cerr << "If syscalls in rules include high volume syscalls (-> activate via `-A` flag), " + "else syscalls may have been removed via base_syscalls option or might be " + "associated with syscalls undefined on your architecture " + "(https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html)" + << std::endl; } -static void select_event_set(falco::app::state& s, const libsinsp::events::set& rules_sc_set) -{ +static void select_event_set(falco::app::state& s, + const libsinsp::events::set& rules_sc_set) { /* PPM syscall codes (sc) can be viewed as condensed libsinsp lookup table * to map a system call name to it's actual system syscall id (as defined * by the Linux kernel). Hence here we don't need syscall enter and exit distinction. */ auto rules_names = libsinsp::events::sc_set_to_event_names(rules_sc_set); - if (!rules_sc_set.empty()) - { - falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(rules_names.size()) - + ") syscalls in rules: " + concat_set_in_order(rules_names) + "\n"); + if(!rules_sc_set.empty()) { + falco_logger::log(falco_logger::level::DEBUG, + "(" + std::to_string(rules_names.size()) + ") syscalls in rules: " + + concat_set_in_order(rules_names) + "\n"); } /* Load PPM event codes needed by plugins with parsing capability */ libsinsp::events::set plugin_ev_codes; - for (const auto &p : s.offline_inspector->get_plugin_manager()->plugins()) - { - if(!(p->caps() & CAP_PARSING)) - { + for(const auto& p : s.offline_inspector->get_plugin_manager()->plugins()) { + if(!(p->caps() & CAP_PARSING)) { continue; } plugin_ev_codes.merge(p->parse_event_codes()); } const auto plugin_sc_set = libsinsp::events::event_set_to_sc_set(plugin_ev_codes); const auto plugin_names = libsinsp::events::sc_set_to_event_names(plugin_sc_set); - if (!plugin_sc_set.empty()) - { - falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(plugin_names.size()) - + ") syscalls required by plugins: " + concat_set_in_order(plugin_names) + "\n"); + if(!plugin_sc_set.empty()) { + falco_logger::log(falco_logger::level::DEBUG, + "(" + std::to_string(plugin_names.size()) + + ") syscalls required by plugins: " + + concat_set_in_order(plugin_names) + "\n"); } - /* DEFAULT OPTION: - * Current `sinsp_state_sc_set()` approach includes multiple steps: - * (1) Enforce all positive syscalls from each Falco rule - * (2) Enforce static Falco state set (non-adaptive, not conditioned by rules, - * but based on PPME event table flags indicating generic sinsp state modifications) - * -> Final set is union of (1) and (2) - * - * Fall-back if no valid positive syscalls in `base_syscalls.custom_set`, - * e.g. when using `base_syscalls.custom_set` only for negative syscalls. - */ + * Current `sinsp_state_sc_set()` approach includes multiple steps: + * (1) Enforce all positive syscalls from each Falco rule + * (2) Enforce static Falco state set (non-adaptive, not conditioned by rules, + * but based on PPME event table flags indicating generic sinsp state modifications) + * -> Final set is union of (1) and (2) + * + * Fall-back if no valid positive syscalls in `base_syscalls.custom_set`, + * e.g. when using `base_syscalls.custom_set` only for negative syscalls. + */ auto base_sc_set = libsinsp::events::sinsp_state_sc_set(); /* USER OVERRIDE INPUT OPTION `base_syscalls.custom_set` etc. */ std::unordered_set user_positive_names = {}; std::unordered_set user_negative_names = {}; - extract_base_syscalls_names(s.config->m_base_syscalls_custom_set, user_positive_names, user_negative_names); + extract_base_syscalls_names(s.config->m_base_syscalls_custom_set, + user_positive_names, + user_negative_names); auto user_positive_sc_set = libsinsp::events::event_names_to_sc_set(user_positive_names); auto user_negative_sc_set = libsinsp::events::event_names_to_sc_set(user_negative_names); auto user_positive_sc_set_names = libsinsp::events::sc_set_to_event_names(user_positive_sc_set); - if (!user_positive_sc_set.empty()) - { + if(!user_positive_sc_set.empty()) { // user overrides base event set base_sc_set = user_positive_sc_set; // we re-transform from sc_set to names to make // sure that bad user inputs are ignored - falco_logger::log(falco_logger::level::DEBUG, "+(" + std::to_string(user_positive_sc_set_names.size()) - + ") syscalls added (base_syscalls override): " - + concat_set_in_order(user_positive_sc_set_names) + "\n"); + falco_logger::log(falco_logger::level::DEBUG, + "+(" + std::to_string(user_positive_sc_set_names.size()) + + ") syscalls added (base_syscalls override): " + + concat_set_in_order(user_positive_sc_set_names) + "\n"); } - auto invalid_positive_sc_set_names = unordered_set_difference(user_positive_names, user_positive_sc_set_names); - if (!invalid_positive_sc_set_names.empty()) - { - falco_logger::log(falco_logger::level::WARNING, "Invalid (positive) syscall names: warning (base_syscalls override): " - + concat_set_in_order(invalid_positive_sc_set_names)); + auto invalid_positive_sc_set_names = + unordered_set_difference(user_positive_names, user_positive_sc_set_names); + if(!invalid_positive_sc_set_names.empty()) { + falco_logger::log(falco_logger::level::WARNING, + "Invalid (positive) syscall names: warning (base_syscalls override): " + + concat_set_in_order(invalid_positive_sc_set_names)); } // selected events are the union of the rules events set plus @@ -136,48 +139,49 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set

m_base_syscalls_repair && user_positive_sc_set.empty()) - { - /* If `base_syscalls.repair` is specified, but `base_syscalls.custom_set` is empty we are replacing - * the default `sinsp_state_sc_set()` enforcement with the alternative `sinsp_repair_state_sc_set`. - * This approach only activates additional syscalls Falco needs beyond the - * syscalls defined in each Falco rule that are absolutely necessary based - * on the current rules configuration. */ + /* REPLACE DEFAULT STATE, nothing else. Need to override s.selected_sc_set and have a separate + * logic block. */ + if(s.config->m_base_syscalls_repair && user_positive_sc_set.empty()) { + /* If `base_syscalls.repair` is specified, but `base_syscalls.custom_set` is empty we are + * replacing the default `sinsp_state_sc_set()` enforcement with the alternative + * `sinsp_repair_state_sc_set`. This approach only activates additional syscalls Falco needs + * beyond the syscalls defined in each Falco rule that are absolutely necessary based on the + * current rules configuration. */ // returned set already has rules_sc_set merged s.selected_sc_set = libsinsp::events::sinsp_repair_state_sc_set(rules_sc_set); } auto user_negative_sc_set_names = libsinsp::events::sc_set_to_event_names(user_negative_sc_set); - if (!user_negative_sc_set.empty()) - { + if(!user_negative_sc_set.empty()) { /* Remove negative base_syscalls events. */ s.selected_sc_set = s.selected_sc_set.diff(user_negative_sc_set); // we re-transform from sc_set to names to make // sure that bad user inputs are ignored - falco_logger::log(falco_logger::level::DEBUG, "-(" + std::to_string(user_negative_sc_set_names.size()) - + ") syscalls removed (base_syscalls override): " - + concat_set_in_order(user_negative_sc_set_names) + "\n"); + falco_logger::log(falco_logger::level::DEBUG, + "-(" + std::to_string(user_negative_sc_set_names.size()) + + ") syscalls removed (base_syscalls override): " + + concat_set_in_order(user_negative_sc_set_names) + "\n"); } - auto invalid_negative_sc_set_names = unordered_set_difference(user_negative_names, user_negative_sc_set_names); - if (!invalid_negative_sc_set_names.empty()) - { - falco_logger::log(falco_logger::level::WARNING, "Invalid (negative) syscall names: warning (base_syscalls override): " - + concat_set_in_order(invalid_negative_sc_set_names)); + auto invalid_negative_sc_set_names = + unordered_set_difference(user_negative_names, user_negative_sc_set_names); + if(!invalid_negative_sc_set_names.empty()) { + falco_logger::log(falco_logger::level::WARNING, + "Invalid (negative) syscall names: warning (base_syscalls override): " + + concat_set_in_order(invalid_negative_sc_set_names)); } /* Derive the diff between the additional syscalls added via libsinsp state enforcement and the syscalls from each Falco rule. We avoid printing this in case the user specified a custom set of base syscalls */ auto non_rules_sc_set = s.selected_sc_set.diff(rules_sc_set); - if (!non_rules_sc_set.empty() && user_positive_sc_set.empty()) - { + if(!non_rules_sc_set.empty() && user_positive_sc_set.empty()) { auto non_rules_sc_set_names = libsinsp::events::sc_set_to_event_names(non_rules_sc_set); - falco_logger::log(falco_logger::level::DEBUG, "+(" + std::to_string(non_rules_sc_set_names.size()) - + ") syscalls (Falco's state engine set of syscalls): " - + concat_set_in_order(non_rules_sc_set_names) + "\n"); + falco_logger::log(falco_logger::level::DEBUG, + "+(" + std::to_string(non_rules_sc_set_names.size()) + + ") syscalls (Falco's state engine set of syscalls): " + + concat_set_in_order(non_rules_sc_set_names) + "\n"); } /* -A flag behavior: @@ -185,24 +189,22 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set

activate via `-A` flag): " - + concat_set_in_order(erased_sc_set_names) + "\n"); + falco_logger::log(falco_logger::level::DEBUG, + "-(" + std::to_string(erased_sc_set_names.size()) + + ") ignored syscalls (-> activate via `-A` flag): " + + concat_set_in_order(erased_sc_set_names) + "\n"); } } /* If a custom set is specified (positive, negative, or both), we attempt * to repair it if configured to do so. */ - if (s.config->m_base_syscalls_repair && !s.config->m_base_syscalls_custom_set.empty()) - { + if(s.config->m_base_syscalls_repair && !s.config->m_base_syscalls_custom_set.empty()) { /* If base_syscalls.repair is specified enforce state using `sinsp_repair_state_sc_set`. * This approach is an alternative to the default `sinsp_state_sc_set()` state enforcement * and only activates additional syscalls Falco needs beyond the syscalls defined in the @@ -210,11 +212,12 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set

m_modern_ebpf.m_cpus_for_each_buffer > online_cpus) - { - falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n"); + if(s.config->m_modern_ebpf.m_cpus_for_each_buffer > online_cpus) { + falco_logger::log(falco_logger::level::WARNING, + "you required a buffer every '" + + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_buffer) + + "' CPUs but there are only '" + std::to_string(online_cpus) + + "' online CPUs. Falco changed the config to: one buffer every '" + + std::to_string(online_cpus) + "' CPUs\n"); s.config->m_modern_ebpf.m_cpus_for_each_buffer = online_cpus; } #endif diff --git a/userspace/falco/app/actions/configure_syscall_buffer_size.cpp b/userspace/falco/app/actions/configure_syscall_buffer_size.cpp index ca1cdae70ee..d675992eba1 100644 --- a/userspace/falco/app/actions/configure_syscall_buffer_size.cpp +++ b/userspace/falco/app/actions/configure_syscall_buffer_size.cpp @@ -25,49 +25,69 @@ using namespace falco::app::actions; #define MAX_INDEX 10 #define DEFAULT_BYTE_SIZE 1 << 23 -falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco::app::state& s) { #ifdef __linux__ auto index = s.driver_buf_size_preset(); - if (index == -1) - { + if(index == -1) { // Chosen driver kind does not support this option. return run_result::ok(); } - if(index < MIN_INDEX || index > MAX_INDEX) - { - return run_result::fatal("The 'buf_size_preset' value must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n"); + if(index < MIN_INDEX || index > MAX_INDEX) { + return run_result::fatal("The 'buf_size_preset' value must be between '" + + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + + "'\n"); } /* Sizes from `1 MB` to `512 MB`. The index `0` is reserved, users cannot use it! */ - std::vector vect{0, 1 << 20, 1 << 21, 1 << 22, DEFAULT_BYTE_SIZE, 1 << 24, 1 << 25, 1 << 26, 1 << 27, 1 << 28, 1 << 29}; + std::vector vect{0, + 1 << 20, + 1 << 21, + 1 << 22, + DEFAULT_BYTE_SIZE, + 1 << 24, + 1 << 25, + 1 << 26, + 1 << 27, + 1 << 28, + 1 << 29}; uint64_t chosen_size = vect[index]; /* If the page size is not valid we return here. */ long page_size = getpagesize(); - if(page_size <= 0) - { + if(page_size <= 0) { s.syscall_buffer_bytes_size = DEFAULT_BYTE_SIZE; - falco_logger::log(falco_logger::level::WARNING, "Unable to get the system page size through 'getpagesize()'. Try to use the default syscall buffer dimension: " + std::to_string(DEFAULT_BYTE_SIZE) + " bytes\n"); + falco_logger::log(falco_logger::level::WARNING, + "Unable to get the system page size through 'getpagesize()'. Try to use " + "the default syscall buffer dimension: " + + std::to_string(DEFAULT_BYTE_SIZE) + " bytes\n"); return run_result::ok(); } /* Check if the chosen size is a multiple of the page size. */ - if(chosen_size % page_size != 0) - { - return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not a multiple of your system page size '" + std::to_string(page_size) + "'. Please configure a greater 'buf_size_preset' value in the Falco configuration file\n"); + if(chosen_size % page_size != 0) { + return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + + "' is not a multiple of your system page size '" + + std::to_string(page_size) + + "'. Please configure a greater 'buf_size_preset' value in the " + "Falco configuration file\n"); } /* Check if the chosen size is greater than `2 * page_size`. */ - if((chosen_size / page_size) <= 2) - { - return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not greater than '2 * " + std::to_string(page_size) + "' where '" + std::to_string(page_size) + "' is your system page size. Please configure a greater 'buf_size_preset' value in the Falco configuration file\n"); + if((chosen_size / page_size) <= 2) { + return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + + "' is not greater than '2 * " + std::to_string(page_size) + + "' where '" + std::to_string(page_size) + + "' is your system page size. Please configure a greater " + "'buf_size_preset' value in the Falco configuration file\n"); } s.syscall_buffer_bytes_size = chosen_size; - falco_logger::log(falco_logger::level::INFO, "The chosen syscall buffer dimension is: " + std::to_string(chosen_size) + " bytes (" + std::to_string(chosen_size / (uint64_t)(1024 * 1024)) + " MBs)\n"); - -#endif // __linux__ + falco_logger::log(falco_logger::level::INFO, + "The chosen syscall buffer dimension is: " + std::to_string(chosen_size) + + " bytes (" + std::to_string(chosen_size / (uint64_t)(1024 * 1024)) + + " MBs)\n"); + +#endif // __linux__ return run_result::ok(); } diff --git a/userspace/falco/app/actions/create_requested_paths.cpp b/userspace/falco/app/actions/create_requested_paths.cpp index 2698628f3b1..b64168a1104 100644 --- a/userspace/falco/app/actions/create_requested_paths.cpp +++ b/userspace/falco/app/actions/create_requested_paths.cpp @@ -25,55 +25,43 @@ using namespace falco::app::actions; static int create_dir(const std::string &path); -falco::app::run_result falco::app::actions::create_requested_paths(falco::app::state& s) -{ - if(s.is_gvisor()) - { +falco::app::run_result falco::app::actions::create_requested_paths(falco::app::state &s) { + if(s.is_gvisor()) { // This is bad: parsing gvisor config to get endpoint // to be able to auto-create the path to the file for the user. std::ifstream reader(s.config->m_gvisor.m_config); - if (reader.fail()) - { + if(reader.fail()) { return run_result::fatal(s.config->m_gvisor.m_config + ": cannot open file"); } nlohmann::json parsed_json; std::string gvisor_socket; - try - { + try { parsed_json = nlohmann::json::parse(reader); - } - catch (const std::exception &e) - { - return run_result::fatal(s.config->m_gvisor.m_config + ": cannot parse JSON: " + e.what()); + } catch(const std::exception &e) { + return run_result::fatal(s.config->m_gvisor.m_config + + ": cannot parse JSON: " + e.what()); } - try - { + try { gvisor_socket = parsed_json["trace_session"]["sinks"][0]["config"]["endpoint"]; - } - catch (const std::exception &e) - { - return run_result::fatal(s.config->m_gvisor.m_config + ": failed to fetch config.endpoint: " + e.what()); + } catch(const std::exception &e) { + return run_result::fatal(s.config->m_gvisor.m_config + + ": failed to fetch config.endpoint: " + e.what()); } int ret = create_dir(gvisor_socket); - if (ret != 0) - { + if(ret != 0) { return run_result::fatal(gvisor_socket + ": " + strerror(errno)); } } - if (s.config->m_grpc_enabled && !s.config->m_grpc_bind_address.empty()) - { - if(falco::utils::network::is_unix_scheme(s.config->m_grpc_bind_address)) - { + if(s.config->m_grpc_enabled && !s.config->m_grpc_bind_address.empty()) { + if(falco::utils::network::is_unix_scheme(s.config->m_grpc_bind_address)) { auto server_path = s.config->m_grpc_bind_address.substr( - falco::utils::network::UNIX_SCHEME.length() - ); + falco::utils::network::UNIX_SCHEME.length()); int ret = create_dir(server_path); - if(ret != 0) - { + if(ret != 0) { return run_result::fatal(server_path + ": " + strerror(errno)); } } @@ -86,17 +74,14 @@ falco::app::run_result falco::app::actions::create_requested_paths(falco::app::s // This function operates like `mkdir -p` excluding the last part of // the path which we assume to be the filename. -static int create_dir(const std::string &path) -{ - - std::filesystem::path dirPath(path); +static int create_dir(const std::string &path) { + std::filesystem::path dirPath(path); - try { - std::filesystem::create_directories(dirPath.parent_path()); - } catch (const std::exception& ex) { + try { + std::filesystem::create_directories(dirPath.parent_path()); + } catch(const std::exception &ex) { return -1; - } - - return 0; + } + return 0; } diff --git a/userspace/falco/app/actions/create_signal_handlers.cpp b/userspace/falco/app/actions/create_signal_handlers.cpp index 5547ec13588..0db702081ba 100644 --- a/userspace/falco/app/actions/create_signal_handlers.cpp +++ b/userspace/falco/app/actions/create_signal_handlers.cpp @@ -23,60 +23,50 @@ limitations under the License. #ifdef __linux__ #include -#endif // __linux__ +#endif // __linux__ using namespace falco::app; using namespace falco::app::actions; static std::shared_ptr s_restarter; -static void terminate_signal_handler(int signal) -{ +static void terminate_signal_handler(int signal) { falco::app::g_terminate_signal.trigger(); } -static void reopen_outputs_signal_handler(int signal) -{ +static void reopen_outputs_signal_handler(int signal) { falco::app::g_reopen_outputs_signal.trigger(); } -static void restart_signal_handler(int signal) -{ - if (s_restarter != nullptr) - { +static void restart_signal_handler(int signal) { + if(s_restarter != nullptr) { s_restarter->trigger(); } } -bool create_handler(int sig, void (*func)(int), run_result &ret) -{ +bool create_handler(int sig, void (*func)(int), run_result& ret) { ret = run_result::ok(); #ifdef __linux__ - if(signal(sig, func) == SIG_ERR) - { + if(signal(sig, func) == SIG_ERR) { char errbuf[1024]; - if (strerror_r(errno, errbuf, sizeof(errbuf)) != 0) - { - snprintf(errbuf, sizeof(errbuf)-1, "Errno %d", errno); + if(strerror_r(errno, errbuf, sizeof(errbuf)) != 0) { + snprintf(errbuf, sizeof(errbuf) - 1, "Errno %d", errno); } ret = run_result::fatal(std::string("Could not create signal handler for ") + - strsignal(sig) + - ": " + - errbuf); + strsignal(sig) + ": " + errbuf); } #endif return ret.success; } -falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::state& s) { auto ret = run_result::ok(); #ifdef __linux__ - if (s.options.dry_run) - { - falco_logger::log(falco_logger::level::DEBUG, "Skipping signal handlers creation in dry-run\n"); + if(s.options.dry_run) { + falco_logger::log(falco_logger::level::DEBUG, + "Skipping signal handlers creation in dry-run\n"); return run_result::ok(); } @@ -84,79 +74,71 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s falco::app::g_restart_signal.reset(); falco::app::g_reopen_outputs_signal.reset(); - if (!g_terminate_signal.is_lock_free() - || !g_restart_signal.is_lock_free() - || !g_reopen_outputs_signal.is_lock_free()) - { - falco_logger::log(falco_logger::level::WARNING, "Bundled atomics implementation is not lock-free, signal handlers may be unstable\n"); + if(!g_terminate_signal.is_lock_free() || !g_restart_signal.is_lock_free() || + !g_reopen_outputs_signal.is_lock_free()) { + falco_logger::log(falco_logger::level::WARNING, + "Bundled atomics implementation is not lock-free, signal handlers may be " + "unstable\n"); } - if(! create_handler(SIGINT, ::terminate_signal_handler, ret) || - ! create_handler(SIGTERM, ::terminate_signal_handler, ret) || - ! create_handler(SIGUSR1, ::reopen_outputs_signal_handler, ret) || - ! create_handler(SIGHUP, ::restart_signal_handler, ret)) - { + if(!create_handler(SIGINT, ::terminate_signal_handler, ret) || + !create_handler(SIGTERM, ::terminate_signal_handler, ret) || + !create_handler(SIGUSR1, ::reopen_outputs_signal_handler, ret) || + !create_handler(SIGHUP, ::restart_signal_handler, ret)) { return ret; } falco::app::restart_handler::watch_list_t files_to_watch; falco::app::restart_handler::watch_list_t dirs_to_watch; - if (s.config->m_watch_config_files) - { - files_to_watch.insert( - files_to_watch.end(), - s.config->m_loaded_configs_filenames.begin(), - s.config->m_loaded_configs_filenames.end()); - dirs_to_watch.insert( - dirs_to_watch.end(), - s.config->m_loaded_configs_folders.begin(), - s.config->m_loaded_configs_folders.end()); - files_to_watch.insert( - files_to_watch.end(), - s.config->m_loaded_rules_filenames.begin(), - s.config->m_loaded_rules_filenames.end()); - dirs_to_watch.insert( - dirs_to_watch.end(), - s.config->m_loaded_rules_folders.begin(), - s.config->m_loaded_rules_folders.end()); + if(s.config->m_watch_config_files) { + files_to_watch.insert(files_to_watch.end(), + s.config->m_loaded_configs_filenames.begin(), + s.config->m_loaded_configs_filenames.end()); + dirs_to_watch.insert(dirs_to_watch.end(), + s.config->m_loaded_configs_folders.begin(), + s.config->m_loaded_configs_folders.end()); + files_to_watch.insert(files_to_watch.end(), + s.config->m_loaded_rules_filenames.begin(), + s.config->m_loaded_rules_filenames.end()); + dirs_to_watch.insert(dirs_to_watch.end(), + s.config->m_loaded_rules_folders.begin(), + s.config->m_loaded_rules_folders.end()); } - s.restarter = std::make_shared([&s]{ - bool tmp = false; - bool success = false; - std::string err; - falco::app::state tmp_state(s.cmdline, s.options); - tmp_state.options.dry_run = true; - try - { - success = falco::app::run(tmp_state, tmp, err); - } - catch (std::exception& e) - { - err = e.what(); - } - catch (...) - { - err = "unknown error"; - } - - if (!success && s.outputs != nullptr) - { - std::string rule = "Falco internal: hot restart failure"; - std::string msg = rule + ": " + err; - auto fields = nlohmann::json::object(); - auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - s.outputs->handle_msg(now, falco_common::PRIORITY_CRITICAL, msg, rule, fields); - } - - return success; - }, files_to_watch, dirs_to_watch); + s.restarter = std::make_shared( + [&s] { + bool tmp = false; + bool success = false; + std::string err; + falco::app::state tmp_state(s.cmdline, s.options); + tmp_state.options.dry_run = true; + try { + success = falco::app::run(tmp_state, tmp, err); + } catch(std::exception& e) { + err = e.what(); + } catch(...) { + err = "unknown error"; + } + + if(!success && s.outputs != nullptr) { + std::string rule = "Falco internal: hot restart failure"; + std::string msg = rule + ": " + err; + auto fields = nlohmann::json::object(); + auto now = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + s.outputs->handle_msg(now, falco_common::PRIORITY_CRITICAL, msg, rule, fields); + } + + return success; + }, + files_to_watch, + dirs_to_watch); ret = run_result::ok(); ret.success = s.restarter->start(ret.errstr); ret.proceed = ret.success; - if (ret.success) - { + if(ret.success) { s_restarter = s.restarter; } #endif @@ -164,30 +146,25 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s return ret; } -falco::app::run_result falco::app::actions::unregister_signal_handlers(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::unregister_signal_handlers(falco::app::state& s) { #ifdef __linux__ - if (s.options.dry_run) - { - falco_logger::log(falco_logger::level::DEBUG, "Skipping unregistering signal handlers in dry-run\n"); + if(s.options.dry_run) { + falco_logger::log(falco_logger::level::DEBUG, + "Skipping unregistering signal handlers in dry-run\n"); return run_result::ok(); } s_restarter = nullptr; - if (s.restarter != nullptr) - { + if(s.restarter != nullptr) { s.restarter->stop(); } run_result ret; - if(! create_handler(SIGINT, SIG_DFL, ret) || - ! create_handler(SIGTERM, SIG_DFL, ret) || - ! create_handler(SIGUSR1, SIG_DFL, ret) || - ! create_handler(SIGHUP, SIG_DFL, ret)) - { + if(!create_handler(SIGINT, SIG_DFL, ret) || !create_handler(SIGTERM, SIG_DFL, ret) || + !create_handler(SIGUSR1, SIG_DFL, ret) || !create_handler(SIGHUP, SIG_DFL, ret)) { return ret; } -#endif // __linux__ +#endif // __linux__ return run_result::ok(); } diff --git a/userspace/falco/app/actions/helpers.h b/userspace/falco/app/actions/helpers.h index 69562bf23dd..aa03a099626 100644 --- a/userspace/falco/app/actions/helpers.h +++ b/userspace/falco/app/actions/helpers.h @@ -28,35 +28,33 @@ namespace actions { bool check_rules_plugin_requirements(falco::app::state& s, std::string& err); void print_enabled_event_sources(falco::app::state& s); -void activate_interesting_kernel_tracepoints(falco::app::state& s, std::unique_ptr& inspector); +void activate_interesting_kernel_tracepoints(falco::app::state& s, + std::unique_ptr& inspector); void check_for_ignored_events(falco::app::state& s); void format_plugin_info(std::shared_ptr p, std::ostream& os); void format_described_rules_as_text(const nlohmann::json& v, std::ostream& os); falco::app::run_result open_offline_inspector(falco::app::state& s); -falco::app::run_result open_live_inspector( - falco::app::state& s, - std::shared_ptr inspector, - const std::string& source); +falco::app::run_result open_live_inspector(falco::app::state& s, + std::shared_ptr inspector, + const std::string& source); template -void read_files(InputIterator begin, InputIterator end, - std::vector& rules_contents, - falco::load_result::rules_contents_t& rc) -{ +void read_files(InputIterator begin, + InputIterator end, + std::vector& rules_contents, + falco::load_result::rules_contents_t& rc) { // Read the contents in a first pass - for(auto it = begin; it != end; it++) - { - const std::string &filename = *it; + for(auto it = begin; it != end; it++) { + const std::string& filename = *it; std::ifstream is; is.open(filename); - if (!is.is_open()) - { + if(!is.is_open()) { throw falco_exception("Could not open file " + filename + " for reading"); } std::string rules_content((std::istreambuf_iterator(is)), - std::istreambuf_iterator()); + std::istreambuf_iterator()); rules_contents.emplace_back(std::move(rules_content)); } @@ -64,20 +62,17 @@ void read_files(InputIterator begin, InputIterator end, // references becoming invalid. auto it = begin; auto rit = rules_contents.begin(); - for(; it != end && rit != rules_contents.end(); it++, rit++) - { + for(; it != end && rit != rules_contents.end(); it++, rit++) { rc.emplace(*it, *rit); } // Both it and rit must be at the end, otherwise // there's a bug in the above - if(it != end || rit != rules_contents.end()) - { + if(it != end || rit != rules_contents.end()) { throw falco_exception("Unexpected mismatch in rules content name/rules content sets?"); } } - -}; // namespace actions -}; // namespace app -}; // namespace falco +}; // namespace actions +}; // namespace app +}; // namespace falco diff --git a/userspace/falco/app/actions/helpers_generic.cpp b/userspace/falco/app/actions/helpers_generic.cpp index 4022eb04d3f..cba0231febf 100644 --- a/userspace/falco/app/actions/helpers_generic.cpp +++ b/userspace/falco/app/actions/helpers_generic.cpp @@ -24,27 +24,23 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -bool falco::app::actions::check_rules_plugin_requirements(falco::app::state& s, std::string& err) -{ +bool falco::app::actions::check_rules_plugin_requirements(falco::app::state& s, std::string& err) { // Ensure that all plugins are compatible with the loaded set of rules // note: offline inspector contains all the loaded plugins std::vector plugin_reqs; - for (const auto &plugin : s.offline_inspector->get_plugin_manager()->plugins()) - { + for(const auto& plugin : s.offline_inspector->get_plugin_manager()->plugins()) { falco_engine::plugin_version_requirement req; req.name = plugin->name(); req.version = plugin->plugin_version().as_string(); plugin_reqs.push_back(req); - } + } return s.engine->check_plugin_requirements(plugin_reqs, err); } -void falco::app::actions::print_enabled_event_sources(falco::app::state& s) -{ +void falco::app::actions::print_enabled_event_sources(falco::app::state& s) { /* Print all loaded sources. */ std::string str; - for (const auto &src : s.loaded_sources) - { + for(const auto& src : s.loaded_sources) { str += str.empty() ? "" : ", "; str += src; } @@ -52,96 +48,80 @@ void falco::app::actions::print_enabled_event_sources(falco::app::state& s) /* Print all enabled sources. */ str.clear(); - for (const auto &src : s.enabled_sources) - { + for(const auto& src : s.enabled_sources) { str += str.empty() ? "" : ", "; str += src; } falco_logger::log(falco_logger::level::INFO, "Enabled event sources: " + str); // print some warnings to the user - for (const auto& src : s.enabled_sources) - { + for(const auto& src : s.enabled_sources) { std::shared_ptr first_plugin = nullptr; const auto& plugins = s.offline_inspector->get_plugin_manager()->plugins(); - for (const auto& p : plugins) - { - if ((p->caps() & CAP_SOURCING) - && ((p->id() != 0 && src == p->event_source()) - || (p->id() == 0 && src == falco_common::syscall_source))) - { - if (first_plugin == nullptr) - { + for(const auto& p : plugins) { + if((p->caps() & CAP_SOURCING) && + ((p->id() != 0 && src == p->event_source()) || + (p->id() == 0 && src == falco_common::syscall_source))) { + if(first_plugin == nullptr) { first_plugin = p; - } - else - { - if (src != falco_common::syscall_source || s.is_nodriver()) - { - falco_logger::log(falco_logger::level::WARNING, "Enabled event source '" - + src + "' can be opened with multiple loaded plugins, will use only '" - + first_plugin->name() + "'"); + } else { + if(src != falco_common::syscall_source || s.is_nodriver()) { + falco_logger::log(falco_logger::level::WARNING, + "Enabled event source '" + src + + "' can be opened with multiple loaded plugins, " + "will use only '" + + first_plugin->name() + "'"); } } } } - if (!first_plugin && s.is_nodriver()) - { - falco_logger::log(falco_logger::level::WARNING, "Enabled event source '" - + src + "' will be opened with no driver, no event will be produced"); + if(!first_plugin && s.is_nodriver()) { + falco_logger::log(falco_logger::level::WARNING, + "Enabled event source '" + src + + "' will be opened with no driver, no event will be produced"); } } } -void falco::app::actions::format_plugin_info(std::shared_ptr p, std::ostream& os) -{ +void falco::app::actions::format_plugin_info(std::shared_ptr p, std::ostream& os) { os << "Name: " << p->name() << std::endl; os << "Description: " << p->description() << std::endl; os << "Contact: " << p->contact() << std::endl; os << "Version: " << p->plugin_version().as_string() << std::endl; os << "Capabilities: " << std::endl; - if(p->caps() & CAP_SOURCING) - { + if(p->caps() & CAP_SOURCING) { os << " - Event Sourcing"; - if (p->id() != 0) - { + if(p->id() != 0) { os << " (ID=" << p->id(); os << ", source='" << p->event_source() << "')"; - } - else - { + } else { os << " (system events)"; } os << std::endl; } - if(p->caps() & CAP_EXTRACTION) - { + if(p->caps() & CAP_EXTRACTION) { os << " - Field Extraction" << std::endl; } - if(p->caps() & CAP_PARSING) - { + if(p->caps() & CAP_PARSING) { os << " - Event Parsing" << std::endl; } - if(p->caps() & CAP_ASYNC) - { + if(p->caps() & CAP_ASYNC) { os << " - Async Events" << std::endl; } } -static void format_two_columns(std::ostream& os, const std::string& l, const std::string& r) -{ +static void format_two_columns(std::ostream& os, const std::string& l, const std::string& r) { static constexpr const int s_max_line_len = 4096; char buf[s_max_line_len]; snprintf(buf, sizeof(buf) - 1, "%-50s %s", l.c_str(), r.c_str()); os << buf << std::endl; } -void falco::app::actions::format_described_rules_as_text(const nlohmann::json& v, std::ostream& os) -{ +void falco::app::actions::format_described_rules_as_text(const nlohmann::json& v, + std::ostream& os) { format_two_columns(os, "Rule", "Description"); - format_two_columns(os, "----", "-----------"); - for(const auto &r : v["rules"]) - { + format_two_columns(os, "----", "-----------"); + for(const auto& r : v["rules"]) { auto str = falco::utils::wrap_text(r["info"]["description"], 51, 110) + "\n"; format_two_columns(os, r["info"]["name"], str); } diff --git a/userspace/falco/app/actions/helpers_inspector.cpp b/userspace/falco/app/actions/helpers_inspector.cpp index 765844524e7..62dd59694bb 100644 --- a/userspace/falco/app/actions/helpers_inspector.cpp +++ b/userspace/falco/app/actions/helpers_inspector.cpp @@ -27,106 +27,113 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::open_offline_inspector(falco::app::state& s) -{ - try - { +falco::app::run_result falco::app::actions::open_offline_inspector(falco::app::state& s) { + try { s.offline_inspector->open_savefile(s.config->m_replay.m_capture_file); - falco_logger::log(falco_logger::level::INFO, "Replaying events from the capture file: " + s.config->m_replay.m_capture_file + "\n"); + falco_logger::log(falco_logger::level::INFO, + "Replaying events from the capture file: " + + s.config->m_replay.m_capture_file + "\n"); return run_result::ok(); - } - catch (sinsp_exception &e) - { - return run_result::fatal("Could not open trace filename " + s.config->m_replay.m_capture_file + " for reading: " + e.what()); + } catch(sinsp_exception& e) { + return run_result::fatal("Could not open trace filename " + + s.config->m_replay.m_capture_file + " for reading: " + e.what()); } } -falco::app::run_result falco::app::actions::open_live_inspector( - falco::app::state& s, - std::shared_ptr inspector, - const std::string& source) -{ - try - { - if(s.config->m_falco_libs_thread_table_size > 0) - { +falco::app::run_result falco::app::actions::open_live_inspector(falco::app::state& s, + std::shared_ptr inspector, + const std::string& source) { + try { + if(s.config->m_falco_libs_thread_table_size > 0) { // Default value is set in libs as part of the sinsp_thread_manager setup - inspector->m_thread_manager->set_max_thread_table_size(s.config->m_falco_libs_thread_table_size); + inspector->m_thread_manager->set_max_thread_table_size( + s.config->m_falco_libs_thread_table_size); } - if (source != falco_common::syscall_source) /* Plugin engine */ + if(source != falco_common::syscall_source) /* Plugin engine */ { - for (const auto& p: inspector->get_plugin_manager()->plugins()) - { + for(const auto& p : inspector->get_plugin_manager()->plugins()) { // note: if more than one loaded plugin supports the given // event source, only the first one will be opened, following // the loading order specified in the Falco config. - if (p->caps() & CAP_SOURCING && p->id() != 0 && p->event_source() == source) - { + if(p->caps() & CAP_SOURCING && p->id() != 0 && p->event_source() == source) { auto cfg = s.plugin_configs.at(p->name()); - falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with plugin '" + cfg->m_name + "'"); - inspector->open_plugin(cfg->m_name, cfg->m_open_params, sinsp_plugin_platform::SINSP_PLATFORM_HOSTINFO); + falco_logger::log( + falco_logger::level::INFO, + "Opening '" + source + "' source with plugin '" + cfg->m_name + "'"); + inspector->open_plugin(cfg->m_name, + cfg->m_open_params, + sinsp_plugin_platform::SINSP_PLATFORM_HOSTINFO); return run_result::ok(); } } return run_result::fatal("Can't find plugin for event source: " + source); - } - else if (s.is_nodriver()) /* nodriver engine. */ + } else if(s.is_nodriver()) /* nodriver engine. */ { // when opening a capture with no driver, Falco will first check // if a plugin is capable of generating raw events from the libscap // event table (including system events), and if none is found it // will use the nodriver engine. - for (const auto& p: inspector->get_plugin_manager()->plugins()) - { - if (p->caps() & CAP_SOURCING && p->id() == 0) - { + for(const auto& p : inspector->get_plugin_manager()->plugins()) { + if(p->caps() & CAP_SOURCING && p->id() == 0) { auto cfg = s.plugin_configs.at(p->name()); - falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with plugin '" + cfg->m_name + "'"); - inspector->open_plugin(cfg->m_name, cfg->m_open_params, sinsp_plugin_platform::SINSP_PLATFORM_FULL); + falco_logger::log( + falco_logger::level::INFO, + "Opening '" + source + "' source with plugin '" + cfg->m_name + "'"); + inspector->open_plugin(cfg->m_name, + cfg->m_open_params, + sinsp_plugin_platform::SINSP_PLATFORM_FULL); return run_result::ok(); } } - falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with no driver\n"); + falco_logger::log(falco_logger::level::INFO, + "Opening '" + source + "' source with no driver\n"); inspector->open_nodriver(); - } - else if(s.is_gvisor()) /* gvisor engine. */ + } else if(s.is_gvisor()) /* gvisor engine. */ { - falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.config->m_gvisor.m_config); + falco_logger::log(falco_logger::level::INFO, + "Opening '" + source + "' source with gVisor. Configuration path: " + + s.config->m_gvisor.m_config); inspector->open_gvisor(s.config->m_gvisor.m_config, s.config->m_gvisor.m_root); - } - else if(s.is_modern_ebpf()) /* modern BPF engine. */ + } else if(s.is_modern_ebpf()) /* modern BPF engine. */ { - falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with modern BPF probe."); - falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_buffer) + "' CPUs."); - inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_modern_ebpf.m_cpus_for_each_buffer, true, s.selected_sc_set); - } - else if(s.is_ebpf()) /* BPF engine. */ + falco_logger::log(falco_logger::level::INFO, + "Opening '" + source + "' source with modern BPF probe."); + falco_logger::log( + falco_logger::level::INFO, + "One ring buffer every '" + + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_buffer) + + "' CPUs."); + inspector->open_modern_bpf(s.syscall_buffer_bytes_size, + s.config->m_modern_ebpf.m_cpus_for_each_buffer, + true, + s.selected_sc_set); + } else if(s.is_ebpf()) /* BPF engine. */ { - falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with BPF probe. BPF probe path: " + s.config->m_ebpf.m_probe_path); - inspector->open_bpf(s.config->m_ebpf.m_probe_path.c_str(), s.syscall_buffer_bytes_size, s.selected_sc_set); - } - else /* Kernel module (default). */ + falco_logger::log(falco_logger::level::INFO, + "Opening '" + source + "' source with BPF probe. BPF probe path: " + + s.config->m_ebpf.m_probe_path); + inspector->open_bpf(s.config->m_ebpf.m_probe_path.c_str(), + s.syscall_buffer_bytes_size, + s.selected_sc_set); + } else /* Kernel module (default). */ { - try - { - falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with Kernel module"); + try { + falco_logger::log(falco_logger::level::INFO, + "Opening '" + source + "' source with Kernel module"); inspector->open_kmod(s.syscall_buffer_bytes_size, s.selected_sc_set); - } - catch(sinsp_exception &e) - { + } catch(sinsp_exception& e) { // Try to insert the Falco kernel module - falco_logger::log(falco_logger::level::INFO, "Trying to inject the Kernel module and opening the capture again..."); - if(system("modprobe " DRIVER_NAME " > /dev/null 2> /dev/null")) - { + falco_logger::log( + falco_logger::level::INFO, + "Trying to inject the Kernel module and opening the capture again..."); + if(system("modprobe " DRIVER_NAME " > /dev/null 2> /dev/null")) { falco_logger::log(falco_logger::level::ERR, "Unable to load the driver\n"); } inspector->open_kmod(s.syscall_buffer_bytes_size, s.selected_sc_set); } } - } - catch (sinsp_exception &e) - { + } catch(sinsp_exception& e) { return run_result::fatal(e.what()); } diff --git a/userspace/falco/app/actions/init_falco_engine.cpp b/userspace/falco/app/actions/init_falco_engine.cpp index 483f827ca37..b44435ef4a4 100644 --- a/userspace/falco/app/actions/init_falco_engine.cpp +++ b/userspace/falco/app/actions/init_falco_engine.cpp @@ -22,55 +22,68 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -void configure_output_format(falco::app::state& s) -{ - for (auto& eo : s.config->m_append_output) - { - if (eo.m_format != "") - { - s.engine->add_extra_output_format(eo.m_format, eo.m_source, eo.m_tags, eo.m_rule, false); +void configure_output_format(falco::app::state& s) { + for(auto& eo : s.config->m_append_output) { + if(eo.m_format != "") { + s.engine->add_extra_output_format(eo.m_format, + eo.m_source, + eo.m_tags, + eo.m_rule, + false); } - for (auto const& ff : eo.m_formatted_fields) - { - s.engine->add_extra_output_formatted_field(ff.first, ff.second, eo.m_source, eo.m_tags, eo.m_rule); + for(auto const& ff : eo.m_formatted_fields) { + s.engine->add_extra_output_formatted_field(ff.first, + ff.second, + eo.m_source, + eo.m_tags, + eo.m_rule); } - for (auto const& rf : eo.m_raw_fields) - { + for(auto const& rf : eo.m_raw_fields) { s.engine->add_extra_output_raw_field(rf, eo.m_source, eo.m_tags, eo.m_rule); } } // See https://falco.org/docs/rules/style-guide/ - const std::string container_info = "container_id=%container.id container_image=%container.image.repository container_image_tag=%container.image.tag container_name=%container.name"; + const std::string container_info = + "container_id=%container.id container_image=%container.image.repository " + "container_image_tag=%container.image.tag container_name=%container.name"; const std::string k8s_info = "k8s_ns=%k8s.ns.name k8s_pod_name=%k8s.pod.name"; const std::string gvisor_info = "vpid=%proc.vpid vtid=%thread.vtid"; - if(s.options.print_additional == "c" || s.options.print_additional == "container") - { - s.engine->add_extra_output_format(container_info, falco_common::syscall_source, {}, "", true); - } - else if(s.options.print_additional == "cg" || s.options.print_additional == "container-gvisor") - { - s.engine->add_extra_output_format(gvisor_info + " " + container_info, falco_common::syscall_source, {}, "", true); - } - else if(s.options.print_additional == "k" || s.options.print_additional == "kubernetes") - { - s.engine->add_extra_output_format(container_info + " " + k8s_info, falco_common::syscall_source, {}, "", true); - } - else if(s.options.print_additional == "kg" || s.options.print_additional == "kubernetes-gvisor") - { - s.engine->add_extra_output_format(gvisor_info + " " + container_info + " " + k8s_info, falco_common::syscall_source, {}, "", true); - } - else if(!s.options.print_additional.empty()) - { + if(s.options.print_additional == "c" || s.options.print_additional == "container") { + s.engine->add_extra_output_format(container_info, + falco_common::syscall_source, + {}, + "", + true); + } else if(s.options.print_additional == "cg" || + s.options.print_additional == "container-gvisor") { + s.engine->add_extra_output_format(gvisor_info + " " + container_info, + falco_common::syscall_source, + {}, + "", + true); + } else if(s.options.print_additional == "k" || s.options.print_additional == "kubernetes") { + s.engine->add_extra_output_format(container_info + " " + k8s_info, + falco_common::syscall_source, + {}, + "", + true); + } else if(s.options.print_additional == "kg" || + s.options.print_additional == "kubernetes-gvisor") { + s.engine->add_extra_output_format(gvisor_info + " " + container_info + " " + k8s_info, + falco_common::syscall_source, + {}, + "", + true); + } else if(!s.options.print_additional.empty()) { s.engine->add_extra_output_format(s.options.print_additional, "", {}, "", false); } } -void add_source_to_engine(falco::app::state& s, const std::string& src) -{ +void add_source_to_engine(falco::app::state& s, const std::string& src) { auto src_info = s.source_infos.at(src); auto& filterchecks = *src_info->filterchecks; auto* inspector = src_info->inspector.get(); @@ -78,26 +91,22 @@ void add_source_to_engine(falco::app::state& s, const std::string& src) auto filter_factory = std::make_shared(inspector, filterchecks); auto formatter_factory = std::make_shared(inspector, filterchecks); - if(s.config->m_json_output) - { + if(s.config->m_json_output) { formatter_factory->set_output_format(sinsp_evt_formatter::OF_JSON); } src_info->engine_idx = s.engine->add_source(src, filter_factory, formatter_factory); } -falco::app::run_result falco::app::actions::init_falco_engine(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::init_falco_engine(falco::app::state& s) { // add syscall as first source, this is also what each inspector do // in their own list of registered event sources add_source_to_engine(s, falco_common::syscall_source); // add all non-syscall event sources in engine - for (const auto& src : s.loaded_sources) - { + for(const auto& src : s.loaded_sources) { // we skip the syscall source because we already added it - if (src != falco_common::syscall_source) - { + if(src != falco_common::syscall_source) { add_source_to_engine(s, src); } } @@ -110,19 +119,16 @@ falco::app::run_result falco::app::actions::init_falco_engine(falco::app::state& // is because in that case event sources are scattered across different // inspectors. Since this is an implementation-based assumption, we // check this and return an error to spot regressions in the future. - if (s.is_capture_mode()) - { + if(s.is_capture_mode()) { auto manager = s.offline_inspector->get_plugin_manager(); - for (const auto &p : manager->plugins()) - { - if (p->caps() & CAP_SOURCING && p->id() != 0) - { + for(const auto& p : manager->plugins()) { + if(p->caps() & CAP_SOURCING && p->id() != 0) { bool added = false; auto source_idx = manager->source_idx_by_plugin_id(p->id(), added); auto engine_idx = s.source_infos.at(p->event_source())->engine_idx; - if (!added || source_idx != engine_idx) - { - return run_result::fatal("Could not add event source in the engine: " + p->event_source()); + if(!added || source_idx != engine_idx) { + return run_result::fatal("Could not add event source in the engine: " + + p->event_source()); } } } diff --git a/userspace/falco/app/actions/init_inspectors.cpp b/userspace/falco/app/actions/init_inspectors.cpp index 4a5c2c49df0..ab767f67410 100644 --- a/userspace/falco/app/actions/init_inspectors.cpp +++ b/userspace/falco/app/actions/init_inspectors.cpp @@ -25,8 +25,7 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -static void init_syscall_inspector(falco::app::state& s, std::shared_ptr inspector) -{ +static void init_syscall_inspector(falco::app::state& s, std::shared_ptr inspector) { inspector->set_buffer_format(s.options.event_buffer_format); // @@ -34,116 +33,98 @@ static void init_syscall_inspector(falco::app::state& s, std::shared_ptr // // Debug log messages - if(s.config->m_container_engines_mask & (1 << CT_DOCKER)) - { + if(s.config->m_container_engines_mask & (1 << CT_DOCKER)) { falco_logger::log(falco_logger::level::DEBUG, "Enabled container engine 'docker'"); } - if(s.config->m_container_engines_mask & (1 << CT_PODMAN)) - { + if(s.config->m_container_engines_mask & (1 << CT_PODMAN)) { falco_logger::log(falco_logger::level::DEBUG, "Enabled container engine 'podman'"); } - if(s.config->m_container_engines_mask & ((1 << CT_CRI) | (1 << CT_CRIO) | (1 << CT_CONTAINERD))) - { + if(s.config->m_container_engines_mask & + ((1 << CT_CRI) | (1 << CT_CRIO) | (1 << CT_CONTAINERD))) { falco_logger::log(falco_logger::level::DEBUG, "Enabled container engine 'CRI'"); } - if(s.config->m_container_engines_mask & (1 << CT_LXC)) - { + if(s.config->m_container_engines_mask & (1 << CT_LXC)) { falco_logger::log(falco_logger::level::DEBUG, "Enabled container engine 'lxc'"); } - if(s.config->m_container_engines_mask & (1 << CT_LIBVIRT_LXC)) - { + if(s.config->m_container_engines_mask & (1 << CT_LIBVIRT_LXC)) { falco_logger::log(falco_logger::level::DEBUG, "Enabled container engine 'libvirt_lxc'"); } - if(s.config->m_container_engines_mask & (1 << CT_BPM)) - { + if(s.config->m_container_engines_mask & (1 << CT_BPM)) { falco_logger::log(falco_logger::level::DEBUG, "Enabled container engine 'bpm'"); } // Container engines configs via falco.yaml inspector->set_container_engine_mask(s.config->m_container_engines_mask); - for (auto &p : s.config->m_container_engines_cri_socket_paths) - { - if (!p.empty()) - { + for(auto& p : s.config->m_container_engines_cri_socket_paths) { + if(!p.empty()) { inspector->add_cri_socket_path(p); - falco_logger::log(falco_logger::level::DEBUG, "Enabled container runtime socket at '" + p + "' via config file"); + falco_logger::log(falco_logger::level::DEBUG, + "Enabled container runtime socket at '" + p + "' via config file"); } } inspector->set_cri_async(!s.config->m_container_engines_disable_cri_async); // Container engines configs via CLI args // If required, set the CRI paths - for (auto &p : s.options.cri_socket_paths) - { - if (!p.empty()) - { + for(auto& p : s.options.cri_socket_paths) { + if(!p.empty()) { inspector->add_cri_socket_path(p); - falco_logger::log(falco_logger::level::DEBUG, "Enabled container runtime socket at '" + p + "' via CLI args"); + falco_logger::log(falco_logger::level::DEBUG, + "Enabled container runtime socket at '" + p + "' via CLI args"); } } // Decide whether to do sync or async for CRI metadata fetch inspector->set_cri_async(!s.options.disable_cri_async); - if(s.options.disable_cri_async || s.config->m_container_engines_disable_cri_async) - { + if(s.options.disable_cri_async || s.config->m_container_engines_disable_cri_async) { falco_logger::log(falco_logger::level::DEBUG, "Disabling async lookups for 'CRI'"); } // // If required, set the snaplen // - if(s.options.snaplen != 0) - { + if(s.options.snaplen != 0) { inspector->set_snaplen(s.options.snaplen); } - if (s.is_driver_drop_failed_exit_enabled()) - { - falco_logger::log(falco_logger::level::INFO, "Failed syscall exit events are dropped in the kernel driver\n"); + if(s.is_driver_drop_failed_exit_enabled()) { + falco_logger::log(falco_logger::level::INFO, + "Failed syscall exit events are dropped in the kernel driver\n"); inspector->set_dropfailed(true); } inspector->set_hostname_and_port_resolution_mode(false); } -static bool populate_filterchecks( - const std::shared_ptr& inspector, - const std::string& source, - filter_check_list& filterchecks, - std::unordered_set& used_plugins, - std::string& err) -{ +static bool populate_filterchecks(const std::shared_ptr& inspector, + const std::string& source, + filter_check_list& filterchecks, + std::unordered_set& used_plugins, + std::string& err) { std::vector infos; - for(const auto& plugin : inspector->get_plugin_manager()->plugins()) - { - if (!(plugin->caps() & CAP_EXTRACTION)) - { + for(const auto& plugin : inspector->get_plugin_manager()->plugins()) { + if(!(plugin->caps() & CAP_EXTRACTION)) { continue; } // check if some fields are overlapping on this event sources infos.clear(); filterchecks.get_all_fields(infos); - for (const auto &info : infos) - { - for (int32_t i = 0; i < info->m_nfields; i++) - { + for(const auto& info : infos) { + for(int32_t i = 0; i < info->m_nfields; i++) { // check if one of the fields extractable by the plugin // is already provided by another filtercheck for this source std::string fname = info->m_fields[i].m_name; - for (const auto &field : plugin->fields()) - { - if (field.m_name == fname) - { - err = "Plugin '" + plugin->name() - + "' supports extraction of field '" + fname - + "' that is overlapping for source '" + source + "'"; + for(const auto& field : plugin->fields()) { + if(field.m_name == fname) { + err = "Plugin '" + plugin->name() + "' supports extraction of field '" + + fname + "' that is overlapping for source '" + source + "'"; return false; } } @@ -157,79 +138,68 @@ static bool populate_filterchecks( return true; } -falco::app::run_result falco::app::actions::init_inspectors(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::init_inspectors(falco::app::state& s) { std::string err; std::unordered_set used_plugins; const auto& all_plugins = s.offline_inspector->get_plugin_manager()->plugins(); - for (const auto &src : s.loaded_sources) - { + for(const auto& src : s.loaded_sources) { auto src_info = s.source_infos.at(src); // in capture mode, every event source uses the offline inspector. // in live mode, we create a new inspector for each event source - if (s.is_capture_mode()) - { + if(s.is_capture_mode()) { src_info->inspector = s.offline_inspector; - } - else - { - src_info->inspector = std::make_shared(s.config->m_metrics_flags & METRICS_V2_STATE_COUNTERS); + } else { + src_info->inspector = + std::make_shared(s.config->m_metrics_flags & METRICS_V2_STATE_COUNTERS); } // do extra preparation for the syscall source - if (src == falco_common::syscall_source) - { + if(src == falco_common::syscall_source) { init_syscall_inspector(s, src_info->inspector); } // load and init all plugins compatible with this event source // (if in capture mode, all plugins will be inited on the same inspector) - for (const auto& p : all_plugins) - { + for(const auto& p : all_plugins) { std::shared_ptr plugin = nullptr; auto config = s.plugin_configs.at(p->name()); - auto is_input = (p->caps() & CAP_SOURCING) - && ((p->id() != 0 && src == p->event_source()) - || (p->id() == 0 && src == falco_common::syscall_source)); + auto is_input = (p->caps() & CAP_SOURCING) && + ((p->id() != 0 && src == p->event_source()) || + (p->id() == 0 && src == falco_common::syscall_source)); - if (s.is_capture_mode()) - { + if(s.is_capture_mode()) { // in capture mode, every plugin is already registered // in the offline inspector by the load_plugins action plugin = p; - } - else - { + } else { // in live mode, for the inspector assigned to the given // event source, we must register the plugin supporting // that event source and also plugins with field extraction // capability that are compatible with that event source - if (is_input - || (p->caps() & CAP_EXTRACTION && sinsp_plugin::is_source_compatible(p->extract_event_sources(), src)) - || (p->caps() & CAP_PARSING && sinsp_plugin::is_source_compatible(p->parse_event_sources(), src)) - || (p->caps() & CAP_ASYNC && sinsp_plugin::is_source_compatible(p->async_event_sources(), src))) - { + if(is_input || + (p->caps() & CAP_EXTRACTION && + sinsp_plugin::is_source_compatible(p->extract_event_sources(), src)) || + (p->caps() & CAP_PARSING && + sinsp_plugin::is_source_compatible(p->parse_event_sources(), src)) || + (p->caps() & CAP_ASYNC && + sinsp_plugin::is_source_compatible(p->async_event_sources(), src))) { plugin = src_info->inspector->register_plugin(config->m_library_path); } } // init the plugin, if we registered it into an inspector // (in capture mode, this is true for every plugin) - if (plugin) - { + if(plugin) { // avoid initializing the same plugin twice in the same // inspector if we're in capture mode - if (!s.is_capture_mode() || used_plugins.find(p->name()) == used_plugins.end()) - { - if (!plugin->init(config->m_init_config, err)) - { + if(!s.is_capture_mode() || used_plugins.find(p->name()) == used_plugins.end()) { + if(!plugin->init(config->m_init_config, err)) { return run_result::fatal(err); } } - if (is_input) - { + if(is_input) { auto gen_check = src_info->inspector->new_generic_filtercheck(); src_info->filterchecks->add_filter_check(std::move(gen_check)); } @@ -238,40 +208,37 @@ falco::app::run_result falco::app::actions::init_inspectors(falco::app::state& s } // populate filtercheck list for this inspector - if (!populate_filterchecks( - src_info->inspector, - src, - *src_info->filterchecks, - used_plugins, - err)) - { + if(!populate_filterchecks(src_info->inspector, + src, + *src_info->filterchecks, + used_plugins, + err)) { return run_result::fatal(err); } // in live mode, each inspector should have registered at most two event sources: // the "syscall" on, loaded at default at index 0, and optionally another // one defined by a plugin, at index 1 - if (!s.is_capture_mode()) - { + if(!s.is_capture_mode()) { const auto& sources = src_info->inspector->event_sources(); - if (sources.size() == 0 || sources.size() > 2 || sources[0] != falco_common::syscall_source) - { + if(sources.size() == 0 || sources.size() > 2 || + sources[0] != falco_common::syscall_source) { err.clear(); - for (const auto &source : sources) - { + for(const auto& source : sources) { err += (err.empty() ? "" : ", ") + source; } - return run_result::fatal("Illegal sources setup in live inspector for source '" + src + "': " + err); + return run_result::fatal("Illegal sources setup in live inspector for source '" + + src + "': " + err); } } } // check if some plugin remains unused - for (const auto& p : all_plugins) - { - if (used_plugins.find(p->name()) == used_plugins.end()) - { - return run_result::fatal("Plugin '" + p->name() + "' is loaded but unused as not compatible with any known event source"); + for(const auto& p : all_plugins) { + if(used_plugins.find(p->name()) == used_plugins.end()) { + return run_result::fatal( + "Plugin '" + p->name() + + "' is loaded but unused as not compatible with any known event source"); } } diff --git a/userspace/falco/app/actions/init_outputs.cpp b/userspace/falco/app/actions/init_outputs.cpp index fb5f30b36c3..6f9f98bc1ff 100644 --- a/userspace/falco/app/actions/init_outputs.cpp +++ b/userspace/falco/app/actions/init_outputs.cpp @@ -27,51 +27,48 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s) -{ - if (s.config->m_outputs.empty()) - { - return run_result::fatal("No output configured, please make sure at least one output is configured and enabled."); +falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s) { + if(s.config->m_outputs.empty()) { + return run_result::fatal( + "No output configured, please make sure at least one output is configured and " + "enabled."); } // read hostname std::string hostname; char* env_hostname = getenv("FALCO_HOSTNAME"); // todo(leogr): keep FALCO_GRPC_HOSTNAME for backward compatibility. Shall we deprecate it? - if(env_hostname || (env_hostname = getenv("FALCO_GRPC_HOSTNAME"))) - { + if(env_hostname || (env_hostname = getenv("FALCO_GRPC_HOSTNAME"))) { hostname = env_hostname; - falco_logger::log(falco_logger::level::INFO, "Hostname value has been overridden via environment variable to: " + hostname + "\n"); - } - else - { + falco_logger::log(falco_logger::level::INFO, + "Hostname value has been overridden via environment variable to: " + + hostname + "\n"); + } else { char c_hostname[256]; int err = gethostname(c_hostname, 256); - if(err != 0) - { + if(err != 0) { return run_result::fatal("Failed to get hostname"); } hostname = c_hostname; } - if (s.options.dry_run) - { - falco_logger::log(falco_logger::level::DEBUG, "Skipping outputs initialization in dry-run\n"); + if(s.options.dry_run) { + falco_logger::log(falco_logger::level::DEBUG, + "Skipping outputs initialization in dry-run\n"); return run_result::ok(); } - s.outputs = std::make_shared( - s.engine, - s.config->m_outputs, - s.config->m_json_output, - s.config->m_json_include_output_property, - s.config->m_json_include_tags_property, - s.config->m_json_include_message_property, - s.config->m_output_timeout, - s.config->m_buffered_outputs, - s.config->m_outputs_queue_capacity, - s.config->m_time_format_iso_8601, - hostname); + s.outputs = std::make_shared(s.engine, + s.config->m_outputs, + s.config->m_json_output, + s.config->m_json_include_output_property, + s.config->m_json_include_tags_property, + s.config->m_json_include_message_property, + s.config->m_output_timeout, + s.config->m_buffered_outputs, + s.config->m_outputs_queue_capacity, + s.config->m_time_format_iso_8601, + hostname); return run_result::ok(); } diff --git a/userspace/falco/app/actions/list_fields.cpp b/userspace/falco/app/actions/list_fields.cpp index 6b0707af731..5e63998da47 100644 --- a/userspace/falco/app/actions/list_fields.cpp +++ b/userspace/falco/app/actions/list_fields.cpp @@ -20,16 +20,16 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::list_fields(falco::app::state& s) -{ - if(s.options.list_fields) - { +falco::app::run_result falco::app::actions::list_fields(falco::app::state& s) { + if(s.options.list_fields) { if(s.options.list_source_fields != "" && - !s.engine->is_source_valid(s.options.list_source_fields)) - { + !s.engine->is_source_valid(s.options.list_source_fields)) { return run_result::fatal("Value for --list must be a valid source type"); } - s.engine->list_fields(s.options.list_source_fields, s.options.verbose, s.options.names_only, s.options.markdown); + s.engine->list_fields(s.options.list_source_fields, + s.options.verbose, + s.options.names_only, + s.options.markdown); return run_result::exit(); } diff --git a/userspace/falco/app/actions/list_plugins.cpp b/userspace/falco/app/actions/list_plugins.cpp index 9d66bbf7562..7a7828737cc 100644 --- a/userspace/falco/app/actions/list_plugins.cpp +++ b/userspace/falco/app/actions/list_plugins.cpp @@ -23,15 +23,12 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::list_plugins(const falco::app::state& s) -{ - if(s.options.list_plugins) - { +falco::app::run_result falco::app::actions::list_plugins(const falco::app::state& s) { + if(s.options.list_plugins) { std::ostringstream os; sinsp inspector; const auto& configs = s.config->m_plugins; - for (auto &c : configs) - { + for(auto& c : configs) { // load the plugin (no need to initialize it) auto plugin = inspector.register_plugin(c.m_library_path); format_plugin_info(plugin, os); diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index 03954ff1740..6523aaaace3 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -22,51 +22,47 @@ using namespace falco::app; using namespace falco::app::actions; // applies legacy/in-deprecation options to the current state -static falco::app::run_result apply_deprecated_options(const falco::app::state& s) -{ +static falco::app::run_result apply_deprecated_options(const falco::app::state& s) { return run_result::ok(); } -falco::app::run_result falco::app::actions::load_config(const falco::app::state& s) -{ +falco::app::run_result falco::app::actions::load_config(const falco::app::state& s) { // List of loaded conf files, ie: s.options.conf_filename // plus all the `config_files` expanded list of configs. config_loaded_res res; - try - { - if (!s.options.conf_filename.empty()) - { - res = s.config->init_from_file(s.options.conf_filename, s.options.cmdline_config_options); - } - else - { + try { + if(!s.options.conf_filename.empty()) { + res = s.config->init_from_file(s.options.conf_filename, + s.options.cmdline_config_options); + } else { // Is possible to have an empty config file when we want to use some command line // options like `--help`, `--version`, ... // The configs used in `load_yaml` will be initialized to the default values. res = s.config->init_from_content("", s.options.cmdline_config_options); } - } - catch (std::exception& e) - { + } catch(std::exception& e) { return run_result::fatal(e.what()); } // log after config init because config determines where logs go falco_logger::set_time_format_iso_8601(s.config->m_time_format_iso_8601); - falco_logger::log(falco_logger::level::INFO, "Falco version: " + std::string(FALCO_VERSION) + " (" + std::string(FALCO_TARGET_ARCH) + ")\n"); - if (!s.cmdline.empty()) - { + falco_logger::log(falco_logger::level::INFO, + "Falco version: " + std::string(FALCO_VERSION) + " (" + + std::string(FALCO_TARGET_ARCH) + ")\n"); + if(!s.cmdline.empty()) { falco_logger::log(falco_logger::level::DEBUG, "CLI args: " + s.cmdline); } - if (!s.options.conf_filename.empty()) - { - falco_logger::log(falco_logger::level::INFO, "Falco initialized with configuration files:\n"); - for (const auto& pair : res) - { + if(!s.options.conf_filename.empty()) { + falco_logger::log(falco_logger::level::INFO, + "Falco initialized with configuration files:\n"); + for(const auto& pair : res) { auto config_path = pair.first; auto validation = pair.second; - auto priority = validation == yaml_helper::validation_ok ? falco_logger::level::INFO : falco_logger::level::WARNING; - falco_logger::log(priority, std::string(" ") + config_path + " | schema validation: " + validation + "\n"); + auto priority = validation == yaml_helper::validation_ok ? falco_logger::level::INFO + : falco_logger::level::WARNING; + falco_logger::log(priority, + std::string(" ") + config_path + + " | schema validation: " + validation + "\n"); } } @@ -75,17 +71,18 @@ falco::app::run_result falco::app::actions::load_config(const falco::app::state& return apply_deprecated_options(s); } -falco::app::run_result falco::app::actions::require_config_file(const falco::app::state& s) -{ +falco::app::run_result falco::app::actions::require_config_file(const falco::app::state& s) { #ifndef __EMSCRIPTEN__ - if (s.options.conf_filename.empty()) - { + if(s.options.conf_filename.empty()) { #ifndef BUILD_TYPE_RELEASE - return run_result::fatal(std::string("You must create a config file at ") + FALCO_SOURCE_CONF_FILE + ", " + FALCO_INSTALL_CONF_FILE + " or by passing -c"); -#else // BUILD_TYPE_RELEASE - return run_result::fatal(std::string("You must create a config file at ") + FALCO_INSTALL_CONF_FILE + " or by passing -c"); -#endif // BUILD_TYPE_RELEASE + return run_result::fatal(std::string("You must create a config file at ") + + FALCO_SOURCE_CONF_FILE + ", " + FALCO_INSTALL_CONF_FILE + + " or by passing -c"); +#else // BUILD_TYPE_RELEASE + return run_result::fatal(std::string("You must create a config file at ") + + FALCO_INSTALL_CONF_FILE + " or by passing -c"); +#endif // BUILD_TYPE_RELEASE } -#endif // __EMSCRIPTEN__ +#endif // __EMSCRIPTEN__ return run_result::ok(); -} \ No newline at end of file +} diff --git a/userspace/falco/app/actions/load_plugins.cpp b/userspace/falco/app/actions/load_plugins.cpp index 7ff134e6c0a..3f14fe80248 100644 --- a/userspace/falco/app/actions/load_plugins.cpp +++ b/userspace/falco/app/actions/load_plugins.cpp @@ -21,12 +21,11 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s) { #if defined(MUSL_OPTIMIZED) or defined(__EMSCRIPTEN__) - if (!s.config->m_plugins.empty()) - { - return run_result::fatal("Loading plugins dynamic libraries is not supported by this Falco build"); + if(!s.config->m_plugins.empty()) { + return run_result::fatal( + "Loading plugins dynamic libraries is not supported by this Falco build"); } #endif // Initialize the set of loaded event sources. @@ -35,7 +34,7 @@ falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s) syscall_src_info.filterchecks = std::make_shared(); s.source_infos.clear(); s.source_infos.insert(syscall_src_info, falco_common::syscall_source); - s.loaded_sources = { falco_common::syscall_source }; + s.loaded_sources = {falco_common::syscall_source}; // Initialize map of plugin configs s.plugin_configs.clear(); @@ -47,20 +46,19 @@ falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s) s.offline_inspector = std::make_shared(); // Load all the configured plugins - for(auto &p : s.config->m_plugins) - { - falco_logger::log(falco_logger::level::INFO, "Loading plugin '" + p.m_name + "' from file " + p.m_library_path + "\n"); + for(auto& p : s.config->m_plugins) { + falco_logger::log(falco_logger::level::INFO, + "Loading plugin '" + p.m_name + "' from file " + p.m_library_path + "\n"); auto plugin = s.offline_inspector->register_plugin(p.m_library_path); s.plugin_configs.insert(p, plugin->name()); - if(plugin->caps() & CAP_SOURCING && plugin->id() != 0) - { + if(plugin->caps() & CAP_SOURCING && plugin->id() != 0) { state::source_info src_info; src_info.filterchecks = std::make_shared(); auto sname = plugin->event_source(); s.source_infos.insert(src_info, sname); // note: this avoids duplicate values - if (std::find(s.loaded_sources.begin(), s.loaded_sources.end(), sname) == s.loaded_sources.end()) - { + if(std::find(s.loaded_sources.begin(), s.loaded_sources.end(), sname) == + s.loaded_sources.end()) { s.loaded_sources.push_back(sname); } } diff --git a/userspace/falco/app/actions/load_rules_files.cpp b/userspace/falco/app/actions/load_rules_files.cpp index ec4050baaf7..044e341bae7 100644 --- a/userspace/falco/app/actions/load_rules_files.cpp +++ b/userspace/falco/app/actions/load_rules_files.cpp @@ -26,29 +26,28 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::load_rules_files(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::load_rules_files(falco::app::state& s) { std::string all_rules; - if (!s.options.rules_filenames.empty()) - { + if(!s.options.rules_filenames.empty()) { s.config->m_rules_filenames = s.options.rules_filenames; } - if(s.config->m_rules_filenames.empty()) - { - return run_result::fatal("You must specify at least one rules file/directory via -r or a rules_file entry in falco.yaml"); + if(s.config->m_rules_filenames.empty()) { + return run_result::fatal( + "You must specify at least one rules file/directory via -r or a rules_file entry " + "in falco.yaml"); } falco_logger::log(falco_logger::level::DEBUG, "Configured rules filenames:\n"); - for (const auto& path : s.config->m_rules_filenames) - { + for(const auto& path : s.config->m_rules_filenames) { falco_logger::log(falco_logger::level::DEBUG, std::string(" ") + path + "\n"); } - for (const auto &path : s.config->m_rules_filenames) - { - falco_configuration::read_rules_file_directory(path, s.config->m_loaded_rules_filenames, s.config->m_loaded_rules_folders); + for(const auto& path : s.config->m_rules_filenames) { + falco_configuration::read_rules_file_directory(path, + s.config->m_loaded_rules_filenames, + s.config->m_loaded_rules_folders); } std::vector rules_contents; @@ -56,38 +55,38 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state& try { read_files(s.config->m_loaded_rules_filenames.begin(), - s.config->m_loaded_rules_filenames.end(), - rules_contents, - rc); - } - catch(falco_exception& e) - { + s.config->m_loaded_rules_filenames.end(), + rules_contents, + rc); + } catch(falco_exception& e) { return run_result::fatal(e.what()); } std::string err = ""; falco_logger::log(falco_logger::level::INFO, "Loading rules from:\n"); - for(auto &filename : s.config->m_loaded_rules_filenames) - { + for(auto& filename : s.config->m_loaded_rules_filenames) { std::unique_ptr res; res = s.engine->load_rules(rc.at(filename), filename); - auto priority = res->schema_validation() == yaml_helper::validation_ok ? falco_logger::level::INFO : falco_logger::level::WARNING; - falco_logger::log(priority, std::string(" ") + filename + " | schema validation: " + res->schema_validation() + "\n"); - - if(!res->successful()) - { + auto priority = res->schema_validation() == yaml_helper::validation_ok + ? falco_logger::level::INFO + : falco_logger::level::WARNING; + falco_logger::log(priority, + std::string(" ") + filename + + " | schema validation: " + res->schema_validation() + "\n"); + + if(!res->successful()) { // Return the summary version as the error err = res->as_string(true, rc); break; } - if(res->has_warnings()) - { - falco_logger::log(falco_logger::level::WARNING,res->as_string(true, rc) + "\n"); + if(res->has_warnings()) { + falco_logger::log(falco_logger::level::WARNING, res->as_string(true, rc) + "\n"); } #if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) - s.config->m_loaded_rules_filenames_sha256sum.insert({filename, falco::utils::calculate_file_sha256sum(filename)}); + s.config->m_loaded_rules_filenames_sha256sum.insert( + {filename, falco::utils::calculate_file_sha256sum(filename)}); #endif } @@ -108,7 +107,7 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state& // like it does for the engine version requirement. On the other hand, // This also requires refactoring a big chunk of the API and code of the // engine responsible of loading rules. - // + // // Since we're close to releasing Falco v0.35, the chosen workaround is // to first collect any error from the engine, then checking if there is // also a version dependency not being satisfied, and give that failure @@ -123,50 +122,44 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state& // todo(jasondellaluce): perform plugin deps checks inside the // falco engine in the middle of the loading procedure of a rules file std::string req_err = ""; - if (!check_rules_plugin_requirements(s, req_err)) - { + if(!check_rules_plugin_requirements(s, req_err)) { err = req_err; } - if (!err.empty()) - { + if(!err.empty()) { return run_result::fatal(err); } - for(const auto& sel : s.config->m_rules_selection) - { + for(const auto& sel : s.config->m_rules_selection) { bool enable = sel.m_op == falco_configuration::rule_selection_operation::enable; - if(sel.m_rule != "") - { + if(sel.m_rule != "") { falco_logger::log(falco_logger::level::INFO, - (enable ? "Enabling" : "Disabling") + std::string(" rules with name: ") + sel.m_rule + "\n"); + (enable ? "Enabling" : "Disabling") + + std::string(" rules with name: ") + sel.m_rule + "\n"); s.engine->enable_rule_wildcard(sel.m_rule, enable); } - if(sel.m_tag != "") - { + if(sel.m_tag != "") { falco_logger::log(falco_logger::level::INFO, - (enable ? "Enabling" : "Disabling") + std::string(" rules with tag: ") + sel.m_tag + "\n"); + (enable ? "Enabling" : "Disabling") + + std::string(" rules with tag: ") + sel.m_tag + "\n"); - s.engine->enable_rule_by_tag(std::set{sel.m_tag}, enable); // TODO wildcard support + s.engine->enable_rule_by_tag(std::set{sel.m_tag}, + enable); // TODO wildcard support } } // printout of `-L` option - if (s.options.describe_all_rules || !s.options.describe_rule.empty()) - { + if(s.options.describe_all_rules || !s.options.describe_rule.empty()) { std::string* rptr = !s.options.describe_rule.empty() ? &(s.options.describe_rule) : nullptr; const auto& plugins = s.offline_inspector->get_plugin_manager()->plugins(); auto out = s.engine->describe_rule(rptr, plugins); - if (!s.config->m_json_output) - { + if(!s.config->m_json_output) { format_described_rules_as_text(out, std::cout); - } - else - { + } else { std::cout << out.dump() << std::endl; } diff --git a/userspace/falco/app/actions/pidfile.cpp b/userspace/falco/app/actions/pidfile.cpp index 4580e1dfe32..6bdfad8f807 100644 --- a/userspace/falco/app/actions/pidfile.cpp +++ b/userspace/falco/app/actions/pidfile.cpp @@ -24,29 +24,26 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::pidfile(const falco::app::state& state) -{ - if (state.options.dry_run) - { +falco::app::run_result falco::app::actions::pidfile(const falco::app::state& state) { + if(state.options.dry_run) { falco_logger::log(falco_logger::level::DEBUG, "Skipping pidfile creation in dry-run\n"); return run_result::ok(); } - if (!state.options.pidfilename.empty()) - { + if(!state.options.pidfilename.empty()) { int64_t self_pid = getpid(); std::ofstream stream; stream.open(state.options.pidfilename); - if (!stream.good()) - { - falco_logger::log(falco_logger::level::ERR, "Could not write pid to pidfile " + state.options.pidfilename + ". Exiting.\n"); + if(!stream.good()) { + falco_logger::log( + falco_logger::level::ERR, + "Could not write pid to pidfile " + state.options.pidfilename + ". Exiting.\n"); exit(-1); } stream << self_pid; stream.close(); - } return run_result::ok(); diff --git a/userspace/falco/app/actions/print_config_schema.cpp b/userspace/falco/app/actions/print_config_schema.cpp index 1eb2b23510c..06c261a9edd 100644 --- a/userspace/falco/app/actions/print_config_schema.cpp +++ b/userspace/falco/app/actions/print_config_schema.cpp @@ -20,10 +20,8 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::print_config_schema(falco::app::state &s) -{ - if(s.options.print_config_schema) - { +falco::app::run_result falco::app::actions::print_config_schema(falco::app::state &s) { + if(s.options.print_config_schema) { printf("%s", s.config->m_config_schema.dump(2).c_str()); return run_result::exit(); } diff --git a/userspace/falco/app/actions/print_generated_gvisor_config.cpp b/userspace/falco/app/actions/print_generated_gvisor_config.cpp index ceedac530ed..cc23e5c53b1 100644 --- a/userspace/falco/app/actions/print_generated_gvisor_config.cpp +++ b/userspace/falco/app/actions/print_generated_gvisor_config.cpp @@ -21,12 +21,11 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::print_generated_gvisor_config(falco::app::state& s) -{ - if(!s.options.gvisor_generate_config_with_socket.empty()) - { +falco::app::run_result falco::app::actions::print_generated_gvisor_config(falco::app::state& s) { + if(!s.options.gvisor_generate_config_with_socket.empty()) { sinsp i; - std::string gvisor_config = i.generate_gvisor_config(s.options.gvisor_generate_config_with_socket); + std::string gvisor_config = + i.generate_gvisor_config(s.options.gvisor_generate_config_with_socket); printf("%s\n", gvisor_config.c_str()); return run_result::exit(); } diff --git a/userspace/falco/app/actions/print_help.cpp b/userspace/falco/app/actions/print_help.cpp index ac6b5b4c6db..a553cafe370 100644 --- a/userspace/falco/app/actions/print_help.cpp +++ b/userspace/falco/app/actions/print_help.cpp @@ -20,10 +20,8 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::print_help(falco::app::state& s) -{ - if(s.options.help) - { +falco::app::run_result falco::app::actions::print_help(falco::app::state& s) { + if(s.options.help) { printf("%s", s.options.usage().c_str()); return run_result::exit(); } diff --git a/userspace/falco/app/actions/print_ignored_events.cpp b/userspace/falco/app/actions/print_ignored_events.cpp index 89836e148e5..3d5e328a1d7 100644 --- a/userspace/falco/app/actions/print_ignored_events.cpp +++ b/userspace/falco/app/actions/print_ignored_events.cpp @@ -22,16 +22,13 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::print_ignored_events(const falco::app::state& s) -{ - if(!s.options.print_ignored_events) - { +falco::app::run_result falco::app::actions::print_ignored_events(const falco::app::state& s) { + if(!s.options.print_ignored_events) { return run_result::ok(); } std::cout << "Ignored syscall(s):" << std::endl; - for(const auto& it : libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set())) - { + for(const auto& it : libsinsp::events::sc_set_to_event_names(falco::app::ignored_sc_set())) { std::cout << "- " << it.c_str() << std::endl; } std::cout << std::endl; diff --git a/userspace/falco/app/actions/print_kernel_version.cpp b/userspace/falco/app/actions/print_kernel_version.cpp index 223c928c4d2..9db5946cc84 100644 --- a/userspace/falco/app/actions/print_kernel_version.cpp +++ b/userspace/falco/app/actions/print_kernel_version.cpp @@ -25,17 +25,17 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::print_kernel_version(const falco::app::state& s) -{ +falco::app::run_result falco::app::actions::print_kernel_version(const falco::app::state& s) { #ifdef __linux__ // We print this info only when a kernel driver is injected - if(s.is_modern_ebpf() || s.is_ebpf() || s.is_kmod()) - { + if(s.is_modern_ebpf() || s.is_ebpf() || s.is_kmod()) { std::ifstream input_file("/proc/version"); - if(!input_file.is_open()) - { + if(!input_file.is_open()) { // We don't want to fail, we just need to log something - falco_logger::log(falco_logger::level::INFO, "Cannot read under '/proc/version' (err_message: '" + std::string(strerror(errno)) + "', err_code: " + std::to_string(errno) + "). No info provided, go on."); + falco_logger::log(falco_logger::level::INFO, + "Cannot read under '/proc/version' (err_message: '" + + std::string(strerror(errno)) + "', err_code: " + + std::to_string(errno) + "). No info provided, go on."); return run_result::ok(); } diff --git a/userspace/falco/app/actions/print_page_size.cpp b/userspace/falco/app/actions/print_page_size.cpp index 6189162a3e6..2dd8c11f8a4 100644 --- a/userspace/falco/app/actions/print_page_size.cpp +++ b/userspace/falco/app/actions/print_page_size.cpp @@ -23,10 +23,8 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::print_page_size(const falco::app::state& s) -{ - if(s.options.print_page_size) - { +falco::app::run_result falco::app::actions::print_page_size(const falco::app::state& s) { + if(s.options.print_page_size) { #ifndef _WIN32 long page_size = getpagesize(); #else @@ -36,13 +34,13 @@ falco::app::run_result falco::app::actions::print_page_size(const falco::app::st long page_size = sysInfo.dwPageSize; #endif - if(page_size <= 0) - { - return run_result::fatal("\nUnable to get the system page size through 'getpagesize()'\n"); - } - else - { - falco_logger::log(falco_logger::level::INFO, "Your system page size is: " + std::to_string(page_size) + " bytes\n"); + if(page_size <= 0) { + return run_result::fatal( + "\nUnable to get the system page size through 'getpagesize()'\n"); + } else { + falco_logger::log( + falco_logger::level::INFO, + "Your system page size is: " + std::to_string(page_size) + " bytes\n"); } return run_result::exit(); } diff --git a/userspace/falco/app/actions/print_plugin_info.cpp b/userspace/falco/app/actions/print_plugin_info.cpp index 1179777dd06..3f080a35d71 100644 --- a/userspace/falco/app/actions/print_plugin_info.cpp +++ b/userspace/falco/app/actions/print_plugin_info.cpp @@ -23,16 +23,12 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::print_plugin_info(const falco::app::state& s) -{ - if(!s.options.print_plugin_info.empty()) - { +falco::app::run_result falco::app::actions::print_plugin_info(const falco::app::state &s) { + if(!s.options.print_plugin_info.empty()) { sinsp inspector; - for(auto &pc : s.config->m_plugins) - { - if (pc.m_name == s.options.print_plugin_info - || pc.m_library_path == s.options.print_plugin_info) - { + for(auto &pc : s.config->m_plugins) { + if(pc.m_name == s.options.print_plugin_info || + pc.m_library_path == s.options.print_plugin_info) { // load the plugin auto p = inspector.register_plugin(pc.m_library_path); @@ -48,15 +44,16 @@ falco::app::run_result falco::app::actions::print_plugin_info(const falco::app:: ss_plugin_schema_type type; auto schema = p->get_init_schema(type); os << "Init config schema type: "; - switch (type) - { - case SS_PLUGIN_SCHEMA_JSON: - os << "JSON" << std::endl; - break; - case SS_PLUGIN_SCHEMA_NONE: - default: - os << "Not available, plugin does not implement the init config schema functionality" << std::endl; - break; + switch(type) { + case SS_PLUGIN_SCHEMA_JSON: + os << "JSON" << std::endl; + break; + case SS_PLUGIN_SCHEMA_NONE: + default: + os << "Not available, plugin does not implement the init config schema " + "functionality" + << std::endl; + break; } os << schema << std::endl; os << std::endl; @@ -64,33 +61,26 @@ falco::app::run_result falco::app::actions::print_plugin_info(const falco::app:: // init the plugin std::string err; - if (!p->init(pc.m_init_config, err)) - { + if(!p->init(pc.m_init_config, err)) { return run_result::fatal(err); } // print plugin suggested open parameters - if (p->caps() & CAP_SOURCING) - { + if(p->caps() & CAP_SOURCING) { os.str(""); os.clear(); auto params = p->list_open_params(); - if (params.empty()) - { + if(params.empty()) { os << "No suggested open params available: "; - os << "plugin has not been configured, or it does not implement the open params suggestion functionality" << std::endl; - } - else - { + os << "plugin has not been configured, or it does not implement the open " + "params suggestion functionality" + << std::endl; + } else { os << "Suggested open params:" << std::endl; - for(const auto &oparam : p->list_open_params()) - { - if(oparam.desc == "") - { + for(const auto &oparam : p->list_open_params()) { + if(oparam.desc == "") { os << oparam.value << std::endl; - } - else - { + } else { os << oparam.value << ": " << oparam.desc << std::endl; } } @@ -103,7 +93,8 @@ falco::app::run_result falco::app::actions::print_plugin_info(const falco::app:: return run_result::exit(); } } - return run_result::fatal("can't find plugin and print its info: " + s.options.print_plugin_info); + return run_result::fatal("can't find plugin and print its info: " + + s.options.print_plugin_info); } return run_result::ok(); diff --git a/userspace/falco/app/actions/print_rule_schema.cpp b/userspace/falco/app/actions/print_rule_schema.cpp index 1052c597d54..23de26b2a3e 100644 --- a/userspace/falco/app/actions/print_rule_schema.cpp +++ b/userspace/falco/app/actions/print_rule_schema.cpp @@ -20,10 +20,8 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::print_rule_schema(falco::app::state &s) -{ - if(s.options.print_rule_schema) - { +falco::app::run_result falco::app::actions::print_rule_schema(falco::app::state &s) { + if(s.options.print_rule_schema) { printf("%s", s.engine->m_rule_schema.dump(2).c_str()); return run_result::exit(); } diff --git a/userspace/falco/app/actions/print_support.cpp b/userspace/falco/app/actions/print_support.cpp index 6e76a8e4d2b..3471f5ae11d 100644 --- a/userspace/falco/app/actions/print_support.cpp +++ b/userspace/falco/app/actions/print_support.cpp @@ -28,21 +28,17 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -static std::string read_file(const std::string &filename) -{ +static std::string read_file(const std::string& filename) { std::ifstream t(filename); - std::string str((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); + std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); return str; } #ifndef _WIN32 -static int get_sysinfo(nlohmann::json &support) -{ +static int get_sysinfo(nlohmann::json& support) { struct utsname sysinfo; - if(uname(&sysinfo) != 0) - { + if(uname(&sysinfo) != 0) { return -1; } @@ -54,8 +50,7 @@ static int get_sysinfo(nlohmann::json &support) return 0; } #else -static int get_sysinfo(nlohmann::json &support) -{ +static int get_sysinfo(nlohmann::json& support) { OSVERSIONINFO osvi; SYSTEM_INFO sysInfo; TCHAR computerName[256]; @@ -63,8 +58,7 @@ static int get_sysinfo(nlohmann::json &support) osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetSystemInfo(&sysInfo); - if(!GetVersionEx(&osvi) || !GetComputerName(computerName, &size)) - { + if(!GetVersionEx(&osvi) || !GetComputerName(computerName, &size)) { return -1; } @@ -73,34 +67,31 @@ static int get_sysinfo(nlohmann::json &support) support["system_info"]["release"] = osvi.dwMajorVersion; support["system_info"]["version"] = osvi.dwMinorVersion; - switch (sysInfo.wProcessorArchitecture) { - case PROCESSOR_ARCHITECTURE_AMD64: - support["system_info"]["machine"] = "x86_64"; - break; - case PROCESSOR_ARCHITECTURE_ARM: - support["system_info"]["machine"] = "ARM"; - break; - case PROCESSOR_ARCHITECTURE_ARM64: - support["system_info"]["machine"] = "ARM64"; - break; - case PROCESSOR_ARCHITECTURE_INTEL: - support["system_info"]["machine"] = "i386"; - break; - default: - support["system_info"]["machine"] = "unknown"; + switch(sysInfo.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_AMD64: + support["system_info"]["machine"] = "x86_64"; + break; + case PROCESSOR_ARCHITECTURE_ARM: + support["system_info"]["machine"] = "ARM"; + break; + case PROCESSOR_ARCHITECTURE_ARM64: + support["system_info"]["machine"] = "ARM64"; + break; + case PROCESSOR_ARCHITECTURE_INTEL: + support["system_info"]["machine"] = "i386"; + break; + default: + support["system_info"]["machine"] = "unknown"; } return 0; } #endif -falco::app::run_result falco::app::actions::print_support(falco::app::state& s) -{ - if(s.options.print_support) - { +falco::app::run_result falco::app::actions::print_support(falco::app::state& s) { + if(s.options.print_support) { nlohmann::json support; - if(get_sysinfo(support) != 0) - { + if(get_sysinfo(support) != 0) { return run_result::fatal(std::string("Could not get system info: ") + strerror(errno)); } @@ -110,8 +101,7 @@ falco::app::run_result falco::app::actions::print_support(falco::app::state& s) support["cmdline"] = s.cmdline; support["config"] = s.config->dump(); support["rules_files"] = nlohmann::json::array(); - for(const auto& filename : s.config->m_loaded_rules_filenames) - { + for(const auto& filename : s.config->m_loaded_rules_filenames) { nlohmann::json finfo; finfo["name"] = filename; nlohmann::json variant; diff --git a/userspace/falco/app/actions/print_syscall_events.cpp b/userspace/falco/app/actions/print_syscall_events.cpp index 95820a0e4e5..7f21293fdba 100644 --- a/userspace/falco/app/actions/print_syscall_events.cpp +++ b/userspace/falco/app/actions/print_syscall_events.cpp @@ -23,16 +23,14 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -struct event_entry -{ +struct event_entry { bool is_enter; bool available; std::string name; const ppm_event_info* info; }; -struct events_by_category -{ +struct events_by_category { std::vector syscalls; std::vector tracepoints; std::vector pluginevents; @@ -45,89 +43,81 @@ struct events_by_category entry.info = libsinsp::events::info(e); entry.available = available; - if (name == "") - { + if(name == "") { entry.name = entry.info->name; } else { entry.name = name; } - if (libsinsp::events::is_syscall_event(e)) - { + if(libsinsp::events::is_syscall_event(e)) { syscalls.push_back(entry); return; } - if (libsinsp::events::is_tracepoint_event(e)) - { + if(libsinsp::events::is_tracepoint_event(e)) { tracepoints.push_back(entry); return; } - if (libsinsp::events::is_plugin_event(e)) - { + if(libsinsp::events::is_plugin_event(e)) { pluginevents.push_back(entry); return; } - if (libsinsp::events::is_metaevent(e)) - { + if(libsinsp::events::is_metaevent(e)) { metaevents.push_back(entry); return; } } }; -static struct events_by_category get_event_entries_by_category(bool include_generics, const libsinsp::events::set& available) -{ +static struct events_by_category get_event_entries_by_category( + bool include_generics, + const libsinsp::events::set& available) { events_by_category result; // skip generic events - for (const auto& e: libsinsp::events::all_event_set()) - { - if (!libsinsp::events::is_generic(e) - && !libsinsp::events::is_old_version_event(e) - && !libsinsp::events::is_unused_event(e) - && !libsinsp::events::is_unknown_event(e)) - { + for(const auto& e : libsinsp::events::all_event_set()) { + if(!libsinsp::events::is_generic(e) && !libsinsp::events::is_old_version_event(e) && + !libsinsp::events::is_unused_event(e) && !libsinsp::events::is_unknown_event(e)) { result.add_event(e, available.contains(e)); } } - if (include_generics) - { + if(include_generics) { // append generic events const auto names = libsinsp::events::event_set_to_names({ppm_event_code::PPME_GENERIC_E}); - for (const auto& name : names) - { - result.add_event(ppm_event_code::PPME_GENERIC_E, available.contains(ppm_event_code::PPME_GENERIC_E), name); - result.add_event(ppm_event_code::PPME_GENERIC_X, available.contains(ppm_event_code::PPME_GENERIC_X), name); + for(const auto& name : names) { + result.add_event(ppm_event_code::PPME_GENERIC_E, + available.contains(ppm_event_code::PPME_GENERIC_E), + name); + result.add_event(ppm_event_code::PPME_GENERIC_X, + available.contains(ppm_event_code::PPME_GENERIC_X), + name); } } return result; } -static bool is_flag_type(ppm_param_type type) -{ +static bool is_flag_type(ppm_param_type type) { return (type == PT_FLAGS8 || type == PT_FLAGS16 || type == PT_FLAGS32 || - type == PT_ENUMFLAGS8 || type == PT_ENUMFLAGS16 || type == PT_ENUMFLAGS32); + type == PT_ENUMFLAGS8 || type == PT_ENUMFLAGS16 || type == PT_ENUMFLAGS32); } -static void print_param(const struct ppm_param_info *param, bool markdown) { +static void print_param(const struct ppm_param_info* param, bool markdown) { printf("%s **%s**", param_type_to_string(param->type), param->name); - if (is_flag_type(param->type) && param->info) { + if(is_flag_type(param->type) && param->info) { auto flag_info = static_cast(param->info); printf(": "); - for (size_t i = 0; flag_info[i].name != NULL; i++) { - if (i != 0) - { + for(size_t i = 0; flag_info[i].name != NULL; i++) { + if(i != 0) { printf(", "); } - if (markdown) { + if(markdown) { printf("*%s*", flag_info[i].name); } else { printf("%s", flag_info[i].name); @@ -136,55 +126,45 @@ static void print_param(const struct ppm_param_info *param, bool markdown) { } } -static void print_events(const std::vector &events, bool markdown) -{ - if(markdown) - { +static void print_events(const std::vector& events, bool markdown) { + if(markdown) { printf("Default | Dir | Name | Params \n"); printf(":-------|:----|:-----|:-----\n"); } - for (const auto& e : events) - { + for(const auto& e : events) { char dir = e.is_enter ? '>' : '<'; - if (markdown) - { + if(markdown) { printf(e.available ? "Yes" : "No"); printf(" | `%c` | `%s` | ", dir, e.name.c_str()); - } - else - { + } else { printf("%c %s(", dir, e.name.c_str()); } - for(uint32_t k = 0; k < e.info->nparams; k++) - { - if(k != 0) - { + for(uint32_t k = 0; k < e.info->nparams; k++) { + if(k != 0) { printf(", "); } print_param(&e.info->params[k], markdown); } - if (markdown) - { + if(markdown) { printf("\n"); - } - else - { + } else { printf(")\n"); } } } -falco::app::run_result falco::app::actions::print_syscall_events(falco::app::state& s) -{ - if(s.options.list_syscall_events) - { +falco::app::run_result falco::app::actions::print_syscall_events(falco::app::state& s) { + if(s.options.list_syscall_events) { const falco::versions_info info(s.offline_inspector); - printf("The events below are valid for Falco *Schema Version*: %s\n", info.driver_schema_version.c_str()); + printf("The events below are valid for Falco *Schema Version*: %s\n", + info.driver_schema_version.c_str()); - const libsinsp::events::set available = libsinsp::events::all_event_set().diff(sc_set_to_event_set(falco::app::ignored_sc_set())); + const libsinsp::events::set available = + libsinsp::events::all_event_set().diff( + sc_set_to_event_set(falco::app::ignored_sc_set())); const struct events_by_category events_bc = get_event_entries_by_category(true, available); printf("## Syscall events\n\n"); diff --git a/userspace/falco/app/actions/print_version.cpp b/userspace/falco/app/actions/print_version.cpp index 7505910e9f2..bc3b8efca07 100644 --- a/userspace/falco/app/actions/print_version.cpp +++ b/userspace/falco/app/actions/print_version.cpp @@ -21,17 +21,12 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::print_version(falco::app::state& s) -{ - if(s.options.print_version_info) - { +falco::app::run_result falco::app::actions::print_version(falco::app::state& s) { + if(s.options.print_version_info) { const falco::versions_info info(s.offline_inspector); - if(s.config->m_json_output) - { + if(s.config->m_json_output) { printf("%s\n", info.as_json().dump().c_str()); - } - else - { + } else { printf("Falco version: %s\n", info.falco_version.c_str()); printf("Libs version: %s\n", info.libs_version.c_str()); printf("Plugin API: %s\n", info.plugin_api_version.c_str()); diff --git a/userspace/falco/app/actions/process_events.cpp b/userspace/falco/app/actions/process_events.cpp index 98d793b79d2..7d663f46707 100644 --- a/userspace/falco/app/actions/process_events.cpp +++ b/userspace/falco/app/actions/process_events.cpp @@ -40,52 +40,41 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -class source_sync_context -{ +class source_sync_context { public: - explicit source_sync_context(falco::semaphore& s) - : m_finished(false), m_joined(false), m_semaphore(s) { } + explicit source_sync_context(falco::semaphore& s): + m_finished(false), + m_joined(false), + m_semaphore(s) {} - inline void finish() - { + inline void finish() { bool v = false; - while (!m_finished.compare_exchange_weak( - v, true, - std::memory_order_seq_cst, - std::memory_order_seq_cst)) - { - if (v) - { + while(!m_finished.compare_exchange_weak(v, + true, + std::memory_order_seq_cst, + std::memory_order_seq_cst)) { + if(v) { throw falco_exception("source_sync_context has been finished twice"); } } m_semaphore.release(); } - inline void join() - { + inline void join() { bool v = false; - while (!m_joined.compare_exchange_weak( - v, true, - std::memory_order_seq_cst, - std::memory_order_seq_cst)) - { - if (v) - { + while(!m_joined.compare_exchange_weak(v, + true, + std::memory_order_seq_cst, + std::memory_order_seq_cst)) { + if(v) { throw falco_exception("source_sync_context has been joined twice"); } } } - inline bool joined() - { - return m_joined.load(std::memory_order_seq_cst); - } + inline bool joined() { return m_joined.load(std::memory_order_seq_cst); } - inline bool finished() - { - return m_finished.load(std::memory_order_seq_cst); - } + inline bool finished() { return m_finished.load(std::memory_order_seq_cst); } private: // set to true when the event processing loop finishes @@ -96,8 +85,7 @@ class source_sync_context falco::semaphore& m_semaphore; }; -struct live_context -{ +struct live_context { // the name of the source of which events are processed std::string source; // the result of the event processing loop @@ -112,15 +100,14 @@ struct live_context // Event processing loop // static falco::app::run_result do_inspect( - falco::app::state& s, - std::shared_ptr inspector, - const std::string& source, // an empty source represents capture mode - std::shared_ptr statsw, - syscall_evt_drop_mgr &sdropmgr, - bool check_drops_and_timeouts, - uint64_t duration_to_tot_ns, - uint64_t &num_evts) -{ + falco::app::state& s, + std::shared_ptr inspector, + const std::string& source, // an empty source represents capture mode + std::shared_ptr statsw, + syscall_evt_drop_mgr& sdropmgr, + bool check_drops_and_timeouts, + uint64_t duration_to_tot_ns, + uint64_t& num_evts) { int32_t rc = 0; sinsp_evt* ev = NULL; stats_writer::collector stats_collector(statsw); @@ -136,8 +123,7 @@ static falco::app::run_result do_inspect( // the only other source loaded in its relative live inspector. size_t expected_live_evt_src_idx = source == falco_common::syscall_source ? 0 : 1; - if (!is_capture_mode) - { + if(!is_capture_mode) { // note: in live mode, each inspector gets assigned a distinct event // source that does not change for the whole capture. source_engine_idx = s.source_infos.at(source)->engine_idx; @@ -147,15 +133,14 @@ static falco::app::run_result do_inspect( num_evts = 0; // init drop manager if we are inspecting syscalls - if (check_drops_and_timeouts) - { + if(check_drops_and_timeouts) { sdropmgr.init(inspector, - s.outputs, // drop manager has its own rate limiting logic - s.config->m_syscall_evt_drop_actions, - s.config->m_syscall_evt_drop_threshold, - s.config->m_syscall_evt_drop_rate, - s.config->m_syscall_evt_drop_max_burst, - s.config->m_syscall_evt_simulate_drops); + s.outputs, // drop manager has its own rate limiting logic + s.config->m_syscall_evt_drop_actions, + s.config->m_syscall_evt_drop_threshold, + s.config->m_syscall_evt_drop_rate, + s.config->m_syscall_evt_drop_max_burst, + s.config->m_syscall_evt_simulate_drops); } // @@ -166,55 +151,54 @@ static falco::app::run_result do_inspect( // // Loop through the events // - while(1) - { + while(1) { rc = inspector->next(&ev); - if (falco::app::g_reopen_outputs_signal.triggered()) - { - falco::app::g_reopen_outputs_signal.handle([&s](){ - falco_logger::log(falco_logger::level::INFO, "SIGUSR1 received, reopening outputs...\n"); - if(s.outputs != nullptr) - { + if(falco::app::g_reopen_outputs_signal.triggered()) { + falco::app::g_reopen_outputs_signal.handle([&s]() { + falco_logger::log(falco_logger::level::INFO, + "SIGUSR1 received, reopening outputs...\n"); + if(s.outputs != nullptr) { s.outputs->reopen_outputs(); } falco::app::g_reopen_outputs_signal.reset(); }); } - if(falco::app::g_terminate_signal.triggered()) - { - falco::app::g_terminate_signal.handle([&](){ + if(falco::app::g_terminate_signal.triggered()) { + falco::app::g_terminate_signal.handle([&]() { falco_logger::log(falco_logger::level::INFO, "SIGINT received, exiting...\n"); }); break; - } - else if(falco::app::g_restart_signal.triggered()) - { - falco::app::g_restart_signal.handle([&s](){ + } else if(falco::app::g_restart_signal.triggered()) { + falco::app::g_restart_signal.handle([&s]() { falco_logger::log(falco_logger::level::INFO, "SIGHUP received, restarting...\n"); s.restart.store(true); }); break; - } - else if(rc == SCAP_TIMEOUT) - { - if(ev == nullptr) [[unlikely]] - { + } else if(rc == SCAP_TIMEOUT) { + if(ev == nullptr) [[unlikely]] { timeouts_since_last_success_or_msg++; - if(timeouts_since_last_success_or_msg > s.config->m_syscall_evt_timeout_max_consecutives - && check_drops_and_timeouts) - { + if(timeouts_since_last_success_or_msg > + s.config->m_syscall_evt_timeout_max_consecutives && + check_drops_and_timeouts) { std::string rule = "Falco internal: timeouts notification"; - std::string msg = rule + ". " + std::to_string(s.config->m_syscall_evt_timeout_max_consecutives) + " consecutive timeouts without event."; + std::string msg = + rule + ". " + + std::to_string(s.config->m_syscall_evt_timeout_max_consecutives) + + " consecutive timeouts without event."; std::string last_event_time_str = "none"; - if(duration_start > 0) - { - sinsp_utils::ts_to_string(duration_start, &last_event_time_str, false, true); + if(duration_start > 0) { + sinsp_utils::ts_to_string(duration_start, + &last_event_time_str, + false, + true); } nlohmann::json fields; fields["last_event_time"] = last_event_time_str; - auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + auto now = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); s.outputs->handle_msg(now, falco_common::PRIORITY_DEBUG, msg, rule, fields); // Reset the timeouts counter, Falco alerted timeouts_since_last_success_or_msg = 0; @@ -222,17 +206,11 @@ static falco::app::run_result do_inspect( } continue; - } - else if(rc == SCAP_FILTERED_EVENT) - { + } else if(rc == SCAP_FILTERED_EVENT) { continue; - } - else if(rc == SCAP_EOF) - { + } else if(rc == SCAP_EOF) { break; - } - else if(rc != SCAP_SUCCESS) - { + } else if(rc != SCAP_SUCCESS) { // // Event read error. // @@ -240,20 +218,16 @@ static falco::app::run_result do_inspect( } // if we are in live mode, we already have the right source engine idx - if (is_capture_mode) - { + if(is_capture_mode) { // note: here we can assume that the source index will be the same // in both the falco engine and the inspector. See the // comment in init_falco_engine.cpp for more details. source_engine_idx = ev->get_source_idx(); - if (source_engine_idx == sinsp_no_event_source_idx) - { + if(source_engine_idx == sinsp_no_event_source_idx) { std::string msg = "Unknown event source for inspector's event"; - if (ev->get_type() == PPME_PLUGINEVENT_E || ev->get_type() == PPME_ASYNCEVENT_E) - { - auto pluginID = *(uint32_t *)ev->get_param(0)->m_val; - if (pluginID != 0) - { + if(ev->get_type() == PPME_PLUGINEVENT_E || ev->get_type() == PPME_ASYNCEVENT_E) { + auto pluginID = *(uint32_t*)ev->get_param(0)->m_val; + if(pluginID != 0) { msg += " (plugin ID: " + std::to_string(pluginID) + ")"; } } @@ -261,21 +235,22 @@ static falco::app::run_result do_inspect( } // for capture mode, the source name can change at every event - stats_collector.collect(inspector, inspector->event_sources()[source_engine_idx], num_evts); - } - else - { + stats_collector.collect(inspector, + inspector->event_sources()[source_engine_idx], + num_evts); + } else { // in live mode, each inspector gets assigned a distinct event source, // so we report an error if we fetch an event of a different source. - if (expected_live_evt_src_idx != ev->get_source_idx()) - { + if(expected_live_evt_src_idx != ev->get_source_idx()) { std::string actual = (ev->get_source_name() != NULL) - ? ("'" + std::string(ev->get_source_name()) + "'") - : (""); + ? ("'" + std::string(ev->get_source_name()) + "'") + : (""); std::string msg = "Unexpected event source for inspector's event:"; msg += " type=" + std::to_string(ev->get_type()); - msg += ", expected='" + source + " (idx=" + std::to_string(expected_live_evt_src_idx) + ")"; - msg += "', actual=" + actual + " (idx=" + std::to_string(ev->get_source_idx()) + ")"; + msg += ", expected='" + source + + " (idx=" + std::to_string(expected_live_evt_src_idx) + ")"; + msg += "', actual=" + actual + " (idx=" + std::to_string(ev->get_source_idx()) + + ")"; return run_result::fatal(msg); } @@ -285,20 +260,15 @@ static falco::app::run_result do_inspect( // Reset the timeouts counter, Falco successfully got an event to process timeouts_since_last_success_or_msg = 0; - if(duration_start == 0) - { + if(duration_start == 0) { duration_start = ev->get_ts(); - } - else if(duration_to_tot_ns > 0) - { - if(ev->get_ts() - duration_start >= duration_to_tot_ns) - { + } else if(duration_to_tot_ns > 0) { + if(ev->get_ts() - duration_start >= duration_to_tot_ns) { break; } } - if(check_drops_and_timeouts && !sdropmgr.process_event(inspector, ev)) - { + if(check_drops_and_timeouts && !sdropmgr.process_event(inspector, ev)) { return run_result::fatal("Drop manager internal error"); } @@ -308,13 +278,15 @@ static falco::app::run_result do_inspect( // of rules. If a match is found, pass the event to // the outputs. auto res = s.engine->process_event(source_engine_idx, ev, s.config->m_rule_matching); - if(res != nullptr) - { - for(auto& rule_res : *res) - { - s.outputs->handle_event( - rule_res.evt, rule_res.rule, rule_res.source, rule_res.priority_num, - rule_res.format, rule_res.tags, rule_res.extra_output_fields); + if(res != nullptr) { + for(auto& rule_res : *res) { + s.outputs->handle_event(rule_res.evt, + rule_res.rule, + rule_res.source, + rule_res.priority_num, + rule_res.format, + rule_res.tags, + rule_res.extra_output_fields); } } @@ -325,68 +297,65 @@ static falco::app::run_result do_inspect( } static void process_inspector_events( - falco::app::state& s, - std::shared_ptr inspector, - std::shared_ptr statsw, - const std::string& source, // an empty source represents capture mode - source_sync_context* sync, - run_result* res) noexcept -{ + falco::app::state& s, + std::shared_ptr inspector, + std::shared_ptr statsw, + const std::string& source, // an empty source represents capture mode + source_sync_context* sync, + run_result* res) noexcept { run_result result; - try - { + try { double duration; scap_stats cstats; uint64_t num_evts = 0; syscall_evt_drop_mgr sdropmgr; bool is_capture_mode = source.empty(); - bool check_drops_timeouts = is_capture_mode - || (source == falco_common::syscall_source && !s.is_gvisor()); + bool check_drops_timeouts = + is_capture_mode || (source == falco_common::syscall_source && !s.is_gvisor()); duration = ((double)clock()) / CLOCKS_PER_SEC; - result = do_inspect(s, inspector, source, statsw, sdropmgr, check_drops_timeouts, - uint64_t(s.options.duration_to_tot*ONE_SECOND_IN_NS), - num_evts); + result = do_inspect(s, + inspector, + source, + statsw, + sdropmgr, + check_drops_timeouts, + uint64_t(s.options.duration_to_tot * ONE_SECOND_IN_NS), + num_evts); duration = ((double)clock()) / CLOCKS_PER_SEC - duration; inspector->get_capture_stats(&cstats); - if(s.options.verbose) - { - if (source == falco_common::syscall_source) - { - fprintf(stderr, "Driver Events:%" PRIu64 "\nDriver Drops:%" PRIu64 "\n", - cstats.n_evts, - cstats.n_drops); + if(s.options.verbose) { + if(source == falco_common::syscall_source) { + fprintf(stderr, + "Driver Events:%" PRIu64 "\nDriver Drops:%" PRIu64 "\n", + cstats.n_evts, + cstats.n_drops); } - fprintf(stderr, "%sElapsed time: %.3lf, Captured Events: %" PRIu64 ", %.2lf eps\n", - (is_capture_mode ? "" : ("("+source+") ").c_str()), - duration, - num_evts, - num_evts / duration); + fprintf(stderr, + "%sElapsed time: %.3lf, Captured Events: %" PRIu64 ", %.2lf eps\n", + (is_capture_mode ? "" : ("(" + source + ") ").c_str()), + duration, + num_evts, + num_evts / duration); } - if (check_drops_timeouts) - { + if(check_drops_timeouts) { sdropmgr.print_stats(); } - } - catch(const std::exception& e) - { + } catch(const std::exception& e) { result = run_result::fatal(e.what()); } - if (sync) - { + if(sync) { try { sync->finish(); - } - catch(const std::exception& e) - { + } catch(const std::exception& e) { result = run_result::merge(result, run_result::fatal(e.what())); } } @@ -395,36 +364,44 @@ static void process_inspector_events( } static falco::app::run_result init_stats_writer( - const std::shared_ptr& sw, - const std::shared_ptr& config, - bool is_dry_run) -{ - if (!config->m_metrics_enabled) - { - return falco::app::run_result::ok(); + const std::shared_ptr& sw, + const std::shared_ptr& config, + bool is_dry_run) { + if(!config->m_metrics_enabled) { + return falco::app::run_result::ok(); } /* Enforce minimum bound of 100ms. */ - if(config->m_metrics_interval < 100) - { - return falco::app::run_result::fatal("Metrics interval must have a minimum value of 100ms and reflect a Prometheus compliant time duration format: https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations. "); + if(config->m_metrics_interval < 100) { + return falco::app::run_result::fatal( + "Metrics interval must have a minimum value of 100ms and reflect a Prometheus " + "compliant time duration format: " + "https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations. "); } - if(std::all_of(config->m_metrics_interval_str.begin(), config->m_metrics_interval_str.end(), ::isdigit)) - { - return falco::app::run_result::fatal("Metrics interval was passed as numeric value without Prometheus time unit. Please specify a time unit"); + if(std::all_of(config->m_metrics_interval_str.begin(), + config->m_metrics_interval_str.end(), + ::isdigit)) { + return falco::app::run_result::fatal( + "Metrics interval was passed as numeric value without Prometheus time unit. Please " + "specify a time unit"); } - if (config->m_metrics_enabled && !(sw->has_output() || config->m_webserver_config.m_prometheus_metrics_enabled)) - { - return falco::app::run_result::fatal("Metrics are enabled with no output configured. Please enable at least one output channel ('metrics.output_rule', 'metrics.output_file' or 'webserver.prometheus_metrics_enabled')"); + if(config->m_metrics_enabled && + !(sw->has_output() || config->m_webserver_config.m_prometheus_metrics_enabled)) { + return falco::app::run_result::fatal( + "Metrics are enabled with no output configured. Please enable at least one output " + "channel ('metrics.output_rule', 'metrics.output_file' or " + "'webserver.prometheus_metrics_enabled')"); } - falco_logger::log(falco_logger::level::INFO, "Setting metrics interval to " + config->m_metrics_interval_str + ", equivalent to " + std::to_string(config->m_metrics_interval) + " (ms)\n"); + falco_logger::log(falco_logger::level::INFO, + "Setting metrics interval to " + config->m_metrics_interval_str + + ", equivalent to " + std::to_string(config->m_metrics_interval) + + " (ms)\n"); auto res = falco::app::run_result::ok(); - if (is_dry_run) - { + if(is_dry_run) { return res; } res.success = stats_writer::init_ticker(config->m_metrics_interval, res.errstr); @@ -432,8 +409,7 @@ static falco::app::run_result init_stats_writer( return res; } -falco::app::run_result falco::app::actions::process_events(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::process_events(falco::app::state& s) { // Notify engine that we finished loading and enabling all rules s.engine->complete_rule_loading(); @@ -441,24 +417,20 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s) auto statsw = std::make_shared(s.outputs, s.config, s.engine); auto res = init_stats_writer(statsw, s.config, s.options.dry_run); - if (s.options.dry_run) - { + if(s.options.dry_run) { falco_logger::log(falco_logger::level::DEBUG, "Skipping event processing in dry-run\n"); return res; } - if (!res.success) - { + if(!res.success) { return res; } // Start processing events bool termination_forced = false; - if(s.is_capture_mode()) - { + if(s.is_capture_mode()) { res = open_offline_inspector(s); - if (!res.success) - { + if(!res.success) { return res; } @@ -468,19 +440,16 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s) // Honor -M also when using a trace file. // Since inspection stops as soon as all events have been consumed // just await the given duration is reached, if needed. - if(s.options.duration_to_tot > 0) - { + if(s.options.duration_to_tot > 0) { std::this_thread::sleep_for(std::chrono::seconds(s.options.duration_to_tot)); } - } - else - { + } else { print_enabled_event_sources(s); #ifdef __EMSCRIPTEN__ - if(s.enabled_sources.size() > 1) - { - return run_result::fatal("enabling multiple event sources is not supported by this Falco build"); + if(s.enabled_sources.size() > 1) { + return run_result::fatal( + "enabling multiple event sources is not supported by this Falco build"); } #endif @@ -488,20 +457,18 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s) falco::semaphore termination_sem(s.enabled_sources.size()); std::vector ctxs; ctxs.reserve(s.enabled_sources.size()); - for (const auto& source : s.enabled_sources) - { + for(const auto& source : s.enabled_sources) { auto& ctx = ctxs.emplace_back(); ctx.source = source; ctx.sync = std::make_unique(termination_sem); auto src_info = s.source_infos.at(source); - try - { - falco_logger::log(falco_logger::level::DEBUG, "Opening event source '" + source + "'\n"); + try { + falco_logger::log(falco_logger::level::DEBUG, + "Opening event source '" + source + "'\n"); termination_sem.acquire(); res = open_live_inspector(s, src_info->inspector, source); - if (!res.success) - { + if(!res.success) { // note: we don't return here because we need to reach // the thread termination loop below to make sure all // already-spawned threads get terminated gracefully @@ -509,22 +476,28 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s) break; } - if (s.enabled_sources.size() == 1) - { + if(s.enabled_sources.size() == 1) { // optimization: with only one source we don't spawn additional threads - process_inspector_events(s, src_info->inspector, statsw, source, ctx.sync.get(), &ctx.res); - } - else - { + process_inspector_events(s, + src_info->inspector, + statsw, + source, + ctx.sync.get(), + &ctx.res); + } else { auto res_ptr = &ctx.res; auto sync_ptr = ctx.sync.get(); - ctx.thread = std::make_unique([&s, src_info, &statsw, source, sync_ptr, res_ptr]() { - process_inspector_events(s, src_info->inspector, statsw, source, sync_ptr, res_ptr); - }); + ctx.thread = std::make_unique( + [&s, src_info, &statsw, source, sync_ptr, res_ptr]() { + process_inspector_events(s, + src_info->inspector, + statsw, + source, + sync_ptr, + res_ptr); + }); } - } - catch (std::exception &e) - { + } catch(std::exception& e) { // note: we don't return here because we need to reach // the thread termination loop below to make sure all // already-spawned threads get terminated gracefully @@ -539,13 +512,12 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s) // to force all other event streams to terminate too. // We accumulate the errors in a single run_result. size_t stopped_count = 0; - while (stopped_count < ctxs.size()) - { - if (!res.success && !termination_forced) - { - falco_logger::log(falco_logger::level::INFO, "An error occurred in an event source, forcing termination...\n"); + while(stopped_count < ctxs.size()) { + if(!res.success && !termination_forced) { + falco_logger::log(falco_logger::level::INFO, + "An error occurred in an event source, forcing termination...\n"); falco::app::g_terminate_signal.trigger(); - falco::app::g_terminate_signal.handle([&](){}); + falco::app::g_terminate_signal.handle([&]() {}); termination_forced = true; } @@ -557,14 +529,10 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s) // event source is enabled, in which we have no additional threads. termination_sem.acquire(); - for (auto &ctx : ctxs) - { - if (ctx.sync->finished() && !ctx.sync->joined()) - { - if (ctx.thread) - { - if (!ctx.thread->joinable()) - { + for(auto& ctx : ctxs) { + if(ctx.sync->finished() && !ctx.sync->joined()) { + if(ctx.thread) { + if(!ctx.thread->joinable()) { // thread has finished executing but // we already joined it, so we skip to the next one. // technically, we should never get here because @@ -574,7 +542,8 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s) ctx.thread->join(); } - falco_logger::log(falco_logger::level::DEBUG, "Stopping capture for event source '" + ctx.source + "'\n"); + falco_logger::log(falco_logger::level::DEBUG, + "Stopping capture for event source '" + ctx.source + "'\n"); s.source_infos.at(ctx.source)->inspector->stop_capture(); res = run_result::merge(res, ctx.res); diff --git a/userspace/falco/app/actions/select_event_sources.cpp b/userspace/falco/app/actions/select_event_sources.cpp index ff1b3556c59..9cff041aea5 100644 --- a/userspace/falco/app/actions/select_event_sources.cpp +++ b/userspace/falco/app/actions/select_event_sources.cpp @@ -21,47 +21,38 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::select_event_sources(falco::app::state& s) -{ - s.enabled_sources = { s.loaded_sources.begin(), s.loaded_sources.end() }; +falco::app::run_result falco::app::actions::select_event_sources(falco::app::state &s) { + s.enabled_sources = {s.loaded_sources.begin(), s.loaded_sources.end()}; // event sources selection is meaningless when reading trace files - if (s.is_capture_mode()) - { + if(s.is_capture_mode()) { return run_result::ok(); } - if (!s.options.enable_sources.empty() && !s.options.disable_sources.empty()) - { + if(!s.options.enable_sources.empty() && !s.options.disable_sources.empty()) { return run_result::fatal("You can not mix --enable-source and --disable-source"); } - if (!s.options.enable_sources.empty()) - { + if(!s.options.enable_sources.empty()) { s.enabled_sources.clear(); - for(const auto &src : s.options.enable_sources) - { - if (std::find(s.loaded_sources.begin(), s.loaded_sources.end(), src) == s.loaded_sources.end()) - { + for(const auto &src : s.options.enable_sources) { + if(std::find(s.loaded_sources.begin(), s.loaded_sources.end(), src) == + s.loaded_sources.end()) { return run_result::fatal("Attempted enabling an unknown event source: " + src); } s.enabled_sources.insert(src); } - } - else if (!s.options.disable_sources.empty()) - { - for(const auto &src : s.options.disable_sources) - { - if (std::find(s.loaded_sources.begin(), s.loaded_sources.end(), src) == s.loaded_sources.end()) - { + } else if(!s.options.disable_sources.empty()) { + for(const auto &src : s.options.disable_sources) { + if(std::find(s.loaded_sources.begin(), s.loaded_sources.end(), src) == + s.loaded_sources.end()) { return run_result::fatal("Attempted disabling an unknown event source: " + src); } s.enabled_sources.erase(src); } } - if(s.enabled_sources.empty()) - { + if(s.enabled_sources.empty()) { return run_result::fatal("Must enable at least one event source"); } diff --git a/userspace/falco/app/actions/start_grpc_server.cpp b/userspace/falco/app/actions/start_grpc_server.cpp index b6a238804b8..a0ce78eaae8 100644 --- a/userspace/falco/app/actions/start_grpc_server.cpp +++ b/userspace/falco/app/actions/start_grpc_server.cpp @@ -24,50 +24,44 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state& s) { #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD) // gRPC server - if(s.config->m_grpc_enabled) - { - if (s.options.dry_run) - { - falco_logger::log(falco_logger::level::DEBUG, "Skipping starting gRPC server in dry-run\n"); + if(s.config->m_grpc_enabled) { + if(s.options.dry_run) { + falco_logger::log(falco_logger::level::DEBUG, + "Skipping starting gRPC server in dry-run\n"); return run_result::ok(); } - falco_logger::log(falco_logger::level::INFO, "gRPC server threadiness equals to " + std::to_string(s.config->m_grpc_threadiness) + "\n"); - // TODO(fntlnz,leodido): when we want to spawn multiple threads we need to have a queue per thread, or implement - // different queuing mechanisms, round robin, fanout? What we want to achieve? - s.grpc_server.init( - s.config->m_grpc_bind_address, - s.config->m_grpc_threadiness, - s.config->m_grpc_private_key, - s.config->m_grpc_cert_chain, - s.config->m_grpc_root_certs, - s.config->m_log_level - ); - s.grpc_server_thread = std::thread([&s] { - s.grpc_server.run(); - }); + falco_logger::log(falco_logger::level::INFO, + "gRPC server threadiness equals to " + + std::to_string(s.config->m_grpc_threadiness) + "\n"); + // TODO(fntlnz,leodido): when we want to spawn multiple threads we need to have a queue per + // thread, or implement different queuing mechanisms, round robin, fanout? What we want to + // achieve? + s.grpc_server.init(s.config->m_grpc_bind_address, + s.config->m_grpc_threadiness, + s.config->m_grpc_private_key, + s.config->m_grpc_cert_chain, + s.config->m_grpc_root_certs, + s.config->m_log_level); + s.grpc_server_thread = std::thread([&s] { s.grpc_server.run(); }); } #endif return run_result::ok(); } -falco::app::run_result falco::app::actions::stop_grpc_server(falco::app::state& s) -{ +falco::app::run_result falco::app::actions::stop_grpc_server(falco::app::state& s) { #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD) - if(s.config->m_grpc_enabled) - { - if (s.options.dry_run) - { - falco_logger::log(falco_logger::level::DEBUG, "Skipping stopping gRPC server in dry-run\n"); + if(s.config->m_grpc_enabled) { + if(s.options.dry_run) { + falco_logger::log(falco_logger::level::DEBUG, + "Skipping stopping gRPC server in dry-run\n"); return run_result::ok(); } - if(s.grpc_server_thread.joinable()) - { + if(s.grpc_server_thread.joinable()) { s.grpc_server.shutdown(); s.grpc_server_thread.join(); } @@ -75,4 +69,3 @@ falco::app::run_result falco::app::actions::stop_grpc_server(falco::app::state& #endif return run_result::ok(); } - diff --git a/userspace/falco/app/actions/start_webserver.cpp b/userspace/falco/app/actions/start_webserver.cpp index bd857ef7d04..df4d91ff968 100644 --- a/userspace/falco/app/actions/start_webserver.cpp +++ b/userspace/falco/app/actions/start_webserver.cpp @@ -24,43 +24,36 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::start_webserver(falco::app::state& state) -{ +falco::app::run_result falco::app::actions::start_webserver(falco::app::state& state) { #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD) - if(!state.is_capture_mode() && state.config->m_webserver_enabled) - { - if (state.options.dry_run) - { - falco_logger::log(falco_logger::level::DEBUG, "Skipping starting webserver in dry-run\n"); + if(!state.is_capture_mode() && state.config->m_webserver_enabled) { + if(state.options.dry_run) { + falco_logger::log(falco_logger::level::DEBUG, + "Skipping starting webserver in dry-run\n"); return run_result::ok(); } falco_configuration::webserver_config webserver_config = state.config->m_webserver_config; std::string ssl_option = (webserver_config.m_ssl_enabled ? " (SSL)" : ""); - falco_logger::log(falco_logger::level::INFO, "Starting health webserver with threadiness " - + std::to_string(webserver_config.m_threadiness) - + ", listening on " - + webserver_config.m_listen_address - + ":" - + std::to_string(webserver_config.m_listen_port) - + ssl_option + "\n"); + falco_logger::log(falco_logger::level::INFO, + "Starting health webserver with threadiness " + + std::to_string(webserver_config.m_threadiness) + + ", listening on " + webserver_config.m_listen_address + ":" + + std::to_string(webserver_config.m_listen_port) + ssl_option + + "\n"); - state.webserver.start( - state, - webserver_config); + state.webserver.start(state, webserver_config); } #endif return run_result::ok(); } -falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& state) -{ +falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& state) { #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD) - if(!state.is_capture_mode() && state.config->m_webserver_enabled) - { - if (state.options.dry_run) - { - falco_logger::log(falco_logger::level::DEBUG, "Skipping stopping webserver in dry-run\n"); + if(!state.is_capture_mode() && state.config->m_webserver_enabled) { + if(state.options.dry_run) { + falco_logger::log(falco_logger::level::DEBUG, + "Skipping stopping webserver in dry-run\n"); return run_result::ok(); } diff --git a/userspace/falco/app/actions/validate_rules_files.cpp b/userspace/falco/app/actions/validate_rules_files.cpp index 7edeb0423e7..9e6f6be2fde 100644 --- a/userspace/falco/app/actions/validate_rules_files.cpp +++ b/userspace/falco/app/actions/validate_rules_files.cpp @@ -25,22 +25,17 @@ limitations under the License. using namespace falco::app; using namespace falco::app::actions; -falco::app::run_result falco::app::actions::validate_rules_files(falco::app::state& s) -{ - if(s.options.validate_rules_filenames.size() > 0) - { - +falco::app::run_result falco::app::actions::validate_rules_files(falco::app::state& s) { + if(s.options.validate_rules_filenames.size() > 0) { std::vector rules_contents; falco::load_result::rules_contents_t rc; try { read_files(s.options.validate_rules_filenames.begin(), - s.options.validate_rules_filenames.end(), - rules_contents, - rc); - } - catch(falco_exception& e) - { + s.options.validate_rules_filenames.end(), + rules_contents, + rc); + } catch(falco_exception& e) { return run_result::fatal(e.what()); } @@ -69,8 +64,7 @@ falco::app::run_result falco::app::actions::validate_rules_files(falco::app::sta std::string summary; falco_logger::log(falco_logger::level::INFO, "Validating rules file(s):\n"); - for(const auto& file : s.options.validate_rules_filenames) - { + for(const auto& file : s.options.validate_rules_filenames) { falco_logger::log(falco_logger::level::INFO, " " + file + "\n"); } @@ -79,36 +73,29 @@ falco::app::run_result falco::app::actions::validate_rules_files(falco::app::sta std::string err = ""; nlohmann::json results = nlohmann::json::array(); - for(auto &filename : s.options.validate_rules_filenames) - { + for(auto& filename : s.options.validate_rules_filenames) { std::unique_ptr res; res = s.engine->load_rules(rc.at(filename), filename); - if (!check_rules_plugin_requirements(s, err)) - { + if(!check_rules_plugin_requirements(s, err)) { return run_result::fatal(err); } successful &= res->successful(); - if(s.config->m_json_output) - { + if(s.config->m_json_output) { results.push_back(res->as_json(rc)); } - - if(summary != "") - { + + if(summary != "") { summary += "\n"; } // Add to the summary if not successful, or successful // with no warnings. - if(!res->successful() || (res->successful() && !res->has_warnings())) - { + if(!res->successful() || (res->successful() && !res->has_warnings())) { summary += res->as_string(true, rc); - } - else - { + } else { // If here, there must be only warnings. // Add a line to the summary noting that the // file was ok with warnings, without actually @@ -120,39 +107,31 @@ falco::app::run_result falco::app::actions::validate_rules_files(falco::app::sta // printout of `-L` option nlohmann::json describe_res; - if (successful && (s.options.describe_all_rules || !s.options.describe_rule.empty())) - { - std::string* rptr = !s.options.describe_rule.empty() ? &(s.options.describe_rule) : nullptr; + if(successful && (s.options.describe_all_rules || !s.options.describe_rule.empty())) { + std::string* rptr = + !s.options.describe_rule.empty() ? &(s.options.describe_rule) : nullptr; const auto& plugins = s.offline_inspector->get_plugin_manager()->plugins(); describe_res = s.engine->describe_rule(rptr, plugins); } - if(s.config->m_json_output) - { + if(s.config->m_json_output) { nlohmann::json res; res["falco_load_results"] = results; - if (!describe_res.empty() && successful) - { + if(!describe_res.empty() && successful) { res["falco_describe_results"] = std::move(describe_res); } std::cout << res.dump() << std::endl; - } - else - { + } else { std::cout << summary << std::endl; - if (!describe_res.empty() && successful) - { + if(!describe_res.empty() && successful) { std::cout << std::endl; format_described_rules_as_text(describe_res, std::cout); } } - if(successful) - { + if(successful) { return run_result::exit(); - } - else - { + } else { return run_result::fatal(summary); } } diff --git a/userspace/falco/app/app.cpp b/userspace/falco/app/app.cpp index fb92f43405a..85870c743ad 100644 --- a/userspace/falco/app/app.cpp +++ b/userspace/falco/app/app.cpp @@ -26,8 +26,7 @@ falco::atomic_signal_handler falco::app::g_reopen_outputs_signal; using app_action = std::function; -libsinsp::events::set falco::app::ignored_sc_set() -{ +libsinsp::events::set falco::app::ignored_sc_set() { // we ignore all the I/O syscalls that can have very high throughput and // that can badly impact performance. Of those, we avoid ignoring the // ones that are part of the base set used by libsinsp for maintaining @@ -35,17 +34,13 @@ libsinsp::events::set falco::app::ignored_sc_set() return libsinsp::events::io_sc_set().diff(libsinsp::events::sinsp_state_sc_set()); } -bool falco::app::run(int argc, char** argv, bool& restart, std::string& errstr) -{ - falco::app::state s; - if(!s.options.parse(argc, argv, errstr)) - { +bool falco::app::run(int argc, char** argv, bool& restart, std::string& errstr) { + falco::app::state s; + if(!s.options.parse(argc, argv, errstr)) { return false; } - for(char **arg = argv; *arg; arg++) - { - if(s.cmdline.size() > 0) - { + for(char** arg = argv; *arg; arg++) { + if(s.cmdline.size() > 0) { s.cmdline += " "; } s.cmdline += *arg; @@ -53,71 +48,66 @@ bool falco::app::run(int argc, char** argv, bool& restart, std::string& errstr) return falco::app::run(s, restart, errstr); } -bool falco::app::run(falco::app::state& s, bool& restart, std::string& errstr) -{ +bool falco::app::run(falco::app::state& s, bool& restart, std::string& errstr) { // The order here is the order in which the methods will be // called. Before changing the order, ensure that all // dependencies are honored (e.g. don't process events before // loading plugins, opening inspector, etc.). std::list run_steps = { - falco::app::actions::print_config_schema, - falco::app::actions::print_rule_schema, - falco::app::actions::load_config, - falco::app::actions::print_help, - falco::app::actions::print_kernel_version, - falco::app::actions::print_version, - falco::app::actions::print_page_size, - falco::app::actions::print_generated_gvisor_config, - falco::app::actions::print_ignored_events, - falco::app::actions::print_syscall_events, - falco::app::actions::require_config_file, - falco::app::actions::print_plugin_info, - falco::app::actions::list_plugins, - falco::app::actions::load_plugins, - falco::app::actions::init_inspectors, - falco::app::actions::init_falco_engine, - falco::app::actions::list_fields, - falco::app::actions::select_event_sources, - falco::app::actions::validate_rules_files, - falco::app::actions::load_rules_files, - falco::app::actions::print_support, - falco::app::actions::init_outputs, - falco::app::actions::create_signal_handlers, - falco::app::actions::create_requested_paths, - falco::app::actions::pidfile, - falco::app::actions::configure_interesting_sets, - falco::app::actions::configure_syscall_buffer_size, - falco::app::actions::configure_syscall_buffer_num, - falco::app::actions::start_grpc_server, - falco::app::actions::start_webserver, - falco::app::actions::process_events, + falco::app::actions::print_config_schema, + falco::app::actions::print_rule_schema, + falco::app::actions::load_config, + falco::app::actions::print_help, + falco::app::actions::print_kernel_version, + falco::app::actions::print_version, + falco::app::actions::print_page_size, + falco::app::actions::print_generated_gvisor_config, + falco::app::actions::print_ignored_events, + falco::app::actions::print_syscall_events, + falco::app::actions::require_config_file, + falco::app::actions::print_plugin_info, + falco::app::actions::list_plugins, + falco::app::actions::load_plugins, + falco::app::actions::init_inspectors, + falco::app::actions::init_falco_engine, + falco::app::actions::list_fields, + falco::app::actions::select_event_sources, + falco::app::actions::validate_rules_files, + falco::app::actions::load_rules_files, + falco::app::actions::print_support, + falco::app::actions::init_outputs, + falco::app::actions::create_signal_handlers, + falco::app::actions::create_requested_paths, + falco::app::actions::pidfile, + falco::app::actions::configure_interesting_sets, + falco::app::actions::configure_syscall_buffer_size, + falco::app::actions::configure_syscall_buffer_num, + falco::app::actions::start_grpc_server, + falco::app::actions::start_webserver, + falco::app::actions::process_events, }; std::list teardown_steps = { - falco::app::actions::unregister_signal_handlers, - falco::app::actions::stop_grpc_server, - falco::app::actions::stop_webserver, - falco::app::actions::close_inspectors, + falco::app::actions::unregister_signal_handlers, + falco::app::actions::stop_grpc_server, + falco::app::actions::stop_webserver, + falco::app::actions::close_inspectors, }; falco::app::run_result res = falco::app::run_result::ok(); - for (const auto &func : run_steps) - { + for(const auto& func : run_steps) { res = falco::app::run_result::merge(res, func(s)); - if(!res.proceed) - { + if(!res.proceed) { break; } } - for (const auto &func : teardown_steps) - { + for(const auto& func : teardown_steps) { res = falco::app::run_result::merge(res, func(s)); // note: we always proceed because we don't want to miss teardown steps } - if(!res.success) - { + if(!res.success) { errstr = res.errstr; } diff --git a/userspace/falco/app/app.h b/userspace/falco/app/app.h index 016f2959fe0..461bc67adf0 100644 --- a/userspace/falco/app/app.h +++ b/userspace/falco/app/app.h @@ -30,5 +30,5 @@ bool run(int argc, char** argv, bool& restart, std::string& errstr); bool run(falco::app::state& s, bool& restart, std::string& errstr); -}; // namespace app -}; // namespace falco +}; // namespace app +}; // namespace falco diff --git a/userspace/falco/app/options.cpp b/userspace/falco/app/options.cpp index a9a2d7d91de..d0422ff0a0e 100644 --- a/userspace/falco/app/options.cpp +++ b/userspace/falco/app/options.cpp @@ -26,8 +26,7 @@ limitations under the License. namespace falco { namespace app { -bool options::parse(int argc, char **argv, std::string &errstr) -{ +bool options::parse(int argc, char **argv, std::string &errstr) { cxxopts::Options opts("falco", "Falco - Cloud Native Runtime Security"); define(opts); m_usage_str = opts.help(); @@ -35,42 +34,31 @@ bool options::parse(int argc, char **argv, std::string &errstr) cxxopts::ParseResult m_cmdline_parsed; try { m_cmdline_parsed = opts.parse(argc, argv); - } - catch (std::exception &e) - { + } catch(std::exception &e) { errstr = e.what(); return false; } // Some options require additional processing/validation std::ifstream conf_stream; - if (!conf_filename.empty()) - { + if(!conf_filename.empty()) { conf_stream.open(conf_filename); - if (!conf_stream.is_open()) - { + if(!conf_stream.is_open()) { errstr = std::string("Could not find configuration file at ") + conf_filename; return false; } - } - else - { + } else { #ifndef BUILD_TYPE_RELEASE conf_stream.open(FALCO_SOURCE_CONF_FILE); - if (conf_stream.is_open()) - { + if(conf_stream.is_open()) { conf_filename = FALCO_SOURCE_CONF_FILE; - } - else + } else #endif { conf_stream.open(FALCO_INSTALL_CONF_FILE); - if (conf_stream.is_open()) - { + if(conf_stream.is_open()) { conf_filename = FALCO_INSTALL_CONF_FILE; - } - else - { + } else { // Note we do not return false here. Although there is // no valid config file, some ways of running falco // (e.g. --help, --list) do not need a config file. @@ -82,27 +70,26 @@ bool options::parse(int argc, char **argv, std::string &errstr) } } - if(m_cmdline_parsed.count("b") > 0) - { + if(m_cmdline_parsed.count("b") > 0) { event_buffer_format = sinsp_evt::PF_BASE64; } - if(m_cmdline_parsed.count("r") > 0) - { - for(auto &path : m_cmdline_parsed["r"].as>()) - { + if(m_cmdline_parsed.count("r") > 0) { + for(auto &path : m_cmdline_parsed["r"].as>()) { rules_filenames.push_back(path); } } - if (m_cmdline_parsed.count("cri") > 0) - { - falco_logger::log(falco_logger::level::WARNING, "The --cri option is deprecated and will be removed in Falco 0.40.0. Use -o container_engines.cri.sockets[]= instead."); + if(m_cmdline_parsed.count("cri") > 0) { + falco_logger::log(falco_logger::level::WARNING, + "The --cri option is deprecated and will be removed in Falco 0.40.0. Use " + "-o container_engines.cri.sockets[]= instead."); } - if (m_cmdline_parsed.count("disable-cri-async") > 0) - { - falco_logger::log(falco_logger::level::WARNING, "The --disable-cri-async option is deprecated and will be removed in Falco 0.40.0. Use -o container_engines.cri.disable_async=true instead."); + if(m_cmdline_parsed.count("disable-cri-async") > 0) { + falco_logger::log(falco_logger::level::WARNING, + "The --disable-cri-async option is deprecated and will be removed in " + "Falco 0.40.0. Use -o container_engines.cri.disable_async=true instead."); } list_fields = m_cmdline_parsed.count("list") > 0; @@ -110,59 +97,286 @@ bool options::parse(int argc, char **argv, std::string &errstr) return true; } -const std::string& options::usage() -{ +const std::string &options::usage() { return m_usage_str; } -void options::define(cxxopts::Options& opts) -{ - opts.add_options() - ("h,help", "Print this help list and exit.", cxxopts::value(help)->default_value("false")) +void options::define(cxxopts::Options &opts) { + opts.add_options()("h,help", + "Print this help list and exit.", + cxxopts::value(help)->default_value("false")) #ifdef BUILD_TYPE_RELEASE - ("c", "Configuration file. If not specified uses " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "") + ("c", + "Configuration file. If not specified uses " FALCO_INSTALL_CONF_FILE ".", + cxxopts::value(conf_filename), + "") #else - ("c", "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "") + ("c", + "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE + ", " FALCO_INSTALL_CONF_FILE ".", + cxxopts::value(conf_filename), + "") #endif - ("config-schema", "Print the config json schema and exit.", cxxopts::value(print_config_schema)->default_value("false")) - ("rule-schema", "Print the rule json schema and exit.", cxxopts::value(print_rule_schema)->default_value("false")) - ("A", "Monitor all events supported by Falco and defined in rules and configs. Some events are ignored by default when -A is not specified (the -i option lists these events ignored). Using -A can impact performance. This option has no effect when reproducing events from a capture file.", cxxopts::value(all_events)->default_value("false")) - ("b,print-base64", "Print data buffers in base64. This is useful for encoding binary data that needs to be used over media designed to consume this format.") + ("config-schema", + "Print the config json schema and exit.", + cxxopts::value(print_config_schema)->default_value("false"))( + "rule-schema", + "Print the rule json schema and exit.", + cxxopts::value(print_rule_schema)->default_value("false"))( + "A", + "Monitor all events supported by Falco and defined in rules and " + "configs. Some events are ignored by default when -A is not specified " + "(the -i option lists these events ignored). Using -A can impact " + "performance. This option has no effect when reproducing events from a " + "capture file.", + cxxopts::value(all_events)->default_value("false"))( + "b,print-base64", + "Print data buffers in base64. This is useful for encoding binary data " + "that needs to be used over media designed to consume this format.") #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD) - ("cri", "DEPRECATED: use -o container_engines.cri.sockets[]= instead. Path to CRI socket for container metadata. Use the specified to fetch data from a CRI-compatible runtime. If not specified, built-in defaults for commonly known paths are used. This option can be passed multiple times to specify a list of sockets to be tried until a successful one is found.", cxxopts::value(cri_socket_paths), "") - ("disable-cri-async", "DEPRECATED: use -o container_engines.cri.disable_async=true instead. Turn off asynchronous CRI metadata fetching. This is useful to let the input event wait for the container metadata fetch to finish before moving forward. Async fetching, in some environments leads to empty fields for container metadata when the fetch is not fast enough to be completed asynchronously. This can have a performance penalty on your environment depending on the number of containers and the frequency at which they are created/started/stopped.", cxxopts::value(disable_cri_async)->default_value("false")) + ("cri", + "DEPRECATED: use -o container_engines.cri.sockets[]= " + "instead. Path to CRI socket for container metadata. Use the " + "specified to fetch data from a CRI-compatible runtime. If not " + "specified, built-in defaults for commonly known paths are used. This " + "option can be passed multiple times to specify a list of sockets to " + "be tried until a successful one is found.", + cxxopts::value(cri_socket_paths), + "")( + "disable-cri-async", + "DEPRECATED: use -o container_engines.cri.disable_async=true " + "instead. Turn off asynchronous CRI metadata fetching. This is " + "useful to let the input event wait for the container metadata " + "fetch to finish before moving forward. Async fetching, in " + "some environments leads to empty fields for container " + "metadata when the fetch is not fast enough to be completed " + "asynchronously. This can have a performance penalty on your " + "environment depending on the number of containers and the " + "frequency at which they are created/started/stopped.", + cxxopts::value(disable_cri_async)->default_value("false")) #endif - ("disable-source", "Turn off a specific . By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times, but turning off all event sources simultaneously is not permitted. This option can not be mixed with --enable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(disable_sources), "") - ("dry-run", "Run Falco without processing events. It can help check that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false")) - ("enable-source", "Enable a specific . By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. When using this option, only the event sources specified by it will be enabled. This option can not be mixed with --disable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(enable_sources), "") + ("disable-source", + "Turn off a specific . By default, all loaded " + "sources get enabled. Available sources are 'syscall' plus " + "all sources defined by loaded plugins supporting the event " + "sourcing capability. This option can be passed multiple " + "times, but turning off all event sources simultaneously is " + "not permitted. This option can not be mixed with " + "--enable-source. This option has no effect when reproducing " + "events from a capture file.", + cxxopts::value(disable_sources), + "")( + "dry-run", + "Run Falco without processing events. It can help " + "check that the configuration and rules do not have " + "any errors.", + cxxopts::value(dry_run)->default_value("false"))( + "enable-source", + "Enable a specific . By default, all " + "loaded sources get enabled. Available sources are " + "'syscall' plus all sources defined by loaded plugins " + "supporting the event sourcing capability. This option " + "can be passed multiple times. When using this option, " + "only the event sources specified by it will be " + "enabled. This option can not be mixed with " + "--disable-source. This option has no effect when " + "reproducing events from a capture file.", + cxxopts::value(enable_sources), + "") #ifdef HAS_GVISOR - ("gvisor-generate-config", "Generate a configuration file that can be used for gVisor and exit. See --gvisor-config for more details.", cxxopts::value(gvisor_generate_config_with_socket)->implicit_value("/run/falco/gvisor.sock"), "") + ("gvisor-generate-config", + "Generate a configuration file that can be used for " + "gVisor and exit. See --gvisor-config for more " + "details.", + cxxopts::value( + gvisor_generate_config_with_socket) + ->implicit_value("/run/falco/gvisor.sock"), + "") #endif - ("i", "Print those events that are ignored by default for performance reasons and exit. See -A for more details.", cxxopts::value(print_ignored_events)->default_value("false")) - ("L", "Show the name and description of all rules and exit. If json_output is set to true, it prints details about all rules, macros, and lists in JSON format.", cxxopts::value(describe_all_rules)->default_value("false")) - ("l", "Show the name and description of the rule specified and exit. If json_output is set to true, it prints details about the rule in JSON format.", cxxopts::value(describe_rule), "") - ("list", "List all defined fields and exit. If is provided, only list those fields for the source . Current values for are \"syscall\" or any source from a configured plugin with event sourcing capability.", cxxopts::value(list_source_fields)->implicit_value(""), "") - ("list-events", "List all defined syscall events, metaevents, tracepoint events and exit.", cxxopts::value(list_syscall_events)) - ("list-plugins", "Print info on all loaded plugins and exit.", cxxopts::value(list_plugins)->default_value("false")) - ("M", "Stop Falco execution after are passed.", cxxopts::value(duration_to_tot)->default_value("0"), "") - ("markdown", "Print output in Markdown format when used in conjunction with --list or --list-events options. It has no effect when used with other options.", cxxopts::value(markdown)) - ("N", "Only print field names when used in conjunction with the --list option. It has no effect when used with other options.", cxxopts::value(names_only)->default_value("false")) - ("o,option", "Set the value of option to . Overrides values in the configuration file. can be identified using its location in the configuration file using dot notation. Elements of list entries can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "=") - ("plugin-info", "Print info for the plugin specified by and exit.\nThis includes all descriptive information like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n can be the plugin's name or its configured 'library_path'.", cxxopts::value(print_plugin_info), "") - ("p,print", "Print (or replace) additional information in the rule's output.\nUse -pc or -pcontainer to append container details to syscall events.\nUse -pk or -pkubernetes to add both container and Kubernetes details to syscall events.\nIf using gVisor, choose -pcg or -pkg variants (or -pcontainer-gvisor and -pkubernetes-gvisor, respectively).\nIf a syscall rule's output contains %container.info, it will be replaced with the corresponding details. Otherwise, these details will be directly appended to the rule's output.\nAlternatively, use -p for a custom format. In this case, the given will be appended to the rule's output without any replacement to all events, including plugin events.", cxxopts::value(print_additional), "") - ("P,pidfile", "Write PID to specified path. By default, no PID file is created.", cxxopts::value(pidfilename)->default_value(""), "") - ("r", "Rules file or directory to be loaded. This option can be passed multiple times. Falco defaults to the values in the configuration file when this option is not specified.", cxxopts::value>(), "") - ("S,snaplen", "Collect only the first bytes of each I/O buffer for 'syscall' events. By default, the first 80 bytes are collected by the driver and sent to the user space for processing. Use this option with caution since it can have a strong performance impact.", cxxopts::value(snaplen)->default_value("0"), "") - ("support", "Print support information, including version, rules files used, loaded configuration, etc., and exit. The output is in JSON format.", cxxopts::value(print_support)->default_value("false")) - ("U,unbuffered", "Turn off output buffering for configured outputs. This causes every single line emitted by Falco to be flushed, which generates higher CPU usage but is useful when piping those outputs into another process or a script.", cxxopts::value(unbuffered_outputs)->default_value("false")) - ("V,validate", "Read the contents of the specified file(s), validate the loaded rules, and exit. This option can be passed multiple times to validate multiple files.", cxxopts::value(validate_rules_filenames), "") - ("v", "Enable verbose output.", cxxopts::value(verbose)->default_value("false")) - ("version", "Print version information and exit.", cxxopts::value(print_version_info)->default_value("false")) - ("page-size", "Print the system page size and exit. This utility may help choose the right syscall ring buffer size.", cxxopts::value(print_page_size)->default_value("false")); - + ("i", + "Print those events that are ignored by " + "default for performance reasons and exit. " + "See -A for more details.", + cxxopts::value(print_ignored_events) + ->default_value("false"))( + "L", + "Show the name and description of all " + "rules and exit. If json_output is set " + "to true, it prints details about all " + "rules, macros, and lists in JSON " + "format.", + cxxopts::value(describe_all_rules) + ->default_value("false"))( + "l", + "Show the name and description of the " + "rule specified and exit. If " + "json_output is set to true, it prints " + "details about the rule in JSON " + "format.", + cxxopts::value(describe_rule), + "")( + "list", + "List all defined fields and exit. If " + " is provided, only list those " + "fields for the source . " + "Current values for are " + "\"syscall\" or any source from a " + "configured plugin with event sourcing " + "capability.", + cxxopts::value(list_source_fields) + ->implicit_value(""), + "")( + "list-events", + "List all defined syscall events, " + "metaevents, tracepoint events and " + "exit.", + cxxopts::value( + list_syscall_events))( + "list-plugins", + "Print info on all loaded plugins and " + "exit.", + cxxopts::value(list_plugins) + ->default_value("false"))( + "M", + "Stop Falco execution after " + " are passed.", + cxxopts::value(duration_to_tot) + ->default_value("0"), + "")( + "markdown", + "Print output in Markdown format when " + "used in conjunction with --list or " + "--list-events options. It has no " + "effect when used with other options.", + cxxopts::value(markdown))( + "N", + "Only print field names when used in " + "conjunction with the --list option. " + "It has no effect when used with other " + "options.", + cxxopts::value(names_only) + ->default_value("false"))( + "o,option", + "Set the value of option to " + ". Overrides values in the " + "configuration file. can be " + "identified using its location in the " + "configuration file using dot " + "notation. Elements of list entries " + "can be accessed via square brackets " + "[].\n E.g. base.id = val\n " + "base.subvalue.subvalue2 = val\n " + " base.list[1]=val", + cxxopts::value(cmdline_config_options), + "=")( + "plugin-info", + "Print info for the plugin specified " + "by and exit.\nThis " + "includes all descriptive information " + "like name and author, along with " + "the\nschema format for the init " + "configuration and a list of suggested " + "open parameters.\n can " + "be the plugin's name or its " + "configured 'library_path'.", + cxxopts::value(print_plugin_info), + "")( + "p,print", + "Print (or replace) additional " + "information in the rule's " + "output.\nUse -pc or -pcontainer to " + "append container details to syscall " + "events.\nUse -pk or -pkubernetes to " + "add both container and Kubernetes " + "details to syscall events.\nIf using " + "gVisor, choose -pcg or -pkg variants " + "(or -pcontainer-gvisor and " + "-pkubernetes-gvisor, " + "respectively).\nIf a syscall rule's " + "output contains %container.info, it " + "will be replaced with the " + "corresponding details. Otherwise, " + "these details will be directly " + "appended to the rule's " + "output.\nAlternatively, use -p " + " for a custom format. " + "In this case, the given " + " will be appended to " + "the rule's output without any " + "replacement to all events, including " + "plugin events.", + cxxopts::value(print_additional), + "")( + "P,pidfile", + "Write PID to specified " + "path. By default, no PID file is " + "created.", + cxxopts::value(pidfilename) + ->default_value(""), + "")( + "r", + "Rules file or directory to be loaded. " + "This option can be passed multiple " + "times. Falco defaults to the values " + "in the configuration file when this " + "option is not specified.", + cxxopts::value< + std::vector>(), + "")( + "S,snaplen", + "Collect only the first bytes of " + "each I/O buffer for 'syscall' events. " + "By default, the first 80 bytes are " + "collected by the driver and sent to " + "the user space for processing. Use " + "this option with caution since it can " + "have a strong performance impact.", + cxxopts::value(snaplen)->default_value( + "0"), + "")( + "support", + "Print support information, including " + "version, rules files used, loaded " + "configuration, etc., and exit. The " + "output is in JSON format.", + cxxopts::value(print_support) + ->default_value("false"))( + "U,unbuffered", + "Turn off output buffering for " + "configured outputs. This causes every " + "single line emitted by Falco to be " + "flushed, which generates higher CPU " + "usage but is useful when piping those " + "outputs into another process or a " + "script.", + cxxopts::value(unbuffered_outputs) + ->default_value("false"))( + "V,validate", + "Read the contents of the specified " + " file(s), validate the " + "loaded rules, and exit. This option " + "can be passed multiple times to " + "validate multiple files.", + cxxopts::value( + validate_rules_filenames), + "")( + "v", + "Enable verbose output.", + cxxopts::value(verbose)->default_value( + "false"))( + "version", + "Print version information and exit.", + cxxopts::value(print_version_info) + ->default_value("false"))( + "page-size", + "Print the system page size and exit. " + "This utility may help choose the " + "right syscall ring buffer size.", + cxxopts::value(print_page_size) + ->default_value("false")); opts.set_width(140); } -}; // namespace app -}; // namespace falco +}; // namespace app +}; // namespace falco diff --git a/userspace/falco/app/options.h b/userspace/falco/app/options.h index 6dc70de55ad..da35d76ed74 100644 --- a/userspace/falco/app/options.h +++ b/userspace/falco/app/options.h @@ -24,7 +24,9 @@ limitations under the License. #include #include -namespace cxxopts { class Options; }; +namespace cxxopts { +class Options; +}; namespace falco { namespace app { @@ -34,9 +36,9 @@ class options { options() = default; ~options() = default; options(options&&) = default; - options& operator = (options&&) = default; + options& operator=(options&&) = default; options(const options&) = default; - options& operator = (const options&) = default; + options& operator=(const options&) = default; // Each of these maps directly to a command line option. bool help = false; @@ -75,7 +77,7 @@ class options { bool print_page_size = false; bool dry_run = false; - bool parse(int argc, char **argv, std::string &errstr); + bool parse(int argc, char** argv, std::string& errstr); const std::string& usage(); @@ -84,5 +86,5 @@ class options { std::string m_usage_str; }; -}; // namespace application -}; // namespace falco +}; // namespace app +}; // namespace falco diff --git a/userspace/falco/app/restart_handler.cpp b/userspace/falco/app/restart_handler.cpp index 4fbc29c0909..eb0a85a8eea 100644 --- a/userspace/falco/app/restart_handler.cpp +++ b/userspace/falco/app/restart_handler.cpp @@ -36,182 +36,166 @@ limitations under the License. #define gettid() syscall(SYS_gettid) #endif -falco::app::restart_handler::~restart_handler() -{ - stop(); - close(m_inotify_fd); - m_inotify_fd = -1; +falco::app::restart_handler::~restart_handler() { + stop(); + close(m_inotify_fd); + m_inotify_fd = -1; } -void falco::app::restart_handler::trigger() -{ - m_forced.store(true, std::memory_order_release); +void falco::app::restart_handler::trigger() { + m_forced.store(true, std::memory_order_release); } -bool falco::app::restart_handler::start(std::string& err) -{ +bool falco::app::restart_handler::start(std::string& err) { #ifdef __linux__ - m_inotify_fd = inotify_init(); - if (m_inotify_fd < 0) - { - err = "could not initialize inotify handler"; - return false; - } - - for (const auto& f : m_watched_files) - { - auto wd = inotify_add_watch(m_inotify_fd, f.c_str(), IN_CLOSE_WRITE | IN_MOVE_SELF | IN_DELETE_SELF); - if (wd < 0) - { - err = "could not watch file: " + f; - return false; - } - falco_logger::log(falco_logger::level::DEBUG, "Watching file '" + f +"'\n"); - } - - for (const auto &f : m_watched_dirs) - { - auto wd = inotify_add_watch(m_inotify_fd, f.c_str(), IN_CREATE | IN_DELETE | IN_MOVE); - if (wd < 0) - { - err = "could not watch directory: " + f; - return false; - } - falco_logger::log(falco_logger::level::DEBUG, "Watching directory '" + f +"'\n"); - } - - // launch the watcher thread - m_watcher = std::thread(&falco::app::restart_handler::watcher_loop, this); + m_inotify_fd = inotify_init(); + if(m_inotify_fd < 0) { + err = "could not initialize inotify handler"; + return false; + } + + for(const auto& f : m_watched_files) { + auto wd = inotify_add_watch(m_inotify_fd, + f.c_str(), + IN_CLOSE_WRITE | IN_MOVE_SELF | IN_DELETE_SELF); + if(wd < 0) { + err = "could not watch file: " + f; + return false; + } + falco_logger::log(falco_logger::level::DEBUG, "Watching file '" + f + "'\n"); + } + + for(const auto& f : m_watched_dirs) { + auto wd = inotify_add_watch(m_inotify_fd, f.c_str(), IN_CREATE | IN_DELETE | IN_MOVE); + if(wd < 0) { + err = "could not watch directory: " + f; + return false; + } + falco_logger::log(falco_logger::level::DEBUG, "Watching directory '" + f + "'\n"); + } + + // launch the watcher thread + m_watcher = std::thread(&falco::app::restart_handler::watcher_loop, this); #endif - return true; + return true; } -void falco::app::restart_handler::stop() -{ +void falco::app::restart_handler::stop() { #ifdef __linux__ - m_stop.store(true, std::memory_order_release); - if (m_watcher.joinable()) - { - m_watcher.join(); - } + m_stop.store(true, std::memory_order_release); + if(m_watcher.joinable()) { + m_watcher.join(); + } #endif } -void falco::app::restart_handler::watcher_loop() noexcept -{ +void falco::app::restart_handler::watcher_loop() noexcept { #ifdef __linux__ - if (fcntl(m_inotify_fd, F_SETOWN, gettid()) < 0) - { - // an error occurred, we can't recover - // todo(jasondellaluce): should we terminate the process? - falco_logger::log(falco_logger::level::ERR, "Failed owning inotify handler, shutting down watcher..."); - return; - } - - fd_set set; - bool forced = false; - bool should_check = false; - bool should_restart = false; - struct timeval timeout; - uint8_t buf[(10 * (sizeof(struct inotify_event) + NAME_MAX + 1))]; - while (!m_stop.load(std::memory_order_acquire)) - { - // wait for inotify events with a certain timeout. - // Note, we'll run through select even before performing a dry-run, - // so that we can dismiss in case we have to debounce rapid - // subsequent events. - timeout.tv_sec = 0; - timeout.tv_usec = 100000; - FD_ZERO(&set); - FD_SET(m_inotify_fd, &set); - auto rv = select(m_inotify_fd + 1, &set, NULL, NULL, &timeout); - if (rv < 0) - { - // an error occurred, we can't recover - // todo(jasondellaluce): should we terminate the process? - falco_logger::log(falco_logger::level::ERR, "Failed select with inotify handler, shutting down watcher..."); - return; - } - - // check if there's been a forced restart request - forced = m_forced.load(std::memory_order_acquire); - m_forced.store(false, std::memory_order_release); - - // no new watch event is received during the timeout - if (rv == 0 && !forced) - { - // perform a dry run. In case no error occurs, we loop back - // to the select in order to debounce new inotify events before - // actually triggering a restart. - if (should_check) - { - should_check = false; - should_restart = m_on_check(); - continue; - } - - // if the previous dry run was successful, and no new - // inotify events have been received during the dry run, - // then we trigger the restarting signal and quit. - // note: quitting is a time optimization, the thread - // will be forced to quit anyways later by the Falco app, but - // at least we don't make users wait for the timeout. - if (should_restart) - { - // todo(jasondellaluce): make this a callback too maybe? - g_restart_signal.trigger(); - return; - } - - // let's go back to the select - continue; - } - - // at this point, we either received a new inotify event or a forced - // restart. If this happened during a dry run (even if the dry run - // was successful), or during a timeout wait since the last successful - // dry run before a restart, we dismiss the restart attempt and - // perform an additional dry-run for safety purposes (the new inotify - // events may be related to bad config/rules files changes). - should_restart = false; - should_check = false; - - // if there's date on the inotify fd, consume it - // (even if there is a forced request too) - if (rv > 0) - { - // note: if available data is less than buffer size, this should - // return n > 0 but not filling the buffer. If available data is - // more than buffer size, we will loop back to select and behave - // like we debounced an event. - auto n = read(m_inotify_fd, buf, sizeof(buf)); - if (n < 0) - { - // an error occurred, we can't recover - // todo(jasondellaluce): should we terminate the process? - falco_logger::log(falco_logger::level::ERR, "Failed read with inotify handler, shutting down watcher..."); - return; - } - // this is an odd case, but if we got here with - // no read data, and no forced request, we get back - // looping in the select. This can likely happen if - // there's data in the inotify fd but the first read - // returned no bytes. Likely we'll get back here at the - // next select call. - else if (n == 0) - { - // we still proceed in case the request was forced - if (!forced) - { - continue; - } - } - } - - // we consumed the new inotify events or we received a forced - // restart request, so we'll perform a dry run after the - // next timeout. - should_check = true; - } + if(fcntl(m_inotify_fd, F_SETOWN, gettid()) < 0) { + // an error occurred, we can't recover + // todo(jasondellaluce): should we terminate the process? + falco_logger::log(falco_logger::level::ERR, + "Failed owning inotify handler, shutting down watcher..."); + return; + } + + fd_set set; + bool forced = false; + bool should_check = false; + bool should_restart = false; + struct timeval timeout; + uint8_t buf[(10 * (sizeof(struct inotify_event) + NAME_MAX + 1))]; + while(!m_stop.load(std::memory_order_acquire)) { + // wait for inotify events with a certain timeout. + // Note, we'll run through select even before performing a dry-run, + // so that we can dismiss in case we have to debounce rapid + // subsequent events. + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + FD_ZERO(&set); + FD_SET(m_inotify_fd, &set); + auto rv = select(m_inotify_fd + 1, &set, NULL, NULL, &timeout); + if(rv < 0) { + // an error occurred, we can't recover + // todo(jasondellaluce): should we terminate the process? + falco_logger::log(falco_logger::level::ERR, + "Failed select with inotify handler, shutting down watcher..."); + return; + } + + // check if there's been a forced restart request + forced = m_forced.load(std::memory_order_acquire); + m_forced.store(false, std::memory_order_release); + + // no new watch event is received during the timeout + if(rv == 0 && !forced) { + // perform a dry run. In case no error occurs, we loop back + // to the select in order to debounce new inotify events before + // actually triggering a restart. + if(should_check) { + should_check = false; + should_restart = m_on_check(); + continue; + } + + // if the previous dry run was successful, and no new + // inotify events have been received during the dry run, + // then we trigger the restarting signal and quit. + // note: quitting is a time optimization, the thread + // will be forced to quit anyways later by the Falco app, but + // at least we don't make users wait for the timeout. + if(should_restart) { + // todo(jasondellaluce): make this a callback too maybe? + g_restart_signal.trigger(); + return; + } + + // let's go back to the select + continue; + } + + // at this point, we either received a new inotify event or a forced + // restart. If this happened during a dry run (even if the dry run + // was successful), or during a timeout wait since the last successful + // dry run before a restart, we dismiss the restart attempt and + // perform an additional dry-run for safety purposes (the new inotify + // events may be related to bad config/rules files changes). + should_restart = false; + should_check = false; + + // if there's date on the inotify fd, consume it + // (even if there is a forced request too) + if(rv > 0) { + // note: if available data is less than buffer size, this should + // return n > 0 but not filling the buffer. If available data is + // more than buffer size, we will loop back to select and behave + // like we debounced an event. + auto n = read(m_inotify_fd, buf, sizeof(buf)); + if(n < 0) { + // an error occurred, we can't recover + // todo(jasondellaluce): should we terminate the process? + falco_logger::log(falco_logger::level::ERR, + "Failed read with inotify handler, shutting down watcher..."); + return; + } + // this is an odd case, but if we got here with + // no read data, and no forced request, we get back + // looping in the select. This can likely happen if + // there's data in the inotify fd but the first read + // returned no bytes. Likely we'll get back here at the + // next select call. + else if(n == 0) { + // we still proceed in case the request was forced + if(!forced) { + continue; + } + } + } + + // we consumed the new inotify events or we received a forced + // restart request, so we'll perform a dry run after the + // next timeout. + should_check = true; + } #endif } diff --git a/userspace/falco/app/restart_handler.h b/userspace/falco/app/restart_handler.h index fc8519f9a45..6adc28b5bf5 100644 --- a/userspace/falco/app/restart_handler.h +++ b/userspace/falco/app/restart_handler.h @@ -23,56 +23,52 @@ limitations under the License. #include #include -namespace falco -{ -namespace app -{ +namespace falco { +namespace app { /** * @brief A thread-safe helper for handling hot-reload application restarts. */ -class restart_handler -{ +class restart_handler { public: - /** - * @brief A function that performs safety checks before confirming - * a triggered application restart. Returns true if the application - * can safely be restarted. - */ - using on_check_t = std::function; + /** + * @brief A function that performs safety checks before confirming + * a triggered application restart. Returns true if the application + * can safely be restarted. + */ + using on_check_t = std::function; - /** - * @brief A list of files or directories paths to watch. - */ - using watch_list_t = std::vector; + /** + * @brief A list of files or directories paths to watch. + */ + using watch_list_t = std::vector; - explicit restart_handler( - on_check_t on_check, - const watch_list_t& watch_files = {}, - const watch_list_t& watch_dirs = {}) - : m_inotify_fd(-1), - m_stop(false), - m_forced(false), - m_on_check(on_check), - m_watched_dirs(watch_dirs), - m_watched_files(watch_files) { } - virtual ~restart_handler(); + explicit restart_handler(on_check_t on_check, + const watch_list_t& watch_files = {}, + const watch_list_t& watch_dirs = {}): + m_inotify_fd(-1), + m_stop(false), + m_forced(false), + m_on_check(on_check), + m_watched_dirs(watch_dirs), + m_watched_files(watch_files) {} + virtual ~restart_handler(); - bool start(std::string& err); - void stop(); - void trigger(); + bool start(std::string& err); + void stop(); + void trigger(); private: - void watcher_loop() noexcept; + void watcher_loop() noexcept; - int m_inotify_fd; - std::thread m_watcher; - std::atomic m_stop; - std::atomic m_forced; - on_check_t m_on_check; - watch_list_t m_watched_dirs; - watch_list_t m_watched_files; + int m_inotify_fd; + std::thread m_watcher; + std::atomic m_stop; + std::atomic m_forced; + on_check_t m_on_check; + watch_list_t m_watched_dirs; + watch_list_t m_watched_files; }; -}; // namespace app -}; // namespace falco +}; // namespace app +}; // namespace falco diff --git a/userspace/falco/app/run_result.h b/userspace/falco/app/run_result.h index 506febd8c52..d8b6410d059 100644 --- a/userspace/falco/app/run_result.h +++ b/userspace/falco/app/run_result.h @@ -22,68 +22,61 @@ limitations under the License. namespace falco { namespace app { -struct run_result -{ - // Successful result - inline static run_result ok() - { - run_result r; - r.success = true; - r.errstr = ""; - r.proceed = true; - return r; - } +struct run_result { + // Successful result + inline static run_result ok() { + run_result r; + r.success = true; + r.errstr = ""; + r.proceed = true; + return r; + } - // Successful result that causes the program to stop - inline static run_result exit() - { - run_result r = ok(); - r.proceed = false; - return r; - } + // Successful result that causes the program to stop + inline static run_result exit() { + run_result r = ok(); + r.proceed = false; + return r; + } - // Failure result that causes the program to stop with an error - inline static run_result fatal(const std::string& err) - { - run_result r; - r.success = false; - r.errstr = err; - r.proceed = false; - return r; - } + // Failure result that causes the program to stop with an error + inline static run_result fatal(const std::string& err) { + run_result r; + r.success = false; + r.errstr = err; + r.proceed = false; + return r; + } - // Merges two run results into one - inline static run_result merge(const run_result& a, const run_result& b) - { - auto res = ok(); - res.proceed = a.proceed && b.proceed; - res.success = a.success && b.success; - res.errstr = a.errstr; - if (!b.errstr.empty()) - { - res.errstr += res.errstr.empty() ? "" : "\n"; - res.errstr += b.errstr; - } - return res; - } + // Merges two run results into one + inline static run_result merge(const run_result& a, const run_result& b) { + auto res = ok(); + res.proceed = a.proceed && b.proceed; + res.success = a.success && b.success; + res.errstr = a.errstr; + if(!b.errstr.empty()) { + res.errstr += res.errstr.empty() ? "" : "\n"; + res.errstr += b.errstr; + } + return res; + } - run_result(): success(true), errstr(""), proceed(true) {} - virtual ~run_result() = default; - run_result(run_result&&) = default; - run_result& operator = (run_result&&) = default; - run_result(const run_result&) = default; - run_result& operator = (const run_result&) = default; + run_result(): success(true), errstr(""), proceed(true) {} + virtual ~run_result() = default; + run_result(run_result&&) = default; + run_result& operator=(run_result&&) = default; + run_result(const run_result&) = default; + run_result& operator=(const run_result&) = default; - - // If true, the method completed successfully. - bool success; - // If success==false, details on the error. - std::string errstr; - // If true, subsequent methods should be performed. If - // false, subsequent methods should *not* be performed - // and falco should tear down/exit/restart. - bool proceed; + // If true, the method completed successfully. + bool success; + // If success==false, details on the error. + std::string errstr; + // If true, subsequent methods should be performed. If + // false, subsequent methods should *not* be performed + // and falco should tear down/exit/restart. + bool proceed; }; -}; // namespace app -}; // namespace falco +}; // namespace app +}; // namespace falco diff --git a/userspace/falco/app/signals.h b/userspace/falco/app/signals.h index a95ea6b1b6f..7e72881bddb 100644 --- a/userspace/falco/app/signals.h +++ b/userspace/falco/app/signals.h @@ -26,5 +26,5 @@ extern atomic_signal_handler g_terminate_signal; extern atomic_signal_handler g_restart_signal; extern atomic_signal_handler g_reopen_outputs_signal; -}; // namespace app -}; // namespace falco +}; // namespace app +}; // namespace falco diff --git a/userspace/falco/app/state.h b/userspace/falco/app/state.h index ffe7ef77ae3..a5281c65475 100644 --- a/userspace/falco/app/state.h +++ b/userspace/falco/app/state.h @@ -43,163 +43,137 @@ namespace app { // standalone class to allow for a bit of separation between // application state and instance variables, and to also defer // initializing this state until application::init. -struct state -{ - // Holds the info mapped for each loaded event source - struct source_info - { - source_info() : filterchecks(std::make_shared()) {} - - // The index of the given event source in the state's falco_engine, - // as returned by falco_engine::add_source - std::size_t engine_idx = -1; - // The filtercheck list containing all fields compatible - // with the given event source - std::shared_ptr filterchecks; - // The inspector assigned to this event source. If in capture mode, - // all event source will share the same inspector. If the event - // source is a plugin one, the assigned inspector must have that - // plugin registered in its plugin manager - std::shared_ptr inspector; - }; - - state(): - config(std::make_shared()), - engine(std::make_shared()), - offline_inspector(std::make_shared()) - { - } - - state(const std::string& cmd, const falco::app::options& opts): state() - { - cmdline = cmd; - options = opts; - } - - std::string cmdline; - falco::app::options options; - std::atomic restart = false; - - - std::shared_ptr config; - std::shared_ptr outputs; - std::shared_ptr engine; - - // The set of loaded event sources (by default, the syscall event - // source plus all event sources coming from the loaded plugins). - // note: this has to be a vector to preserve the loading order, - // however it's not supposed to contain duplicate values. - std::vector loaded_sources; - - // The set of enabled event sources (can be altered by using - // the --enable-source and --disable-source options) - std::unordered_set enabled_sources; - - // Used to load all plugins to get their info. In capture mode, - // this is also used to open the capture file and read its events - std::shared_ptr offline_inspector; - - // List of all the information mapped to each event source - // indexed by event source name - indexed_vector source_infos; - - // List of all plugin configurations indexed by plugin name as returned - // by their sinsp_plugin::name method - indexed_vector plugin_configs; - - // Set of syscalls we want the driver to capture - libsinsp::events::set selected_sc_set; - - // Dimension of the syscall buffer in bytes. - uint64_t syscall_buffer_bytes_size = DEFAULT_DRIVER_BUFFER_BYTES_DIM; - - // Helper responsible for watching of handling hot application restarts - std::shared_ptr restarter; +struct state { + // Holds the info mapped for each loaded event source + struct source_info { + source_info(): filterchecks(std::make_shared()) {} + + // The index of the given event source in the state's falco_engine, + // as returned by falco_engine::add_source + std::size_t engine_idx = -1; + // The filtercheck list containing all fields compatible + // with the given event source + std::shared_ptr filterchecks; + // The inspector assigned to this event source. If in capture mode, + // all event source will share the same inspector. If the event + // source is a plugin one, the assigned inspector must have that + // plugin registered in its plugin manager + std::shared_ptr inspector; + }; + + state(): + config(std::make_shared()), + engine(std::make_shared()), + offline_inspector(std::make_shared()) {} + + state(const std::string& cmd, const falco::app::options& opts): state() { + cmdline = cmd; + options = opts; + } + + std::string cmdline; + falco::app::options options; + std::atomic restart = false; + + std::shared_ptr config; + std::shared_ptr outputs; + std::shared_ptr engine; + + // The set of loaded event sources (by default, the syscall event + // source plus all event sources coming from the loaded plugins). + // note: this has to be a vector to preserve the loading order, + // however it's not supposed to contain duplicate values. + std::vector loaded_sources; + + // The set of enabled event sources (can be altered by using + // the --enable-source and --disable-source options) + std::unordered_set enabled_sources; + + // Used to load all plugins to get their info. In capture mode, + // this is also used to open the capture file and read its events + std::shared_ptr offline_inspector; + + // List of all the information mapped to each event source + // indexed by event source name + indexed_vector source_infos; + + // List of all plugin configurations indexed by plugin name as returned + // by their sinsp_plugin::name method + indexed_vector plugin_configs; + + // Set of syscalls we want the driver to capture + libsinsp::events::set selected_sc_set; + + // Dimension of the syscall buffer in bytes. + uint64_t syscall_buffer_bytes_size = DEFAULT_DRIVER_BUFFER_BYTES_DIM; + + // Helper responsible for watching of handling hot application restarts + std::shared_ptr restarter; #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD) - falco::grpc::server grpc_server; - std::thread grpc_server_thread; + falco::grpc::server grpc_server; + std::thread grpc_server_thread; - falco_webserver webserver; + falco_webserver webserver; #endif - inline bool is_capture_mode() const - { - return config->m_engine_mode == engine_kind_t::REPLAY; - } - - inline bool is_gvisor() const - { - return config->m_engine_mode == engine_kind_t::GVISOR; - } - - inline bool is_kmod() const - { - return config->m_engine_mode == engine_kind_t::KMOD; - } - - inline bool is_ebpf() const - { - return config->m_engine_mode == engine_kind_t::EBPF; - } - - inline bool is_modern_ebpf() const - { - return config->m_engine_mode == engine_kind_t::MODERN_EBPF; - } - - inline bool is_nodriver() const - { - return config->m_engine_mode == engine_kind_t::NODRIVER; - } - - inline bool is_source_enabled(const std::string& src) const - { - return enabled_sources.find(falco_common::syscall_source) != enabled_sources.end(); - } - - inline bool is_driver_drop_failed_exit_enabled() const - { - bool drop_failed; - switch (config->m_engine_mode) - { - case engine_kind_t::KMOD: - drop_failed = config->m_kmod.m_drop_failed_exit; - break; - case engine_kind_t::EBPF: - drop_failed = config->m_ebpf.m_drop_failed_exit; - break; - case engine_kind_t::MODERN_EBPF: - drop_failed = config->m_modern_ebpf.m_drop_failed_exit; - break; - default: - drop_failed = false; - break; + inline bool is_capture_mode() const { return config->m_engine_mode == engine_kind_t::REPLAY; } + + inline bool is_gvisor() const { return config->m_engine_mode == engine_kind_t::GVISOR; } + + inline bool is_kmod() const { return config->m_engine_mode == engine_kind_t::KMOD; } + + inline bool is_ebpf() const { return config->m_engine_mode == engine_kind_t::EBPF; } + + inline bool is_modern_ebpf() const { + return config->m_engine_mode == engine_kind_t::MODERN_EBPF; + } + + inline bool is_nodriver() const { return config->m_engine_mode == engine_kind_t::NODRIVER; } + + inline bool is_source_enabled(const std::string& src) const { + return enabled_sources.find(falco_common::syscall_source) != enabled_sources.end(); } - return drop_failed; - } - - inline int16_t driver_buf_size_preset() const - { - int16_t index; - switch (config->m_engine_mode) { - case engine_kind_t::KMOD: - index = config->m_kmod.m_buf_size_preset; - break; - case engine_kind_t::EBPF: - index = config->m_ebpf.m_buf_size_preset; - break; - case engine_kind_t::MODERN_EBPF: - index = config->m_modern_ebpf.m_buf_size_preset; - break; - default: - // unsupported - index = - 1; - break; + + inline bool is_driver_drop_failed_exit_enabled() const { + bool drop_failed; + switch(config->m_engine_mode) { + case engine_kind_t::KMOD: + drop_failed = config->m_kmod.m_drop_failed_exit; + break; + case engine_kind_t::EBPF: + drop_failed = config->m_ebpf.m_drop_failed_exit; + break; + case engine_kind_t::MODERN_EBPF: + drop_failed = config->m_modern_ebpf.m_drop_failed_exit; + break; + default: + drop_failed = false; + break; + } + return drop_failed; + } + + inline int16_t driver_buf_size_preset() const { + int16_t index; + switch(config->m_engine_mode) { + case engine_kind_t::KMOD: + index = config->m_kmod.m_buf_size_preset; + break; + case engine_kind_t::EBPF: + index = config->m_ebpf.m_buf_size_preset; + break; + case engine_kind_t::MODERN_EBPF: + index = config->m_modern_ebpf.m_buf_size_preset; + break; + default: + // unsupported + index = -1; + break; + } + return index; } - return index; - } }; -}; // namespace app -}; // namespace falco +}; // namespace app +}; // namespace falco diff --git a/userspace/falco/atomic_signal_handler.h b/userspace/falco/atomic_signal_handler.h index 3d80a231dd7..5630eb3ca0a 100644 --- a/userspace/falco/atomic_signal_handler.h +++ b/userspace/falco/atomic_signal_handler.h @@ -21,113 +21,94 @@ limitations under the License. #include #include -namespace falco -{ - /** - * @brief A concurrent object that helps properly handling - * system signals from multiple threads. - */ - class atomic_signal_handler - { - public: - /** - * @brief Returns true if the underlying atomic implementation - * is lock-free as per C++ standard semantics. - */ - inline bool is_lock_free() const - { - return m_handled.is_lock_free() && m_triggered.is_lock_free(); - } +namespace falco { +/** + * @brief A concurrent object that helps properly handling + * system signals from multiple threads. + */ +class atomic_signal_handler { +public: + /** + * @brief Returns true if the underlying atomic implementation + * is lock-free as per C++ standard semantics. + */ + inline bool is_lock_free() const { + return m_handled.is_lock_free() && m_triggered.is_lock_free(); + } - /** - * @brief Resets the handler to its initial state, which is - * non-triggered and non-handled. - */ - inline void reset() - { - m_handled.store(false, std::memory_order_seq_cst); - m_triggered.store(false, std::memory_order_seq_cst); - } + /** + * @brief Resets the handler to its initial state, which is + * non-triggered and non-handled. + */ + inline void reset() { + m_handled.store(false, std::memory_order_seq_cst); + m_triggered.store(false, std::memory_order_seq_cst); + } - /** - * @brief Returns true if the signal has been triggered. - */ - inline bool triggered() const - { - return m_triggered.load(std::memory_order_seq_cst); - } + /** + * @brief Returns true if the signal has been triggered. + */ + inline bool triggered() const { return m_triggered.load(std::memory_order_seq_cst); } - /** - * @brief Returns true if the signal has been handled. - */ - inline bool handled() const - { - return m_handled.load(std::memory_order_seq_cst); - } + /** + * @brief Returns true if the signal has been handled. + */ + inline bool handled() const { return m_handled.load(std::memory_order_seq_cst); } - /** - * @brief Triggers the signal. Must generally be invoked from - * within an actual signal handler (created with the `signal` - * system call). Can eventually be invoked for "faking" - * the triggering of a signal programmatically. - */ - inline void trigger() - { - m_triggered.store(true, std::memory_order_seq_cst); - m_handled.store(false, std::memory_order_seq_cst); - } + /** + * @brief Triggers the signal. Must generally be invoked from + * within an actual signal handler (created with the `signal` + * system call). Can eventually be invoked for "faking" + * the triggering of a signal programmatically. + */ + inline void trigger() { + m_triggered.store(true, std::memory_order_seq_cst); + m_handled.store(false, std::memory_order_seq_cst); + } - /** - * @brief If a signal is triggered, performs an handler action. - * The action function will be invoked exactly once among all the - * simultaneous calls. The action will not be performed if the - * signal is not triggered, or if the triggered has already been - * handled. When an action is being performed, all the simultaneous - * callers will wait and be blocked up until its execution is finished. - * If the handler action throws an exception, it will be considered - * performed. After the first handler has been performed, every - * other invocation of handle() will be skipped and return false - * up until the next invocation of reset(). - * - * @param f The action to perform. - * @return true If the action has been performed. - * @return false If the action has not been performed. - */ - inline bool handle(std::function f) - { - if (triggered() && !handled()) - { - std::unique_lock lock(m_mtx); - if (!handled()) - { - try - { - f(); - // note: the action may have forcely reset - // the signal handler, so we don't want to create - // an inconsistent state - if (triggered()) - { - m_handled.store(true, std::memory_order_seq_cst); - } - } - catch (std::exception&) - { - if (triggered()) - { - m_handled.store(true, std::memory_order_seq_cst); - } - throw; - } - return true; - } - } - return false; - } + /** + * @brief If a signal is triggered, performs an handler action. + * The action function will be invoked exactly once among all the + * simultaneous calls. The action will not be performed if the + * signal is not triggered, or if the triggered has already been + * handled. When an action is being performed, all the simultaneous + * callers will wait and be blocked up until its execution is finished. + * If the handler action throws an exception, it will be considered + * performed. After the first handler has been performed, every + * other invocation of handle() will be skipped and return false + * up until the next invocation of reset(). + * + * @param f The action to perform. + * @return true If the action has been performed. + * @return false If the action has not been performed. + */ + inline bool handle(std::function f) { + if(triggered() && !handled()) { + std::unique_lock lock(m_mtx); + if(!handled()) { + try { + f(); + // note: the action may have forcely reset + // the signal handler, so we don't want to create + // an inconsistent state + if(triggered()) { + m_handled.store(true, std::memory_order_seq_cst); + } + } catch(std::exception&) { + if(triggered()) { + m_handled.store(true, std::memory_order_seq_cst); + } + throw; + } + return true; + } + } + return false; + } - private: - std::mutex m_mtx; - std::atomic m_triggered{false}; - std::atomic m_handled{false}; - }; +private: + std::mutex m_mtx; + std::atomic m_triggered{false}; + std::atomic m_handled{false}; }; +}; // namespace falco diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 457d7a25021..8673f37924a 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -43,50 +43,68 @@ limitations under the License. namespace fs = std::filesystem; // Reference: https://digitalfortress.tech/tips/top-15-commonly-used-regex/ -static re2::RE2 ip_address_re("((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))"); +static re2::RE2 ip_address_re( + "((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{" + "2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-" + "9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[" + "0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((" + "25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([" + "0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|" + "1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:)" + "{3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]" + "?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-" + "Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[" + "0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){" + "1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]" + "\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:(" + "(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(" + "%.+)?\\s*$))"); #define DEFAULT_BUF_SIZE_PRESET 4 #define DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER 2 #define DEFAULT_DROP_FAILED_EXIT false falco_configuration::falco_configuration(): - m_json_output(false), - m_json_include_output_property(true), - m_json_include_tags_property(true), - m_json_include_message_property(false), - m_rule_matching(falco_common::rule_matching::FIRST), - m_watch_config_files(true), - m_buffered_outputs(false), - m_outputs_queue_capacity(DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE), - m_time_format_iso_8601(false), - m_output_timeout(2000), - m_grpc_enabled(false), - m_grpc_threadiness(0), - m_webserver_enabled(false), - m_syscall_evt_drop_threshold(.1), - m_syscall_evt_drop_rate(.03333), - m_syscall_evt_drop_max_burst(1), - m_syscall_evt_simulate_drops(false), - m_syscall_evt_timeout_max_consecutives(1000), - m_falco_libs_thread_table_size(DEFAULT_FALCO_LIBS_THREAD_TABLE_SIZE), - m_base_syscalls_repair(false), - m_metrics_enabled(false), - m_metrics_interval_str("5000"), - m_metrics_interval(5000), - m_metrics_stats_rule_enabled(false), - m_metrics_output_file(""), - m_metrics_flags(0), - m_metrics_convert_memory_to_mb(true), - m_metrics_include_empty_values(false), - m_container_engines_mask(0), - m_container_engines_disable_cri_async(false), - m_container_engines_cri_socket_paths({"/run/containerd/containerd.sock", "/run/crio/crio.sock","/run/k3s/containerd/containerd.sock"}) -{ + m_json_output(false), + m_json_include_output_property(true), + m_json_include_tags_property(true), + m_json_include_message_property(false), + m_rule_matching(falco_common::rule_matching::FIRST), + m_watch_config_files(true), + m_buffered_outputs(false), + m_outputs_queue_capacity(DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE), + m_time_format_iso_8601(false), + m_output_timeout(2000), + m_grpc_enabled(false), + m_grpc_threadiness(0), + m_webserver_enabled(false), + m_syscall_evt_drop_threshold(.1), + m_syscall_evt_drop_rate(.03333), + m_syscall_evt_drop_max_burst(1), + m_syscall_evt_simulate_drops(false), + m_syscall_evt_timeout_max_consecutives(1000), + m_falco_libs_thread_table_size(DEFAULT_FALCO_LIBS_THREAD_TABLE_SIZE), + m_base_syscalls_repair(false), + m_metrics_enabled(false), + m_metrics_interval_str("5000"), + m_metrics_interval(5000), + m_metrics_stats_rule_enabled(false), + m_metrics_output_file(""), + m_metrics_flags(0), + m_metrics_convert_memory_to_mb(true), + m_metrics_include_empty_values(false), + m_container_engines_mask(0), + m_container_engines_disable_cri_async(false), + m_container_engines_cri_socket_paths({"/run/containerd/containerd.sock", + "/run/crio/crio.sock", + "/run/k3s/containerd/containerd.sock"}) { m_config_schema = nlohmann::json::parse(config_schema_string); } -config_loaded_res falco_configuration::init_from_content(const std::string& config_content, const std::vector& cmdline_options, const std::string& filename) -{ +config_loaded_res falco_configuration::init_from_content( + const std::string &config_content, + const std::vector &cmdline_options, + const std::string &filename) { config_loaded_res res; std::vector validation_status; @@ -100,16 +118,14 @@ config_loaded_res falco_configuration::init_from_content(const std::string& conf return res; } -config_loaded_res falco_configuration::init_from_file(const std::string& conf_filename, const std::vector &cmdline_options) -{ +config_loaded_res falco_configuration::init_from_file( + const std::string &conf_filename, + const std::vector &cmdline_options) { config_loaded_res res; std::vector validation_status; - try - { + try { m_config.load_from_file(conf_filename, m_config_schema, &validation_status); - } - catch(const std::exception& e) - { + } catch(const std::exception &e) { std::cerr << "Cannot read config file (" + conf_filename + "): " + e.what() + "\n"; throw e; } @@ -124,8 +140,7 @@ config_loaded_res falco_configuration::init_from_file(const std::string& conf_fi return res; } -std::string falco_configuration::dump() -{ +std::string falco_configuration::dump() { return m_config.dump(); } @@ -133,50 +148,45 @@ std::string falco_configuration::dump() // NOTE: loaded_config_files will resolve to the filepaths list of loaded config. // m_loaded_configs_filenames and m_loaded_configs_folders instead will hold the list of // filenames and folders specified in config (minus the skipped ones). -void falco_configuration::merge_config_files(const std::string& config_name, config_loaded_res &res) -{ +void falco_configuration::merge_config_files(const std::string &config_name, + config_loaded_res &res) { std::vector validation_status; m_loaded_configs_filenames.push_back(config_name); const auto ppath = std::filesystem::path(config_name); // Parse files to be included std::vector include_files; m_config.get_sequence>(include_files, yaml_helper::configs_key); - for(const std::string& include_file : include_files) - { + for(const std::string &include_file : include_files) { auto include_file_path = std::filesystem::path(include_file); - if (include_file_path == ppath) - { - throw std::logic_error( - "Config error: '" + yaml_helper::configs_key + "' directive tried to recursively include main config file: " + config_name + "."); + if(include_file_path == ppath) { + throw std::logic_error("Config error: '" + yaml_helper::configs_key + + "' directive tried to recursively include main config file: " + + config_name + "."); } - if (!std::filesystem::exists(include_file_path)) - { + if(!std::filesystem::exists(include_file_path)) { // Same we do for rules_file: just skip the entry. continue; } - if (std::filesystem::is_regular_file(include_file_path)) - { + if(std::filesystem::is_regular_file(include_file_path)) { m_loaded_configs_filenames.push_back(include_file); - m_config.include_config_file(include_file_path.string(), m_config_schema, &validation_status); + m_config.include_config_file(include_file_path.string(), + m_config_schema, + &validation_status); // Only report top most schema validation status res[include_file_path.string()] = validation_status[0]; - } - else if (std::filesystem::is_directory(include_file_path)) - { + } else if(std::filesystem::is_directory(include_file_path)) { m_loaded_configs_folders.push_back(include_file); std::vector v; - const auto it_options = std::filesystem::directory_options::follow_directory_symlink - | std::filesystem::directory_options::skip_permission_denied; - for (auto const& dir_entry : std::filesystem::directory_iterator(include_file_path, it_options)) - { - if (std::filesystem::is_regular_file(dir_entry.path())) - { + const auto it_options = std::filesystem::directory_options::follow_directory_symlink | + std::filesystem::directory_options::skip_permission_denied; + for(auto const &dir_entry : + std::filesystem::directory_iterator(include_file_path, it_options)) { + if(std::filesystem::is_regular_file(dir_entry.path())) { v.push_back(dir_entry.path().string()); } } std::sort(v.begin(), v.end()); - for (const auto &f : v) - { + for(const auto &f : v) { m_config.include_config_file(f, m_config_schema, &validation_status); // Only report top most schema validation status res[f] = validation_status[0]; @@ -185,85 +195,91 @@ void falco_configuration::merge_config_files(const std::string& config_name, con } #if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) - for(auto &filename : m_loaded_configs_filenames) - { - m_loaded_configs_filenames_sha256sum.insert({filename, falco::utils::calculate_file_sha256sum(filename)}); + for(auto &filename : m_loaded_configs_filenames) { + m_loaded_configs_filenames_sha256sum.insert( + {filename, falco::utils::calculate_file_sha256sum(filename)}); } #endif } -void falco_configuration::init_logger() -{ +void falco_configuration::init_logger() { m_log_level = m_config.get_scalar("log_level", "info"); falco_logger::set_level(m_log_level); falco_logger::set_sinsp_logging( - m_config.get_scalar("libs_logger.enabled", false), - m_config.get_scalar("libs_logger.severity", "debug"), - "[libs]: "); + m_config.get_scalar("libs_logger.enabled", false), + m_config.get_scalar("libs_logger.severity", "debug"), + "[libs]: "); falco_logger::log_stderr = m_config.get_scalar("log_stderr", false); falco_logger::log_syslog = m_config.get_scalar("log_syslog", true); } -void falco_configuration::load_engine_config(const std::string& config_name) -{ +void falco_configuration::load_engine_config(const std::string &config_name) { // Set driver mode if not already set. const std::unordered_map engine_mode_lut = { - {"kmod",engine_kind_t::KMOD}, - {"ebpf",engine_kind_t::EBPF}, - {"modern_ebpf",engine_kind_t::MODERN_EBPF}, - {"replay",engine_kind_t::REPLAY}, - {"gvisor",engine_kind_t::GVISOR}, - {"nodriver",engine_kind_t::NODRIVER}, + {"kmod", engine_kind_t::KMOD}, + {"ebpf", engine_kind_t::EBPF}, + {"modern_ebpf", engine_kind_t::MODERN_EBPF}, + {"replay", engine_kind_t::REPLAY}, + {"gvisor", engine_kind_t::GVISOR}, + {"nodriver", engine_kind_t::NODRIVER}, }; auto driver_mode_str = m_config.get_scalar("engine.kind", "kmod"); - if (engine_mode_lut.find(driver_mode_str) != engine_mode_lut.end()) - { + if(engine_mode_lut.find(driver_mode_str) != engine_mode_lut.end()) { m_engine_mode = engine_mode_lut.at(driver_mode_str); - } - else - { - throw std::logic_error("Error reading config file (" + config_name + "): engine.kind '"+ driver_mode_str + "' is not a valid kind."); + } else { + throw std::logic_error("Error reading config file (" + config_name + "): engine.kind '" + + driver_mode_str + "' is not a valid kind."); } - switch (m_engine_mode) - { + switch(m_engine_mode) { case engine_kind_t::KMOD: - m_kmod.m_buf_size_preset = m_config.get_scalar("engine.kmod.buf_size_preset", DEFAULT_BUF_SIZE_PRESET); - m_kmod.m_drop_failed_exit = m_config.get_scalar("engine.kmod.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); + m_kmod.m_buf_size_preset = m_config.get_scalar("engine.kmod.buf_size_preset", + DEFAULT_BUF_SIZE_PRESET); + m_kmod.m_drop_failed_exit = + m_config.get_scalar("engine.kmod.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); break; - case engine_kind_t::EBPF: - { - // default value for `m_probe_path` should be `$HOME/FALCO_PROBE_BPF_FILEPATH` - char full_path[PATH_MAX]; - const char *home = std::getenv("HOME"); - if(!home) - { - throw std::logic_error("Cannot get the env variable 'HOME'"); - } - snprintf(full_path, PATH_MAX, "%s/%s", home, FALCO_PROBE_BPF_FILEPATH); - m_ebpf.m_probe_path = m_config.get_scalar("engine.ebpf.probe", std::string(full_path)); - m_ebpf.m_buf_size_preset = m_config.get_scalar("engine.ebpf.buf_size_preset", DEFAULT_BUF_SIZE_PRESET); - m_ebpf.m_drop_failed_exit = m_config.get_scalar("engine.ebpf.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); + case engine_kind_t::EBPF: { + // default value for `m_probe_path` should be `$HOME/FALCO_PROBE_BPF_FILEPATH` + char full_path[PATH_MAX]; + const char *home = std::getenv("HOME"); + if(!home) { + throw std::logic_error("Cannot get the env variable 'HOME'"); } - break; + snprintf(full_path, PATH_MAX, "%s/%s", home, FALCO_PROBE_BPF_FILEPATH); + m_ebpf.m_probe_path = + m_config.get_scalar("engine.ebpf.probe", std::string(full_path)); + m_ebpf.m_buf_size_preset = m_config.get_scalar("engine.ebpf.buf_size_preset", + DEFAULT_BUF_SIZE_PRESET); + m_ebpf.m_drop_failed_exit = + m_config.get_scalar("engine.ebpf.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); + } break; case engine_kind_t::MODERN_EBPF: - m_modern_ebpf.m_cpus_for_each_buffer = m_config.get_scalar("engine.modern_ebpf.cpus_for_each_buffer", DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER); - m_modern_ebpf.m_buf_size_preset = m_config.get_scalar("engine.modern_ebpf.buf_size_preset", DEFAULT_BUF_SIZE_PRESET); - m_modern_ebpf.m_drop_failed_exit = m_config.get_scalar("engine.modern_ebpf.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); + m_modern_ebpf.m_cpus_for_each_buffer = + m_config.get_scalar("engine.modern_ebpf.cpus_for_each_buffer", + DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER); + m_modern_ebpf.m_buf_size_preset = + m_config.get_scalar("engine.modern_ebpf.buf_size_preset", + DEFAULT_BUF_SIZE_PRESET); + m_modern_ebpf.m_drop_failed_exit = + m_config.get_scalar("engine.modern_ebpf.drop_failed_exit", + DEFAULT_DROP_FAILED_EXIT); break; case engine_kind_t::REPLAY: - m_replay.m_capture_file = m_config.get_scalar("engine.replay.capture_file", ""); - if (m_replay.m_capture_file.empty()) - { - throw std::logic_error("Error reading config file (" + config_name + "): engine.kind is 'replay' but no engine.replay.capture_file specified."); + m_replay.m_capture_file = + m_config.get_scalar("engine.replay.capture_file", ""); + if(m_replay.m_capture_file.empty()) { + throw std::logic_error( + "Error reading config file (" + config_name + + "): engine.kind is 'replay' but no engine.replay.capture_file specified."); } break; case engine_kind_t::GVISOR: m_gvisor.m_config = m_config.get_scalar("engine.gvisor.config", ""); - if (m_gvisor.m_config.empty()) - { - throw std::logic_error("Error reading config file (" + config_name + "): engine.kind is 'gvisor' but no engine.gvisor.config specified."); + if(m_gvisor.m_config.empty()) { + throw std::logic_error( + "Error reading config file (" + config_name + + "): engine.kind is 'gvisor' but no engine.gvisor.config specified."); } m_gvisor.m_root = m_config.get_scalar("engine.gvisor.root", ""); break; @@ -273,8 +289,7 @@ void falco_configuration::load_engine_config(const std::string& config_name) } } -void falco_configuration::load_yaml(const std::string& config_name) -{ +void falco_configuration::load_yaml(const std::string &config_name) { init_logger(); load_engine_config(config_name); @@ -282,51 +297,50 @@ void falco_configuration::load_yaml(const std::string& config_name) // Small glue code to support old deprecated 'rules_file' config key. int num_rules_files_opts = 0; - if (m_config.is_defined("rules_files")) - { + if(m_config.is_defined("rules_files")) { num_rules_files_opts++; m_config.get_sequence>(rules_files, std::string("rules_files")); } - if (m_config.is_defined("rules_file")) - { + if(m_config.is_defined("rules_file")) { num_rules_files_opts++; m_config.get_sequence>(rules_files, std::string("rules_file")); - falco_logger::log(falco_logger::level::WARNING, "Using deprecated config key 'rules_file' (singular form). Please use new 'rules_files' config key (plural form)."); + falco_logger::log(falco_logger::level::WARNING, + "Using deprecated config key 'rules_file' (singular form). Please use " + "new 'rules_files' config key (plural form)."); } - if (num_rules_files_opts == 2) - { - throw std::logic_error("Error reading config file (" + config_name + "): both 'rules_files' and 'rules_file' keys set"); + if(num_rules_files_opts == 2) { + throw std::logic_error("Error reading config file (" + config_name + + "): both 'rules_files' and 'rules_file' keys set"); } m_rules_filenames.clear(); m_loaded_rules_filenames.clear(); m_loaded_rules_filenames_sha256sum.clear(); m_loaded_rules_folders.clear(); - for(auto &file : rules_files) - { + for(auto &file : rules_files) { // Here, we only include files that exist struct stat buffer; - if(stat(file.c_str(), &buffer) == 0) - { + if(stat(file.c_str(), &buffer) == 0) { m_rules_filenames.push_back(file); } } m_json_output = m_config.get_scalar("json_output", false); - m_json_include_output_property = m_config.get_scalar("json_include_output_property", true); + m_json_include_output_property = + m_config.get_scalar("json_include_output_property", true); m_json_include_tags_property = m_config.get_scalar("json_include_tags_property", true); - m_json_include_message_property = m_config.get_scalar("json_include_message_property", false); + m_json_include_message_property = + m_config.get_scalar("json_include_message_property", false); m_outputs.clear(); falco::outputs::config file_output; file_output.name = "file"; - if(m_config.get_scalar("file_output.enabled", false)) - { + if(m_config.get_scalar("file_output.enabled", false)) { std::string filename, keep_alive; filename = m_config.get_scalar("file_output.filename", ""); - if(filename == std::string("")) - { - throw std::logic_error("Error reading config file (" + config_name + "): file output enabled but no filename in configuration block"); + if(filename == std::string("")) { + throw std::logic_error("Error reading config file (" + config_name + + "): file output enabled but no filename in configuration block"); } file_output.options["filename"] = filename; @@ -338,27 +352,25 @@ void falco_configuration::load_yaml(const std::string& config_name) falco::outputs::config stdout_output; stdout_output.name = "stdout"; - if(m_config.get_scalar("stdout_output.enabled", false)) - { + if(m_config.get_scalar("stdout_output.enabled", false)) { m_outputs.push_back(stdout_output); } falco::outputs::config syslog_output; syslog_output.name = "syslog"; - if(m_config.get_scalar("syslog_output.enabled", false)) - { + if(m_config.get_scalar("syslog_output.enabled", false)) { m_outputs.push_back(syslog_output); } falco::outputs::config program_output; program_output.name = "program"; - if(m_config.get_scalar("program_output.enabled", false)) - { + if(m_config.get_scalar("program_output.enabled", false)) { std::string program, keep_alive; program = m_config.get_scalar("program_output.program", ""); - if(program == std::string("")) - { - throw std::logic_error("Error reading config file (" + config_name + "): program output enabled but no program in configuration block"); + if(program == std::string("")) { + throw std::logic_error( + "Error reading config file (" + config_name + + "): program output enabled but no program in configuration block"); } program_output.options["program"] = program; @@ -370,29 +382,29 @@ void falco_configuration::load_yaml(const std::string& config_name) falco::outputs::config http_output; http_output.name = "http"; - if(m_config.get_scalar("http_output.enabled", false)) - { + if(m_config.get_scalar("http_output.enabled", false)) { std::string url; url = m_config.get_scalar("http_output.url", ""); - if(url == std::string("")) - { - throw std::logic_error("Error reading config file (" + config_name + "): http output enabled but no url in configuration block"); + if(url == std::string("")) { + throw std::logic_error("Error reading config file (" + config_name + + "): http output enabled but no url in configuration block"); } http_output.options["url"] = url; std::string user_agent; - user_agent = m_config.get_scalar("http_output.user_agent","falcosecurity/falco"); + user_agent = + m_config.get_scalar("http_output.user_agent", "falcosecurity/falco"); http_output.options["user_agent"] = user_agent; bool insecure; insecure = m_config.get_scalar("http_output.insecure", false); - http_output.options["insecure"] = insecure? std::string("true") : std::string("false"); + http_output.options["insecure"] = insecure ? std::string("true") : std::string("false"); bool echo; echo = m_config.get_scalar("http_output.echo", false); - http_output.options["echo"] = echo? std::string("true") : std::string("false"); - + http_output.options["echo"] = echo ? std::string("true") : std::string("false"); + std::string ca_cert; ca_cert = m_config.get_scalar("http_output.ca_cert", ""); http_output.options["ca_cert"] = ca_cert; @@ -407,23 +419,26 @@ void falco_configuration::load_yaml(const std::string& config_name) bool mtls; mtls = m_config.get_scalar("http_output.mtls", false); - http_output.options["mtls"] = mtls? std::string("true") : std::string("false"); + http_output.options["mtls"] = mtls ? std::string("true") : std::string("false"); std::string client_cert; - client_cert = m_config.get_scalar("http_output.client_cert", "/etc/ssl/certs/client.crt"); + client_cert = m_config.get_scalar("http_output.client_cert", + "/etc/ssl/certs/client.crt"); http_output.options["client_cert"] = client_cert; std::string client_key; - client_key = m_config.get_scalar("http_output.client_key", "/etc/ssl/certs/client.key"); + client_key = m_config.get_scalar("http_output.client_key", + "/etc/ssl/certs/client.key"); http_output.options["client_key"] = client_key; bool compress_uploads; compress_uploads = m_config.get_scalar("http_output.compress_uploads", false); - http_output.options["compress_uploads"] = compress_uploads? std::string("true") : std::string("false"); + http_output.options["compress_uploads"] = + compress_uploads ? std::string("true") : std::string("false"); bool keep_alive; keep_alive = m_config.get_scalar("http_output.keep_alive", false); - http_output.options["keep_alive"] = keep_alive? std::string("true") : std::string("false"); + http_output.options["keep_alive"] = keep_alive ? std::string("true") : std::string("false"); m_outputs.push_back(http_output); } @@ -431,42 +446,45 @@ void falco_configuration::load_yaml(const std::string& config_name) m_grpc_enabled = m_config.get_scalar("grpc.enabled", false); m_grpc_bind_address = m_config.get_scalar("grpc.bind_address", "0.0.0.0:5060"); m_grpc_threadiness = m_config.get_scalar("grpc.threadiness", 0); - if(m_grpc_threadiness == 0) - { + if(m_grpc_threadiness == 0) { m_grpc_threadiness = falco::utils::hardware_concurrency(); } // todo > else limit threadiness to avoid oversubscription? - m_grpc_private_key = m_config.get_scalar("grpc.private_key", "/etc/falco/certs/server.key"); - m_grpc_cert_chain = m_config.get_scalar("grpc.cert_chain", "/etc/falco/certs/server.crt"); - m_grpc_root_certs = m_config.get_scalar("grpc.root_certs", "/etc/falco/certs/ca.crt"); + m_grpc_private_key = + m_config.get_scalar("grpc.private_key", "/etc/falco/certs/server.key"); + m_grpc_cert_chain = + m_config.get_scalar("grpc.cert_chain", "/etc/falco/certs/server.crt"); + m_grpc_root_certs = + m_config.get_scalar("grpc.root_certs", "/etc/falco/certs/ca.crt"); falco::outputs::config grpc_output; grpc_output.name = "grpc"; // gRPC output is enabled only if gRPC server is enabled too - if(m_config.get_scalar("grpc_output.enabled", true) && m_grpc_enabled) - { + if(m_config.get_scalar("grpc_output.enabled", true) && m_grpc_enabled) { m_outputs.push_back(grpc_output); } m_output_timeout = m_config.get_scalar("output_timeout", 2000); std::string rule_matching = m_config.get_scalar("rule_matching", "first"); - if (!falco_common::parse_rule_matching(rule_matching, m_rule_matching)) - { - throw std::logic_error("Unknown rule matching strategy \"" + rule_matching + "\"--must be one of first, all"); + if(!falco_common::parse_rule_matching(rule_matching, m_rule_matching)) { + throw std::logic_error("Unknown rule matching strategy \"" + rule_matching + + "\"--must be one of first, all"); } std::string priority = m_config.get_scalar("priority", "debug"); - if (!falco_common::parse_priority(priority, m_min_priority)) - { - throw std::logic_error("Unknown priority \"" + priority + "\"--must be one of emergency, alert, critical, error, warning, notice, informational, debug"); + if(!falco_common::parse_priority(priority, m_min_priority)) { + throw std::logic_error("Unknown priority \"" + priority + + "\"--must be one of emergency, alert, critical, error, warning, " + "notice, informational, debug"); } m_buffered_outputs = m_config.get_scalar("buffered_outputs", false); - m_outputs_queue_capacity = m_config.get_scalar("outputs_queue.capacity", DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE); - // We use 0 in falco.yaml to indicate an unbounded queue; equivalent to the largest long value - if (m_outputs_queue_capacity == 0) - { + m_outputs_queue_capacity = + m_config.get_scalar("outputs_queue.capacity", + DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE); + // We use 0 in falco.yaml to indicate an unbounded queue; equivalent to the largest long value + if(m_outputs_queue_capacity == 0) { m_outputs_queue_capacity = DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE; } @@ -475,81 +493,85 @@ void falco_configuration::load_yaml(const std::string& config_name) m_webserver_enabled = m_config.get_scalar("webserver.enabled", false); m_webserver_config.m_threadiness = m_config.get_scalar("webserver.threadiness", 0); m_webserver_config.m_listen_port = m_config.get_scalar("webserver.listen_port", 8765); - m_webserver_config.m_listen_address = m_config.get_scalar("webserver.listen_address", "0.0.0.0"); - if(!re2::RE2::FullMatch(m_webserver_config.m_listen_address, ip_address_re)) - { - throw std::logic_error("Error reading config file (" + config_name + "): webserver listen address \"" + m_webserver_config.m_listen_address + "\" is not a valid IP address"); + m_webserver_config.m_listen_address = + m_config.get_scalar("webserver.listen_address", "0.0.0.0"); + if(!re2::RE2::FullMatch(m_webserver_config.m_listen_address, ip_address_re)) { + throw std::logic_error( + "Error reading config file (" + config_name + "): webserver listen address \"" + + m_webserver_config.m_listen_address + "\" is not a valid IP address"); } - m_webserver_config.m_k8s_healthz_endpoint = m_config.get_scalar("webserver.k8s_healthz_endpoint", "/healthz"); + m_webserver_config.m_k8s_healthz_endpoint = + m_config.get_scalar("webserver.k8s_healthz_endpoint", "/healthz"); m_webserver_config.m_ssl_enabled = m_config.get_scalar("webserver.ssl_enabled", false); - m_webserver_config.m_ssl_certificate = m_config.get_scalar("webserver.ssl_certificate", "/etc/falco/falco.pem"); - if(m_webserver_config.m_threadiness == 0) - { + m_webserver_config.m_ssl_certificate = + m_config.get_scalar("webserver.ssl_certificate", "/etc/falco/falco.pem"); + if(m_webserver_config.m_threadiness == 0) { m_webserver_config.m_threadiness = falco::utils::hardware_concurrency(); } - m_webserver_config.m_prometheus_metrics_enabled = m_config.get_scalar("webserver.prometheus_metrics_enabled", false); + m_webserver_config.m_prometheus_metrics_enabled = + m_config.get_scalar("webserver.prometheus_metrics_enabled", false); std::list syscall_event_drop_acts; m_config.get_sequence(syscall_event_drop_acts, "syscall_event_drops.actions"); m_syscall_evt_drop_actions.clear(); - for(const std::string &act : syscall_event_drop_acts) - { - if(act == "ignore") - { + for(const std::string &act : syscall_event_drop_acts) { + if(act == "ignore") { m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::DISREGARD); - } - else if(act == "log") - { - if(m_syscall_evt_drop_actions.count(syscall_evt_drop_action::DISREGARD)) - { - throw std::logic_error("Error reading config file (" + config_name + "): syscall event drop action \"" + act + "\" does not make sense with the \"ignore\" action"); + } else if(act == "log") { + if(m_syscall_evt_drop_actions.count(syscall_evt_drop_action::DISREGARD)) { + throw std::logic_error("Error reading config file (" + config_name + + "): syscall event drop action \"" + act + + "\" does not make sense with the \"ignore\" action"); } m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::LOG); - } - else if(act == "alert") - { - if(m_syscall_evt_drop_actions.count(syscall_evt_drop_action::DISREGARD)) - { - throw std::logic_error("Error reading config file (" + config_name + "): syscall event drop action \"" + act + "\" does not make sense with the \"ignore\" action"); + } else if(act == "alert") { + if(m_syscall_evt_drop_actions.count(syscall_evt_drop_action::DISREGARD)) { + throw std::logic_error("Error reading config file (" + config_name + + "): syscall event drop action \"" + act + + "\" does not make sense with the \"ignore\" action"); } m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::ALERT); - } - else if(act == "exit") - { + } else if(act == "exit") { m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::EXIT); - } - else - { - throw std::logic_error("Error reading config file (" + config_name + "): available actions for syscall event drops are \"ignore\", \"log\", \"alert\", and \"exit\""); + } else { + throw std::logic_error("Error reading config file (" + config_name + + "): available actions for syscall event drops are \"ignore\", " + "\"log\", \"alert\", and \"exit\""); } } - if(m_syscall_evt_drop_actions.empty()) - { + if(m_syscall_evt_drop_actions.empty()) { m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::DISREGARD); } m_syscall_evt_drop_threshold = m_config.get_scalar("syscall_event_drops.threshold", .1); - if(m_syscall_evt_drop_threshold < 0 || m_syscall_evt_drop_threshold > 1) - { - throw std::logic_error("Error reading config file (" + config_name + "): syscall event drops threshold must be a double in the range [0, 1]"); + if(m_syscall_evt_drop_threshold < 0 || m_syscall_evt_drop_threshold > 1) { + throw std::logic_error( + "Error reading config file (" + config_name + + "): syscall event drops threshold must be a double in the range [0, 1]"); } m_syscall_evt_drop_rate = m_config.get_scalar("syscall_event_drops.rate", .03333); m_syscall_evt_drop_max_burst = m_config.get_scalar("syscall_event_drops.max_burst", 1); - m_syscall_evt_simulate_drops = m_config.get_scalar("syscall_event_drops.simulate_drops", false); + m_syscall_evt_simulate_drops = + m_config.get_scalar("syscall_event_drops.simulate_drops", false); - m_syscall_evt_timeout_max_consecutives = m_config.get_scalar("syscall_event_timeouts.max_consecutives", 1000); - if(m_syscall_evt_timeout_max_consecutives == 0) - { - throw std::logic_error("Error reading config file(" + config_name + "): the maximum consecutive timeouts without an event must be an unsigned integer > 0"); + m_syscall_evt_timeout_max_consecutives = + m_config.get_scalar("syscall_event_timeouts.max_consecutives", 1000); + if(m_syscall_evt_timeout_max_consecutives == 0) { + throw std::logic_error("Error reading config file(" + config_name + + "): the maximum consecutive timeouts without an event must be an " + "unsigned integer > 0"); } - m_falco_libs_thread_table_size = m_config.get_scalar("falco_libs.thread_table_size", DEFAULT_FALCO_LIBS_THREAD_TABLE_SIZE); + m_falco_libs_thread_table_size = + m_config.get_scalar("falco_libs.thread_table_size", + DEFAULT_FALCO_LIBS_THREAD_TABLE_SIZE); m_base_syscalls_custom_set.clear(); - m_config.get_sequence>(m_base_syscalls_custom_set, std::string("base_syscalls.custom_set")); + m_config.get_sequence>(m_base_syscalls_custom_set, + std::string("base_syscalls.custom_set")); m_base_syscalls_repair = m_config.get_scalar("base_syscalls.repair", false); m_metrics_enabled = m_config.get_scalar("metrics.enabled", false); @@ -559,50 +581,42 @@ void falco_configuration::load_yaml(const std::string& config_name) m_metrics_output_file = m_config.get_scalar("metrics.output_file", ""); m_metrics_flags = 0; - if (m_config.get_scalar("metrics.rules_counters_enabled", true)) - { + if(m_config.get_scalar("metrics.rules_counters_enabled", true)) { m_metrics_flags |= METRICS_V2_RULE_COUNTERS; } - if (m_config.get_scalar("metrics.resource_utilization_enabled", true)) - { + if(m_config.get_scalar("metrics.resource_utilization_enabled", true)) { m_metrics_flags |= METRICS_V2_RESOURCE_UTILIZATION; } - if (m_config.get_scalar("metrics.state_counters_enabled", true)) - { + if(m_config.get_scalar("metrics.state_counters_enabled", true)) { m_metrics_flags |= METRICS_V2_STATE_COUNTERS; } - if (m_config.get_scalar("metrics.kernel_event_counters_enabled", true)) - { + if(m_config.get_scalar("metrics.kernel_event_counters_enabled", true)) { m_metrics_flags |= METRICS_V2_KERNEL_COUNTERS; } - if (m_config.get_scalar("metrics.kernel_event_counters_per_cpu_enabled", true)) - { + if(m_config.get_scalar("metrics.kernel_event_counters_per_cpu_enabled", true)) { m_metrics_flags |= METRICS_V2_KERNEL_COUNTERS_PER_CPU; } - if (m_config.get_scalar("metrics.libbpf_stats_enabled", true)) - { + if(m_config.get_scalar("metrics.libbpf_stats_enabled", true)) { m_metrics_flags |= METRICS_V2_LIBBPF_STATS; } - if (m_config.get_scalar("metrics.plugins_metrics_enabled", true)) - { + if(m_config.get_scalar("metrics.plugins_metrics_enabled", true)) { m_metrics_flags |= METRICS_V2_PLUGINS; } - m_metrics_convert_memory_to_mb = m_config.get_scalar("metrics.convert_memory_to_mb", true); - m_metrics_include_empty_values = m_config.get_scalar("metrics.include_empty_values", false); + m_metrics_convert_memory_to_mb = + m_config.get_scalar("metrics.convert_memory_to_mb", true); + m_metrics_include_empty_values = + m_config.get_scalar("metrics.include_empty_values", false); m_config.get_sequence>(m_rules_selection, "rules"); m_config.get_sequence>(m_append_output, "append_output"); // check if append_output matching conditions are sane, if not emit a warning - for (auto const& entry : m_append_output) - { - if (entry.m_rule != "" && entry.m_tags.size() > 0) - { + for(auto const &entry : m_append_output) { + if(entry.m_rule != "" && entry.m_tags.size() > 0) { std::string tag_list; - for (auto const& tag : entry.m_tags) - { + for(auto const &tag : entry.m_tags) { tag_list += tag; tag_list += ", "; } @@ -610,9 +624,11 @@ void falco_configuration::load_yaml(const std::string& config_name) tag_list.pop_back(); falco_logger::log(falco_logger::level::WARNING, - "An append_ouptut entry specifies both a rule (" + entry.m_rule + ") and a list of tags (" + tag_list + std::string("). ") + - "This means that output will be appended only to the " + entry.m_rule + " rule and only if it has " + - "all the tags: " + tag_list + "."); + "An append_ouptut entry specifies both a rule (" + entry.m_rule + + ") and a list of tags (" + tag_list + std::string("). ") + + "This means that output will be appended only to the " + + entry.m_rule + " rule and only if it has " + + "all the tags: " + tag_list + "."); } } @@ -622,94 +638,79 @@ void falco_configuration::load_yaml(const std::string& config_name) m_config.get_sequence>(load_plugins, "load_plugins"); std::list plugins; - try - { - if (m_config.is_defined("plugins")) - { - m_config.get_sequence>(plugins, std::string("plugins")); + try { + if(m_config.is_defined("plugins")) { + m_config.get_sequence>( + plugins, + std::string("plugins")); } - } - catch (std::exception &e) - { + } catch(std::exception &e) { // Might be thrown due to not being able to open files - throw std::logic_error("Error reading config file(" + config_name + "): could not load plugins config: " + e.what()); + throw std::logic_error("Error reading config file(" + config_name + + "): could not load plugins config: " + e.what()); } // If load_plugins was specified, only save plugins matching those in values m_plugins.clear(); - if (!load_plugins_node_defined) - { + if(!load_plugins_node_defined) { // If load_plugins was not specified at all, every plugin is added. // The loading order is the same as the sequence in the YAML m_config. - m_plugins = { plugins.begin(), plugins.end() }; - } - else - { + m_plugins = {plugins.begin(), plugins.end()}; + } else { // If load_plugins is specified, only plugins contained in its list // are added, with the same order as in the list. - for (const auto& pname : load_plugins) - { + for(const auto &pname : load_plugins) { bool found = false; - for (const auto& p : plugins) - { - if (pname == p.m_name) - { + for(const auto &p : plugins) { + if(pname == p.m_name) { m_plugins.push_back(p); found = true; break; } } - if (!found) - { - throw std::logic_error("Cannot load plugin '" + pname + "': plugin config not found for given name"); + if(!found) { + throw std::logic_error("Cannot load plugin '" + pname + + "': plugin config not found for given name"); } } } - m_watch_config_files = m_config.get_scalar("watch_config_files", true); - if(m_config.get_scalar("container_engines.docker.enabled", true)) - { + if(m_config.get_scalar("container_engines.docker.enabled", true)) { m_container_engines_mask |= (1 << CT_DOCKER); } - if(m_config.get_scalar("container_engines.podman.enabled", true)) - { + if(m_config.get_scalar("container_engines.podman.enabled", true)) { m_container_engines_mask |= (1 << CT_PODMAN); } - if(m_config.get_scalar("container_engines.cri.enabled", true)) - { - m_container_engines_mask |= ((1 << CT_CRI) | - (1 << CT_CRIO) | - (1 << CT_CONTAINERD)); + if(m_config.get_scalar("container_engines.cri.enabled", true)) { + m_container_engines_mask |= ((1 << CT_CRI) | (1 << CT_CRIO) | (1 << CT_CONTAINERD)); m_container_engines_cri_socket_paths.clear(); - m_config.get_sequence>(m_container_engines_cri_socket_paths, "container_engines.cri.cri"); - m_container_engines_disable_cri_async = m_config.get_scalar("container_engines.cri.disable-cri-async", false); + m_config.get_sequence>(m_container_engines_cri_socket_paths, + "container_engines.cri.cri"); + m_container_engines_disable_cri_async = + m_config.get_scalar("container_engines.cri.disable-cri-async", false); } - if(m_config.get_scalar("container_engines.lxc.enabled", true)) - { + if(m_config.get_scalar("container_engines.lxc.enabled", true)) { m_container_engines_mask |= (1 << CT_LXC); } - if(m_config.get_scalar("container_engines.libvirt_lxc.enabled", true)) - { + if(m_config.get_scalar("container_engines.libvirt_lxc.enabled", true)) { m_container_engines_mask |= (1 << CT_LIBVIRT_LXC); } - if(m_config.get_scalar("container_engines.rocket.enabled", true)) - { + if(m_config.get_scalar("container_engines.rocket.enabled", true)) { m_container_engines_mask |= (1 << CT_RKT); } - if(m_config.get_scalar("container_engines.bpm.enabled", true)) - { + if(m_config.get_scalar("container_engines.bpm.enabled", true)) { m_container_engines_mask |= (1 << CT_BPM); } } -void falco_configuration::read_rules_file_directory(const std::string &path, std::list &rules_filenames, std::list &rules_folders) -{ +void falco_configuration::read_rules_file_directory(const std::string &path, + std::list &rules_filenames, + std::list &rules_folders) { fs::path rules_path = std::string(path); - if(fs::is_directory(rules_path)) - { + if(fs::is_directory(rules_path)) { rules_folders.push_back(path); // It's a directory. Read the contents, sort @@ -717,27 +718,21 @@ void falco_configuration::read_rules_file_directory(const std::string &path, std // rules_filenames std::vector dir_filenames; - const auto it_options = fs::directory_options::follow_directory_symlink - | fs::directory_options::skip_permission_denied; + const auto it_options = fs::directory_options::follow_directory_symlink | + fs::directory_options::skip_permission_denied; - for (auto const& dir_entry : fs::directory_iterator(rules_path, it_options)) - { - if(std::filesystem::is_regular_file(dir_entry.path())) - { + for(auto const &dir_entry : fs::directory_iterator(rules_path, it_options)) { + if(std::filesystem::is_regular_file(dir_entry.path())) { dir_filenames.push_back(dir_entry.path().string()); } } - std::sort(dir_filenames.begin(), - dir_filenames.end()); + std::sort(dir_filenames.begin(), dir_filenames.end()); - for(std::string &ent : dir_filenames) - { + for(std::string &ent : dir_filenames) { rules_filenames.push_back(ent); } - } - else - { + } else { // Assume it's a file and just add to // rules_filenames. If it can't be opened/etc that // will be reported later.. @@ -745,12 +740,10 @@ void falco_configuration::read_rules_file_directory(const std::string &path, std } } -static bool split(const std::string &str, char delim, std::pair &parts) -{ +static bool split(const std::string &str, char delim, std::pair &parts) { size_t pos; - if((pos = str.find_first_of(delim)) == std::string::npos) - { + if((pos = str.find_first_of(delim)) == std::string::npos) { return false; } parts.first = str.substr(0, pos); @@ -759,29 +752,24 @@ static bool split(const std::string &str, char delim, std::pair &cmdline_options) -{ - for(const std::string &option : cmdline_options) - { +void falco_configuration::init_cmdline_options(const std::vector &cmdline_options) { + for(const std::string &option : cmdline_options) { set_cmdline_option(option); } } -void falco_configuration::set_cmdline_option(const std::string &opt) -{ +void falco_configuration::set_cmdline_option(const std::string &opt) { std::pair keyval; - if(!split(opt, '=', keyval)) - { - throw std::logic_error("Error parsing config option \"" + opt + "\". Must be of the form key=val or key.subkey=val"); + if(!split(opt, '=', keyval)) { + throw std::logic_error("Error parsing config option \"" + opt + + "\". Must be of the form key=val or key.subkey=val"); } - if (keyval.second[0] == '{' && keyval.second[keyval.second.size() - 1] == '}') - { + if(keyval.second[0] == '{' && keyval.second[keyval.second.size() - 1] == '}') { YAML::Node node = YAML::Load(keyval.second); m_config.set_object(keyval.first, node); - } else - { + } else { m_config.set_scalar(keyval.first, keyval.second); } } diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 2a3b763ea7c..d0b9e4a6018 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -37,21 +37,12 @@ limitations under the License. #include "event_drops.h" #include "falco_outputs.h" -enum class engine_kind_t : uint8_t -{ - KMOD, - EBPF, - MODERN_EBPF, - REPLAY, - GVISOR, - NODRIVER -}; +enum class engine_kind_t : uint8_t { KMOD, EBPF, MODERN_EBPF, REPLAY, GVISOR, NODRIVER }; // Map that holds { config filename | validation status } for each loaded config file. typedef std::map config_loaded_res; -class falco_configuration -{ +class falco_configuration { public: struct plugin_config { std::string m_name; @@ -96,10 +87,7 @@ class falco_configuration bool m_prometheus_metrics_enabled = false; }; - enum class rule_selection_operation { - enable, - disable - }; + enum class rule_selection_operation { enable, disable }; struct rule_selection_config { rule_selection_operation m_op; @@ -119,12 +107,17 @@ class falco_configuration falco_configuration(); virtual ~falco_configuration() = default; - config_loaded_res init_from_file(const std::string& conf_filename, const std::vector& cmdline_options); - config_loaded_res init_from_content(const std::string& config_content, const std::vector& cmdline_options, const std::string& filename="default"); + config_loaded_res init_from_file(const std::string& conf_filename, + const std::vector& cmdline_options); + config_loaded_res init_from_content(const std::string& config_content, + const std::vector& cmdline_options, + const std::string& filename = "default"); std::string dump(); - static void read_rules_file_directory(const std::string& path, std::list& rules_filenames, std::list &rules_folders); + static void read_rules_file_directory(const std::string& path, + std::list& rules_filenames, + std::list& rules_folders); // Config list as passed by the user. Filenames. std::list m_loaded_configs_filenames; @@ -215,7 +208,7 @@ class falco_configuration nlohmann::json m_config_schema; private: - void merge_config_files(const std::string& config_name, config_loaded_res &res); + void merge_config_files(const std::string& config_name, config_loaded_res& res); void load_yaml(const std::string& config_name); void init_logger(); void load_engine_config(const std::string& config_name); @@ -230,239 +223,196 @@ class falco_configuration }; namespace YAML { - template<> - struct convert { - static bool decode(const Node& node, falco_configuration::append_output_config & rhs) { - if(!node.IsMap()) - { - return false; - } - - if(node["match"]) - { - auto& match = node["match"]; +template<> +struct convert { + static bool decode(const Node& node, falco_configuration::append_output_config& rhs) { + if(!node.IsMap()) { + return false; + } - if(match["source"]) - { - rhs.m_source = match["source"].as(); - } + if(node["match"]) { + auto& match = node["match"]; - if(match["tags"] && match["tags"].IsSequence()) - { - for(auto& tag : match["tags"]) - { - if (!tag.IsScalar()) - { - return false; - } + if(match["source"]) { + rhs.m_source = match["source"].as(); + } - rhs.m_tags.insert(tag.as()); + if(match["tags"] && match["tags"].IsSequence()) { + for(auto& tag : match["tags"]) { + if(!tag.IsScalar()) { + return false; } - } - if(match["rule"]) - { - rhs.m_rule = match["rule"].as(); + rhs.m_tags.insert(tag.as()); } } - if(node["extra_output"]) - { - rhs.m_format = node["extra_output"].as(); + if(match["rule"]) { + rhs.m_rule = match["rule"].as(); } + } - if(node["extra_fields"]) - { - if(!node["extra_fields"].IsSequence()) - { - return false; - } + if(node["extra_output"]) { + rhs.m_format = node["extra_output"].as(); + } + + if(node["extra_fields"]) { + if(!node["extra_fields"].IsSequence()) { + return false; + } + + for(auto& field_definition : node["extra_fields"]) { + if(field_definition.IsMap() && field_definition.size() == 1) { + YAML::const_iterator def = field_definition.begin(); + std::string key = def->first.as(); - for(auto& field_definition : node["extra_fields"]) - { - if(field_definition.IsMap() && field_definition.size() == 1) - { - YAML::const_iterator def = field_definition.begin(); - std::string key = def->first.as(); - - // it is an error to redefine an existing key - if (rhs.m_formatted_fields.count(key) != 0 || rhs.m_raw_fields.count(key) != 0) - { - return false; - } - - rhs.m_formatted_fields[key] = def->second.as(); - } else if (field_definition.IsScalar()) - { - std::string key = field_definition.as(); - - // it is an error to redefine an existing key - if (rhs.m_formatted_fields.count(key) != 0) - { - return false; - } - - rhs.m_raw_fields.insert(key); - } else { + // it is an error to redefine an existing key + if(rhs.m_formatted_fields.count(key) != 0 || rhs.m_raw_fields.count(key) != 0) { return false; } + + rhs.m_formatted_fields[key] = def->second.as(); + } else if(field_definition.IsScalar()) { + std::string key = field_definition.as(); + + // it is an error to redefine an existing key + if(rhs.m_formatted_fields.count(key) != 0) { + return false; + } + + rhs.m_raw_fields.insert(key); + } else { + return false; } } - - return true; } - }; - template<> - struct convert { - static Node encode(const falco_configuration::rule_selection_config & rhs) { - Node node; - Node subnode; - if(rhs.m_rule != "") - { - subnode["rule"] = rhs.m_rule; - } + return true; + } +}; - if(rhs.m_tag != "") - { - subnode["tag"] = rhs.m_tag; - } - - if(rhs.m_op == falco_configuration::rule_selection_operation::enable) - { - node["enable"] = subnode; - } - else if(rhs.m_op == falco_configuration::rule_selection_operation::disable) - { - node["disable"] = subnode; - } +template<> +struct convert { + static Node encode(const falco_configuration::rule_selection_config& rhs) { + Node node; + Node subnode; + if(rhs.m_rule != "") { + subnode["rule"] = rhs.m_rule; + } - return node; + if(rhs.m_tag != "") { + subnode["tag"] = rhs.m_tag; } - static bool decode(const Node& node, falco_configuration::rule_selection_config & rhs) { - if(!node.IsMap()) - { - return false; - } + if(rhs.m_op == falco_configuration::rule_selection_operation::enable) { + node["enable"] = subnode; + } else if(rhs.m_op == falco_configuration::rule_selection_operation::disable) { + node["disable"] = subnode; + } - if(node["enable"]) - { - rhs.m_op = falco_configuration::rule_selection_operation::enable; + return node; + } - const Node& enable = node["enable"]; - if(!enable.IsMap()) - { - return false; - } + static bool decode(const Node& node, falco_configuration::rule_selection_config& rhs) { + if(!node.IsMap()) { + return false; + } - if(enable["rule"]) - { - rhs.m_rule = enable["rule"].as(); - } - if(enable["tag"]) - { - rhs.m_tag = enable["tag"].as(); - } - } - else if(node["disable"]) - { - rhs.m_op = falco_configuration::rule_selection_operation::disable; + if(node["enable"]) { + rhs.m_op = falco_configuration::rule_selection_operation::enable; - const Node& disable = node["disable"]; - if(!disable.IsMap()) - { - return false; - } + const Node& enable = node["enable"]; + if(!enable.IsMap()) { + return false; + } - if(disable["rule"]) - { - rhs.m_rule = disable["rule"].as(); - } - if(disable["tag"]) - { - rhs.m_tag = disable["tag"].as(); - } + if(enable["rule"]) { + rhs.m_rule = enable["rule"].as(); } - else - { - return false; + if(enable["tag"]) { + rhs.m_tag = enable["tag"].as(); } + } else if(node["disable"]) { + rhs.m_op = falco_configuration::rule_selection_operation::disable; - if (rhs.m_rule == "" && rhs.m_tag == "") - { + const Node& disable = node["disable"]; + if(!disable.IsMap()) { return false; } - return true; + if(disable["rule"]) { + rhs.m_rule = disable["rule"].as(); + } + if(disable["tag"]) { + rhs.m_tag = disable["tag"].as(); + } + } else { + return false; } - }; - template<> - struct convert { - - // Note that this loses the distinction between init configs - // defined as YAML maps or as opaque strings. - static Node encode(const falco_configuration::plugin_config & rhs) { - Node node; - node["name"] = rhs.m_name; - node["library_path"] = rhs.m_library_path; - node["init_config"] = rhs.m_init_config; - node["open_params"] = rhs.m_open_params; - return node; + if(rhs.m_rule == "" && rhs.m_tag == "") { + return false; } - static bool decode(const Node& node, falco_configuration::plugin_config & rhs) { - if(!node.IsMap()) - { - return false; - } + return true; + } +}; - if(!node["name"]) - { - return false; - } - rhs.m_name = node["name"].as(); +template<> +struct convert { + // Note that this loses the distinction between init configs + // defined as YAML maps or as opaque strings. + static Node encode(const falco_configuration::plugin_config& rhs) { + Node node; + node["name"] = rhs.m_name; + node["library_path"] = rhs.m_library_path; + node["init_config"] = rhs.m_init_config; + node["open_params"] = rhs.m_open_params; + return node; + } + + static bool decode(const Node& node, falco_configuration::plugin_config& rhs) { + if(!node.IsMap()) { + return false; + } - if(!node["library_path"]) - { - return false; - } - rhs.m_library_path = node["library_path"].as(); - if(!rhs.m_library_path.empty() && rhs.m_library_path.at(0) != '/') - { - // prepend share dir if path is not absolute - rhs.m_library_path = std::string(FALCO_ENGINE_PLUGINS_DIR) + rhs.m_library_path; - } + if(!node["name"]) { + return false; + } + rhs.m_name = node["name"].as(); - if(node["init_config"] && !node["init_config"].IsNull()) - { - // 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::decode(node["init_config"], json); - rhs.m_init_config = json.dump(); - } - else - { - rhs.m_init_config = node["init_config"].as(); - } - } + if(!node["library_path"]) { + return false; + } + rhs.m_library_path = node["library_path"].as(); + if(!rhs.m_library_path.empty() && rhs.m_library_path.at(0) != '/') { + // prepend share dir if path is not absolute + rhs.m_library_path = std::string(FALCO_ENGINE_PLUGINS_DIR) + rhs.m_library_path; + } - if(node["open_params"] && !node["open_params"].IsNull()) - { - std::string open_params = node["open_params"].as(); - rhs.m_open_params = trim(open_params); + if(node["init_config"] && !node["init_config"].IsNull()) { + // 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::decode(node["init_config"], json); + rhs.m_init_config = json.dump(); + } else { + rhs.m_init_config = node["init_config"].as(); } + } - return true; + if(node["open_params"] && !node["open_params"].IsNull()) { + std::string open_params = node["open_params"].as(); + rhs.m_open_params = trim(open_params); } - }; -} + + return true; + } +}; +} // namespace YAML diff --git a/userspace/falco/event_drops.cpp b/userspace/falco/event_drops.cpp index 22cd8440149..beee1dea800 100644 --- a/userspace/falco/event_drops.cpp +++ b/userspace/falco/event_drops.cpp @@ -19,28 +19,23 @@ limitations under the License. #include "falco_common.h" syscall_evt_drop_mgr::syscall_evt_drop_mgr(): - m_num_syscall_evt_drops(0), - m_num_actions(0), - m_inspector(NULL), - m_outputs(NULL), - m_next_check_ts(0), - m_simulate_drops(false), - m_threshold(0) -{ -} + m_num_syscall_evt_drops(0), + m_num_actions(0), + m_inspector(NULL), + m_outputs(NULL), + m_next_check_ts(0), + m_simulate_drops(false), + m_threshold(0) {} -syscall_evt_drop_mgr::~syscall_evt_drop_mgr() -{ -} +syscall_evt_drop_mgr::~syscall_evt_drop_mgr() {} void syscall_evt_drop_mgr::init(std::shared_ptr inspector, - std::shared_ptr outputs, - const syscall_evt_drop_actions &actions, - double threshold, - double rate, - double max_tokens, - bool simulate_drops) -{ + std::shared_ptr outputs, + const syscall_evt_drop_actions &actions, + double threshold, + double rate, + double max_tokens, + bool simulate_drops) { m_inspector = inspector; m_outputs = outputs; m_actions = actions; @@ -50,21 +45,17 @@ void syscall_evt_drop_mgr::init(std::shared_ptr inspector, m_inspector->get_capture_stats(&m_last_stats); m_simulate_drops = simulate_drops; - if(m_simulate_drops) - { + if(m_simulate_drops) { m_threshold = 0; } } -bool syscall_evt_drop_mgr::process_event(std::shared_ptr inspector, sinsp_evt *evt) -{ - if(m_next_check_ts == 0) - { +bool syscall_evt_drop_mgr::process_event(std::shared_ptr inspector, sinsp_evt *evt) { + if(m_next_check_ts == 0) { m_next_check_ts = evt->get_ts() + ONE_SECOND_IN_NS; } - if(m_next_check_ts < evt->get_ts()) - { + if(m_next_check_ts < evt->get_ts()) { scap_stats stats, delta; m_next_check_ts = evt->get_ts() + ONE_SECOND_IN_NS; @@ -74,20 +65,35 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr inspector, sinsp delta.n_evts = stats.n_evts - m_last_stats.n_evts; delta.n_drops = stats.n_drops - m_last_stats.n_drops; delta.n_drops_buffer = stats.n_drops_buffer - m_last_stats.n_drops_buffer; - delta.n_drops_buffer_clone_fork_enter = stats.n_drops_buffer_clone_fork_enter - m_last_stats.n_drops_buffer_clone_fork_enter; - delta.n_drops_buffer_clone_fork_exit = stats.n_drops_buffer_clone_fork_exit - m_last_stats.n_drops_buffer_clone_fork_exit; - delta.n_drops_buffer_execve_enter = stats.n_drops_buffer_execve_enter - m_last_stats.n_drops_buffer_execve_enter; - delta.n_drops_buffer_execve_exit = stats.n_drops_buffer_execve_exit - m_last_stats.n_drops_buffer_execve_exit; - delta.n_drops_buffer_connect_enter = stats.n_drops_buffer_connect_enter - m_last_stats.n_drops_buffer_connect_enter; - delta.n_drops_buffer_connect_exit = stats.n_drops_buffer_connect_exit - m_last_stats.n_drops_buffer_connect_exit; - delta.n_drops_buffer_open_enter = stats.n_drops_buffer_open_enter - m_last_stats.n_drops_buffer_open_enter; - delta.n_drops_buffer_open_exit = stats.n_drops_buffer_open_exit - m_last_stats.n_drops_buffer_open_exit; - delta.n_drops_buffer_dir_file_enter = stats.n_drops_buffer_dir_file_enter - m_last_stats.n_drops_buffer_dir_file_enter; - delta.n_drops_buffer_dir_file_exit = stats.n_drops_buffer_dir_file_exit - m_last_stats.n_drops_buffer_dir_file_exit; - delta.n_drops_buffer_other_interest_enter = stats.n_drops_buffer_other_interest_enter - m_last_stats.n_drops_buffer_other_interest_enter; - delta.n_drops_buffer_other_interest_exit = stats.n_drops_buffer_other_interest_exit - m_last_stats.n_drops_buffer_other_interest_exit; - delta.n_drops_buffer_close_exit = stats.n_drops_buffer_close_exit - m_last_stats.n_drops_buffer_close_exit; - delta.n_drops_buffer_proc_exit = stats.n_drops_buffer_proc_exit - m_last_stats.n_drops_buffer_proc_exit; + delta.n_drops_buffer_clone_fork_enter = stats.n_drops_buffer_clone_fork_enter - + m_last_stats.n_drops_buffer_clone_fork_enter; + delta.n_drops_buffer_clone_fork_exit = + stats.n_drops_buffer_clone_fork_exit - m_last_stats.n_drops_buffer_clone_fork_exit; + delta.n_drops_buffer_execve_enter = + stats.n_drops_buffer_execve_enter - m_last_stats.n_drops_buffer_execve_enter; + delta.n_drops_buffer_execve_exit = + stats.n_drops_buffer_execve_exit - m_last_stats.n_drops_buffer_execve_exit; + delta.n_drops_buffer_connect_enter = + stats.n_drops_buffer_connect_enter - m_last_stats.n_drops_buffer_connect_enter; + delta.n_drops_buffer_connect_exit = + stats.n_drops_buffer_connect_exit - m_last_stats.n_drops_buffer_connect_exit; + delta.n_drops_buffer_open_enter = + stats.n_drops_buffer_open_enter - m_last_stats.n_drops_buffer_open_enter; + delta.n_drops_buffer_open_exit = + stats.n_drops_buffer_open_exit - m_last_stats.n_drops_buffer_open_exit; + delta.n_drops_buffer_dir_file_enter = + stats.n_drops_buffer_dir_file_enter - m_last_stats.n_drops_buffer_dir_file_enter; + delta.n_drops_buffer_dir_file_exit = + stats.n_drops_buffer_dir_file_exit - m_last_stats.n_drops_buffer_dir_file_exit; + delta.n_drops_buffer_other_interest_enter = + stats.n_drops_buffer_other_interest_enter - + m_last_stats.n_drops_buffer_other_interest_enter; + delta.n_drops_buffer_other_interest_exit = stats.n_drops_buffer_other_interest_exit - + m_last_stats.n_drops_buffer_other_interest_exit; + delta.n_drops_buffer_close_exit = + stats.n_drops_buffer_close_exit - m_last_stats.n_drops_buffer_close_exit; + delta.n_drops_buffer_proc_exit = + stats.n_drops_buffer_proc_exit - m_last_stats.n_drops_buffer_proc_exit; delta.n_drops_scratch_map = stats.n_drops_scratch_map - m_last_stats.n_drops_scratch_map; delta.n_drops_pf = stats.n_drops_pf - m_last_stats.n_drops_pf; delta.n_drops_bug = stats.n_drops_bug - m_last_stats.n_drops_bug; @@ -97,34 +103,34 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr inspector, sinsp m_last_stats = stats; - if(m_simulate_drops) - { + if(m_simulate_drops) { falco_logger::log(falco_logger::level::INFO, "Simulating syscall event drop"); delta.n_drops++; } - if(delta.n_drops > 0) - { + if(delta.n_drops > 0) { double ratio = delta.n_drops; // The `n_evts` always contains the `n_drops`. ratio /= delta.n_evts; // When simulating drops the threshold is always zero - if(ratio > m_threshold) - { + if(ratio > m_threshold) { m_num_syscall_evt_drops++; // There were new drops in the last second. // If the token bucket allows, perform actions. - if(m_bucket.claim(1, evt->get_ts())) - { + if(m_bucket.claim(1, evt->get_ts())) { m_num_actions++; - return perform_actions(evt->get_ts(), delta, inspector->check_current_engine(BPF_ENGINE) || inspector->check_current_engine(MODERN_BPF_ENGINE)); - } - else - { - falco_logger::log(falco_logger::level::DEBUG, "Syscall event drop but token bucket depleted, skipping actions"); + return perform_actions( + evt->get_ts(), + delta, + inspector->check_current_engine(BPF_ENGINE) || + inspector->check_current_engine(MODERN_BPF_ENGINE)); + } else { + falco_logger::log( + falco_logger::level::DEBUG, + "Syscall event drop but token bucket depleted, skipping actions"); } } } @@ -133,22 +139,21 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr inspector, sinsp return true; } -void syscall_evt_drop_mgr::print_stats() -{ +void syscall_evt_drop_mgr::print_stats() { fprintf(stderr, "Syscall event drop monitoring:\n"); fprintf(stderr, " - event drop detected: %lu occurrences\n", m_num_syscall_evt_drops); fprintf(stderr, " - num times actions taken: %lu\n", m_num_actions); } -bool syscall_evt_drop_mgr::perform_actions(uint64_t now, const scap_stats &delta, bool bpf_enabled) -{ +bool syscall_evt_drop_mgr::perform_actions(uint64_t now, + const scap_stats &delta, + bool bpf_enabled) { std::string rule = "Falco internal: syscall event drop"; - std::string msg = rule + ". " + std::to_string(delta.n_drops) + " system calls dropped in last second."; + std::string msg = + rule + ". " + std::to_string(delta.n_drops) + " system calls dropped in last second."; - for(auto &act : m_actions) - { - switch(act) - { + for(auto &act : m_actions) { + switch(act) { case syscall_evt_drop_action::DISREGARD: return true; @@ -156,40 +161,67 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, const scap_stats &delta falco_logger::log(falco_logger::level::DEBUG, std::move(msg)); return true; - case syscall_evt_drop_action::ALERT: - { + case syscall_evt_drop_action::ALERT: { nlohmann::json output_fields; - output_fields["n_evts"] = std::to_string(delta.n_evts); /* Total number of kernel side events actively traced (not including events discarded due to simple consumer mode in eBPF case). */ - output_fields["n_drops"] = std::to_string(delta.n_drops); /* Number of all kernel side event drops out of n_evts. */ - output_fields["n_drops_buffer_total"] = std::to_string(delta.n_drops_buffer); /* Total number of kernel side drops due to full buffer, includes all categories below, likely higher than sum of syscall categories. */ - /* Kernel side drops due to full buffer for categories of system calls. Not all system calls of interest are mapped into one of the categories. - * Insights: - * (1) Identify statistical properties of workloads (e.g. ratios between categories). - * (2) Data-driven optimization opportunity for kernel side filtering and prioritization. - * (3) Response: Coarse grained insights into syscalls dropped. - * (4) Bonus: Cost associated with syscall category (typically `open` system call category is highest by orders of magnitude). + output_fields["n_evts"] = + std::to_string(delta.n_evts); /* Total number of kernel side events actively + traced (not including events discarded due to + simple consumer mode in eBPF case). */ + output_fields["n_drops"] = std::to_string( + delta.n_drops); /* Number of all kernel side event drops out of n_evts. */ + output_fields["n_drops_buffer_total"] = std::to_string( + delta.n_drops_buffer); /* Total number of kernel side drops due to full buffer, + includes all categories below, likely higher than sum + of syscall categories. */ + /* Kernel side drops due to full buffer for categories of system calls. Not all system + * calls of interest are mapped into one of the categories. Insights: (1) Identify + * statistical properties of workloads (e.g. ratios between categories). (2) Data-driven + * optimization opportunity for kernel side filtering and prioritization. (3) Response: + * Coarse grained insights into syscalls dropped. (4) Bonus: Cost associated with + * syscall category (typically `open` system call category is highest by orders of + * magnitude). */ - output_fields["n_drops_buffer_clone_fork_enter"] = std::to_string(delta.n_drops_buffer_clone_fork_enter); - output_fields["n_drops_buffer_clone_fork_exit"] = std::to_string(delta.n_drops_buffer_clone_fork_exit); - output_fields["n_drops_buffer_execve_enter"] = std::to_string(delta.n_drops_buffer_execve_enter); - output_fields["n_drops_buffer_execve_exit"] = std::to_string(delta.n_drops_buffer_execve_exit); - output_fields["n_drops_buffer_connect_enter"] = std::to_string(delta.n_drops_buffer_connect_enter); - output_fields["n_drops_buffer_connect_exit"] = std::to_string(delta.n_drops_buffer_connect_exit); - output_fields["n_drops_buffer_open_enter"] = std::to_string(delta.n_drops_buffer_open_enter); - output_fields["n_drops_buffer_open_exit"] = std::to_string(delta.n_drops_buffer_open_exit); - output_fields["n_drops_buffer_dir_file_enter"] = std::to_string(delta.n_drops_buffer_dir_file_enter); - output_fields["n_drops_buffer_dir_file_exit"] = std::to_string(delta.n_drops_buffer_dir_file_exit); - /* `n_drops_buffer_other_interest_*` Category consisting of other system calls of interest, - * not all other system calls that did not match a category from above. - * Ideal for a custom category if needed - simply patch switch statement in kernel driver code (`falcosecurity/libs` repo). + output_fields["n_drops_buffer_clone_fork_enter"] = + std::to_string(delta.n_drops_buffer_clone_fork_enter); + output_fields["n_drops_buffer_clone_fork_exit"] = + std::to_string(delta.n_drops_buffer_clone_fork_exit); + output_fields["n_drops_buffer_execve_enter"] = + std::to_string(delta.n_drops_buffer_execve_enter); + output_fields["n_drops_buffer_execve_exit"] = + std::to_string(delta.n_drops_buffer_execve_exit); + output_fields["n_drops_buffer_connect_enter"] = + std::to_string(delta.n_drops_buffer_connect_enter); + output_fields["n_drops_buffer_connect_exit"] = + std::to_string(delta.n_drops_buffer_connect_exit); + output_fields["n_drops_buffer_open_enter"] = + std::to_string(delta.n_drops_buffer_open_enter); + output_fields["n_drops_buffer_open_exit"] = + std::to_string(delta.n_drops_buffer_open_exit); + output_fields["n_drops_buffer_dir_file_enter"] = + std::to_string(delta.n_drops_buffer_dir_file_enter); + output_fields["n_drops_buffer_dir_file_exit"] = + std::to_string(delta.n_drops_buffer_dir_file_exit); + /* `n_drops_buffer_other_interest_*` Category consisting of other system calls of + * interest, not all other system calls that did not match a category from above. Ideal + * for a custom category if needed - simply patch switch statement in kernel driver code + * (`falcosecurity/libs` repo). */ - output_fields["n_drops_buffer_other_interest_enter"] = std::to_string(delta.n_drops_buffer_other_interest_enter); - output_fields["n_drops_buffer_other_interest_exit"] = std::to_string(delta.n_drops_buffer_other_interest_exit); - output_fields["n_drops_buffer_close_exit"] = std::to_string(delta.n_drops_buffer_close_exit); - output_fields["n_drops_buffer_proc_exit"] = std::to_string(delta.n_drops_buffer_proc_exit); - output_fields["n_drops_scratch_map"] = std::to_string(delta.n_drops_scratch_map); /* Number of kernel side scratch map drops. */ - output_fields["n_drops_page_faults"] = std::to_string(delta.n_drops_pf); /* Number of kernel side page faults drops (invalid memory access). */ - output_fields["n_drops_bug"] = std::to_string(delta.n_drops_bug); /* Number of kernel side bug drops (invalid condition in the kernel instrumentation). */ + output_fields["n_drops_buffer_other_interest_enter"] = + std::to_string(delta.n_drops_buffer_other_interest_enter); + output_fields["n_drops_buffer_other_interest_exit"] = + std::to_string(delta.n_drops_buffer_other_interest_exit); + output_fields["n_drops_buffer_close_exit"] = + std::to_string(delta.n_drops_buffer_close_exit); + output_fields["n_drops_buffer_proc_exit"] = + std::to_string(delta.n_drops_buffer_proc_exit); + output_fields["n_drops_scratch_map"] = std::to_string( + delta.n_drops_scratch_map); /* Number of kernel side scratch map drops. */ + output_fields["n_drops_page_faults"] = + std::to_string(delta.n_drops_pf); /* Number of kernel side page faults drops + (invalid memory access). */ + output_fields["n_drops_bug"] = std::to_string( + delta.n_drops_bug); /* Number of kernel side bug drops (invalid condition in the + kernel instrumentation). */ output_fields["ebpf_enabled"] = std::to_string(bpf_enabled); m_outputs->handle_msg(now, falco_common::PRIORITY_DEBUG, msg, rule, output_fields); return true; @@ -200,7 +232,8 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, const scap_stats &delta return false; default: - falco_logger::log(falco_logger::level::ERR, "Ignoring unknown action " + std::to_string(int(act))); + falco_logger::log(falco_logger::level::ERR, + "Ignoring unknown action " + std::to_string(int(act))); return true; } } diff --git a/userspace/falco/event_drops.h b/userspace/falco/event_drops.h index f820703ca00..2efb4bba275 100644 --- a/userspace/falco/event_drops.h +++ b/userspace/falco/event_drops.h @@ -27,29 +27,22 @@ limitations under the License. // The possible actions that this class can take upon // detecting a syscall event drop. -enum class syscall_evt_drop_action : uint8_t -{ - DISREGARD = 0, - LOG, - ALERT, - EXIT -}; +enum class syscall_evt_drop_action : uint8_t { DISREGARD = 0, LOG, ALERT, EXIT }; using syscall_evt_drop_actions = std::unordered_set; -class syscall_evt_drop_mgr -{ +class syscall_evt_drop_mgr { public: syscall_evt_drop_mgr(); virtual ~syscall_evt_drop_mgr(); void init(std::shared_ptr inspector, - std::shared_ptr outputs, - const syscall_evt_drop_actions &actions, - double threshold, - double rate, - double max_tokens, - bool simulate_drops); + std::shared_ptr outputs, + const syscall_evt_drop_actions &actions, + double threshold, + double rate, + double max_tokens, + bool simulate_drops); // Call this for every event. The class will take care of // periodically measuring the scap stats, looking for syscall diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index 60943e6a876..3be8a6afb51 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -23,13 +23,11 @@ limitations under the License. #include "app/app.h" #include "logger.h" -static void display_fatal_err(const std::string &&msg) -{ +static void display_fatal_err(const std::string &&msg) { /** * If stderr logging is not enabled, also log to stderr. */ - if (! falco_logger::log_stderr) - { + if(!falco_logger::log_stderr) { std::cerr << msg; } @@ -39,20 +37,15 @@ static void display_fatal_err(const std::string &&msg) // // ARGUMENT PARSING AND PROGRAM SETUP // -int falco_run(int argc, char **argv, bool &restart) -{ +int falco_run(int argc, char **argv, bool &restart) { restart = false; std::string errstr; - try - { - if (!falco::app::run(argc, argv, restart, errstr)) - { + try { + if(!falco::app::run(argc, argv, restart, errstr)) { fprintf(stderr, "Error: %s\n", errstr.c_str()); return EXIT_FAILURE; } - } - catch(std::exception &e) - { + } catch(std::exception &e) { display_fatal_err("Runtime error: " + std::string(e.what()) + ". Exiting.\n"); return EXIT_FAILURE; } @@ -63,8 +56,7 @@ int falco_run(int argc, char **argv, bool &restart) // // MAIN // -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { int rc; bool restart; @@ -72,8 +64,7 @@ int main(int argc, char **argv) // returned by falco_run. However, when restart (set by // signal handlers, returned in application::run()) is true, // falco_run() is called again. - while((rc = falco_run(argc, argv, restart)) == EXIT_SUCCESS && restart) - { + while((rc = falco_run(argc, argv, restart)) == EXIT_SUCCESS && restart) { } return rc; diff --git a/userspace/falco/falco_metrics.cpp b/userspace/falco/falco_metrics.cpp index f9362bc242c..8d58338de44 100644 --- a/userspace/falco/falco_metrics.cpp +++ b/userspace/falco/falco_metrics.cpp @@ -6,7 +6,7 @@ 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 + 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, @@ -26,184 +26,226 @@ limitations under the License. namespace fs = std::filesystem; /*! - \class falco_metrics - \brief This class is used to convert the metrics provided by the application - and falco libs into a string to be return by the metrics endpoint. + \class falco_metrics + \brief This class is used to convert the metrics provided by the application + and falco libs into a string to be return by the metrics endpoint. */ /*! - \brief content_type to be returned by the webserver's metrics endpoint. + \brief content_type to be returned by the webserver's metrics endpoint. - Currently it is the default Prometheus exposition format + Currently it is the default Prometheus exposition format - https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format + https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format */ const std::string falco_metrics::content_type = "text/plain; version=0.0.4"; - /*! - \brief this method takes an application \c state and returns a textual representation of - its configured metrics. + \brief this method takes an application \c state and returns a textual representation of + its configured metrics. - The current implementation returns a Prometheus exposition formatted string. + The current implementation returns a Prometheus exposition formatted string. */ -std::string falco_metrics::to_text(const falco::app::state& state) -{ - static const char* all_driver_engines[] = { - BPF_ENGINE, KMOD_ENGINE, MODERN_BPF_ENGINE, - SOURCE_PLUGIN_ENGINE, NODRIVER_ENGINE, GVISOR_ENGINE }; +std::string falco_metrics::to_text(const falco::app::state& state) { + static const char* all_driver_engines[] = {BPF_ENGINE, + KMOD_ENGINE, + MODERN_BPF_ENGINE, + SOURCE_PLUGIN_ENGINE, + NODRIVER_ENGINE, + GVISOR_ENGINE}; std::vector> inspectors; std::vector metrics_collectors; - for (const auto& source: state.enabled_sources) - { + for(const auto& source : state.enabled_sources) { auto source_info = state.source_infos.at(source); auto source_inspector = source_info->inspector; inspectors.emplace_back(source_inspector); - metrics_collectors.emplace_back(libs::metrics::libs_metrics_collector(source_inspector.get(), state.config->m_metrics_flags)); + metrics_collectors.emplace_back( + libs::metrics::libs_metrics_collector(source_inspector.get(), + state.config->m_metrics_flags)); } libs::metrics::prometheus_metrics_converter prometheus_metrics_converter; std::string prometheus_text; - for (auto inspector: inspectors) - { + for(auto inspector : inspectors) { // Falco wrapper metrics // - for (size_t i = 0; i < sizeof(all_driver_engines) / sizeof(const char*); i++) - { - if (inspector->check_current_engine(all_driver_engines[i])) - { - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("engine_name", "falcosecurity", "scap", {{"engine_name", all_driver_engines[i]}}); + for(size_t i = 0; i < sizeof(all_driver_engines) / sizeof(const char*); i++) { + if(inspector->check_current_engine(all_driver_engines[i])) { + prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus( + "engine_name", + "falcosecurity", + "scap", + {{"engine_name", all_driver_engines[i]}}); break; } } - const scap_agent_info* agent_info = inspector->get_agent_info(); const scap_machine_info* machine_info = inspector->get_machine_info(); libs::metrics::libs_metrics_collector libs_metrics_collector(inspector.get(), 0); - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("version", "falcosecurity", "falco", {{"version", FALCO_VERSION}}); + prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus( + "version", + "falcosecurity", + "falco", + {{"version", FALCO_VERSION}}); // Not all scap engines report agent and machine infos. - if (agent_info) - { - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("kernel_release", "falcosecurity", "falco", {{"kernel_release", agent_info->uname_r}}); + if(agent_info) { + prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus( + "kernel_release", + "falcosecurity", + "falco", + {{"kernel_release", agent_info->uname_r}}); } - if (machine_info) - { - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("hostname", "falcosecurity", "evt", {{"hostname", machine_info->hostname}}); + if(machine_info) { + prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus( + "hostname", + "falcosecurity", + "evt", + {{"hostname", machine_info->hostname}}); } #if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) - // Distinguish between config and rules files using labels, following Prometheus best practices: https://prometheus.io/docs/practices/naming/#labels - for (const auto& item : state.config.get()->m_loaded_rules_filenames_sha256sum) - { + // Distinguish between config and rules files using labels, following Prometheus best + // practices: https://prometheus.io/docs/practices/naming/#labels + for(const auto& item : state.config.get()->m_loaded_rules_filenames_sha256sum) { fs::path fs_path = item.first; - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("sha256_rules_files", "falcosecurity", "falco", {{"file_name", fs_path.filename()}, {"sha256", item.second}}); + prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus( + "sha256_rules_files", + "falcosecurity", + "falco", + {{"file_name", fs_path.filename()}, {"sha256", item.second}}); } - for (const auto& item : state.config.get()->m_loaded_configs_filenames_sha256sum) - { + for(const auto& item : state.config.get()->m_loaded_configs_filenames_sha256sum) { fs::path fs_path = item.first; - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("sha256_config_files", "falcosecurity", "falco", {{"file_name", fs_path.filename()}, {"sha256", item.second}}); + prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus( + "sha256_config_files", + "falcosecurity", + "falco", + {{"file_name", fs_path.filename()}, {"sha256", item.second}}); } #endif - for (const std::string& source: inspector->event_sources()) - { - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("evt_source", "falcosecurity", "falco", {{"evt_source", source}}); + for(const std::string& source : inspector->event_sources()) { + prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus( + "evt_source", + "falcosecurity", + "falco", + {{"evt_source", source}}); } std::vector additional_wrapper_metrics; - if (agent_info) - { - additional_wrapper_metrics.emplace_back(libs::metrics::libsinsp_metrics::new_metric("start_ts", - METRICS_V2_MISC, - METRIC_VALUE_TYPE_U64, - METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - agent_info->start_ts_epoch)); + if(agent_info) { + additional_wrapper_metrics.emplace_back(libs::metrics::libsinsp_metrics::new_metric( + "start_ts", + METRICS_V2_MISC, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + agent_info->start_ts_epoch)); } - if (machine_info) - { - additional_wrapper_metrics.emplace_back(libs::metrics::libsinsp_metrics::new_metric("host_boot_ts", - METRICS_V2_MISC, - METRIC_VALUE_TYPE_U64, - METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - machine_info->boot_ts_epoch)); - additional_wrapper_metrics.emplace_back(libs::metrics::libsinsp_metrics::new_metric("host_num_cpus", - METRICS_V2_MISC, - METRIC_VALUE_TYPE_U32, - METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - machine_info->num_cpus)); + if(machine_info) { + additional_wrapper_metrics.emplace_back(libs::metrics::libsinsp_metrics::new_metric( + "host_boot_ts", + METRICS_V2_MISC, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + machine_info->boot_ts_epoch)); + additional_wrapper_metrics.emplace_back(libs::metrics::libsinsp_metrics::new_metric( + "host_num_cpus", + METRICS_V2_MISC, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + machine_info->num_cpus)); } - additional_wrapper_metrics.emplace_back(libs::metrics::libsinsp_metrics::new_metric("outputs_queue_num_drops", - METRICS_V2_MISC, - METRIC_VALUE_TYPE_U64, - METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_METRIC_TYPE_MONOTONIC, - state.outputs->get_outputs_queue_num_drops())); - - if (agent_info) - { - auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - additional_wrapper_metrics.emplace_back(libs::metrics::libsinsp_metrics::new_metric("duration_sec", - METRICS_V2_MISC, - METRIC_VALUE_TYPE_U64, - METRIC_VALUE_UNIT_TIME_S_COUNT, - METRIC_VALUE_METRIC_TYPE_MONOTONIC, - (uint64_t)((now - agent_info->start_ts_epoch) / ONE_SECOND_IN_NS))); + additional_wrapper_metrics.emplace_back(libs::metrics::libsinsp_metrics::new_metric( + "outputs_queue_num_drops", + METRICS_V2_MISC, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, + state.outputs->get_outputs_queue_num_drops())); + + if(agent_info) { + auto now = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + additional_wrapper_metrics.emplace_back(libs::metrics::libsinsp_metrics::new_metric( + "duration_sec", + METRICS_V2_MISC, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_TIME_S_COUNT, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, + (uint64_t)((now - agent_info->start_ts_epoch) / ONE_SECOND_IN_NS))); } - for (auto metric: additional_wrapper_metrics) - { + for(auto metric : additional_wrapper_metrics) { prometheus_metrics_converter.convert_metric_to_unit_convention(metric); - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "falcosecurity", "falco"); + prometheus_text += + prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, + "falcosecurity", + "falco"); } // Falco metrics categories // // rules_counters_enabled - if(state.config->m_metrics_flags & METRICS_V2_RULE_COUNTERS) - { + if(state.config->m_metrics_flags & METRICS_V2_RULE_COUNTERS) { const stats_manager& rule_stats_manager = state.engine->get_rule_stats_manager(); const indexed_vector& rules = state.engine->get_rules(); - const std::vector>>& rules_by_id = rule_stats_manager.get_by_rule_id(); - // Distinguish between rules counters using labels, following Prometheus best practices: https://prometheus.io/docs/practices/naming/#labels - for (size_t i = 0; i < rules_by_id.size(); i++) - { + const std::vector>>& rules_by_id = + rule_stats_manager.get_by_rule_id(); + // Distinguish between rules counters using labels, following Prometheus best practices: + // https://prometheus.io/docs/practices/naming/#labels + for(size_t i = 0; i < rules_by_id.size(); i++) { auto rule = rules.at(i); auto count = rules_by_id[i]->load(); - if (count > 0) - { + if(count > 0) { /* Examples ... - # HELP falcosecurity_falco_rules_matches_total https://falco.org/docs/metrics/ - # TYPE falcosecurity_falco_rules_matches_total counter - falcosecurity_falco_rules_matches_total{priority="4",rule_name="Read sensitive file untrusted",source="syscall",tag_T1555="true",tag_container="true",tag_filesystem="true",tag_host="true",tag_maturity_stable="true",tag_mitre_credential_access="true"} 10 - # HELP falcosecurity_falco_rules_matches_total https://falco.org/docs/metrics/ - # TYPE falcosecurity_falco_rules_matches_total counter - falcosecurity_falco_rules_matches_total{priority="5",rule_name="Unexpected UDP Traffic",source="syscall",tag_TA0011="true",tag_container="true",tag_host="true",tag_maturity_incubating="true",tag_mitre_exfiltration="true",tag_network="true"} 1 + # HELP falcosecurity_falco_rules_matches_total + https://falco.org/docs/metrics/ # TYPE + falcosecurity_falco_rules_matches_total counter + falcosecurity_falco_rules_matches_total{priority="4",rule_name="Read + sensitive file + untrusted",source="syscall",tag_T1555="true",tag_container="true",tag_filesystem="true",tag_host="true",tag_maturity_stable="true",tag_mitre_credential_access="true"} + 10 # HELP falcosecurity_falco_rules_matches_total + https://falco.org/docs/metrics/ # TYPE + falcosecurity_falco_rules_matches_total counter + falcosecurity_falco_rules_matches_total{priority="5",rule_name="Unexpected + UDP + Traffic",source="syscall",tag_TA0011="true",tag_container="true",tag_host="true",tag_maturity_incubating="true",tag_mitre_exfiltration="true",tag_network="true"} + 1 */ - auto metric = libs::metrics::libsinsp_metrics::new_metric("rules_matches", - METRICS_V2_RULE_COUNTERS, - METRIC_VALUE_TYPE_U64, - METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_METRIC_TYPE_MONOTONIC, - rules_by_id[i]->load()); + auto metric = libs::metrics::libsinsp_metrics::new_metric( + "rules_matches", + METRICS_V2_RULE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, + rules_by_id[i]->load()); prometheus_metrics_converter.convert_metric_to_unit_convention(metric); std::map const_labels = { - {"rule_name", rule->name}, - {"priority", std::to_string(rule->priority)}, - {"source", rule->source}, + {"rule_name", rule->name}, + {"priority", std::to_string(rule->priority)}, + {"source", rule->source}, }; - std::for_each(rule->tags.cbegin(), rule->tags.cend(), [&const_labels](std::string const& tag) { - const_labels.emplace(std::string{"tag_"} + tag, "true"); - }); - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "falcosecurity", "falco", const_labels); + std::for_each(rule->tags.cbegin(), + rule->tags.cend(), + [&const_labels](std::string const& tag) { + const_labels.emplace(std::string{"tag_"} + tag, "true"); + }); + prometheus_text += + prometheus_metrics_converter.convert_metric_to_text_prometheus( + metric, + "falcosecurity", + "falco", + const_labels); } } } @@ -215,93 +257,97 @@ std::string falco_metrics::to_text(const falco::app::state& state) // state_counters_enabled // kernel_event_counters_enabled // libbpf_stats_enabled - for (auto metrics_collector: metrics_collectors) - { + for(auto metrics_collector : metrics_collectors) { metrics_collector.snapshot(); auto metrics_snapshot = metrics_collector.get_metrics(); - for (auto& metric: metrics_snapshot) - { + for(auto& metric : metrics_snapshot) { prometheus_metrics_converter.convert_metric_to_unit_convention(metric); std::string prometheus_subsystem = "scap"; - - if (metric.flags & METRICS_V2_RESOURCE_UTILIZATION) - { + + if(metric.flags & METRICS_V2_RESOURCE_UTILIZATION) { prometheus_subsystem = "falco"; } - if (metric.flags & METRICS_V2_PLUGINS) - { + if(metric.flags & METRICS_V2_PLUGINS) { prometheus_subsystem = "plugins"; } // raw incoming in form of for example n_evts_cpu_15 or n_drops_cpu_15 - if (strncmp(metric.name, "n_evts_cpu", 10) == 0 || strncmp(metric.name, "n_drops_cpu", 11) == 0) // prefix match + if(strncmp(metric.name, "n_evts_cpu", 10) == 0 || + strncmp(metric.name, "n_drops_cpu", 11) == 0) // prefix match { std::string name_str(metric.name); re2::RE2 pattern("(\\d+)"); std::string cpu_number; - if (re2::RE2::PartialMatch(name_str, pattern, &cpu_number)) - { + if(re2::RE2::PartialMatch(name_str, pattern, &cpu_number)) { re2::RE2::GlobalReplace(&name_str, pattern, ""); // possible double __ will be sanitized within libs - auto metric_new = libs::metrics::libsinsp_metrics::new_metric(name_str.c_str(), - METRICS_V2_KERNEL_COUNTERS_PER_CPU, - METRIC_VALUE_TYPE_U64, - METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_METRIC_TYPE_MONOTONIC, - metric.value.u64); - const std::map& const_labels = { - {"cpu", cpu_number} - }; + auto metric_new = libs::metrics::libsinsp_metrics::new_metric( + name_str.c_str(), + METRICS_V2_KERNEL_COUNTERS_PER_CPU, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, + metric.value.u64); + const std::map& const_labels = {{"cpu", cpu_number}}; /* Examples ... - # HELP falcosecurity_scap_n_evts_cpu_total https://falco.org/docs/metrics/ - # TYPE falcosecurity_scap_n_evts_cpu_total counter - falcosecurity_scap_n_evts_cpu_total{cpu="7"} 237 - # HELP falcosecurity_scap_n_drops_cpu_total https://falco.org/docs/metrics/ - # TYPE falcosecurity_scap_n_drops_cpu_total counter - falcosecurity_scap_n_drops_cpu_total{cpu="7"} 0 + # HELP falcosecurity_scap_n_evts_cpu_total https://falco.org/docs/metrics/ + # TYPE falcosecurity_scap_n_evts_cpu_total counter + falcosecurity_scap_n_evts_cpu_total{cpu="7"} 237 + # HELP falcosecurity_scap_n_drops_cpu_total https://falco.org/docs/metrics/ + # TYPE falcosecurity_scap_n_drops_cpu_total counter + falcosecurity_scap_n_drops_cpu_total{cpu="7"} 0 */ - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus(metric_new, "falcosecurity", prometheus_subsystem, const_labels); + prometheus_text += + prometheus_metrics_converter.convert_metric_to_text_prometheus( + metric_new, + "falcosecurity", + prometheus_subsystem, + const_labels); } - } - else if (strcmp(metric.name, "n_drops_buffer_total") == 0) - { - // Skip the libs aggregate metric since we distinguish between buffer drops using labels similar to the rules_matches + } else if(strcmp(metric.name, "n_drops_buffer_total") == 0) { + // Skip the libs aggregate metric since we distinguish between buffer drops using + // labels similar to the rules_matches continue; - } - else if (strncmp(metric.name, "n_drops_buffer", 14) == 0) // prefix match + } else if(strncmp(metric.name, "n_drops_buffer", 14) == 0) // prefix match { re2::RE2 pattern("n_drops_buffer_([^_]+(?:_[^_]+)*)_(enter|exit)$"); std::string drop; std::string dir; std::string name_str(metric.name); - if (re2::RE2::FullMatch(name_str, pattern, &drop, &dir)) - { - auto metric_new = libs::metrics::libsinsp_metrics::new_metric("n_drops_buffer", - METRICS_V2_KERNEL_COUNTERS, - METRIC_VALUE_TYPE_U64, - METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_METRIC_TYPE_MONOTONIC, - metric.value.u64); - const std::map& const_labels = { - {"drop", drop}, - {"dir", dir} - }; + if(re2::RE2::FullMatch(name_str, pattern, &drop, &dir)) { + auto metric_new = libs::metrics::libsinsp_metrics::new_metric( + "n_drops_buffer", + METRICS_V2_KERNEL_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, + metric.value.u64); + const std::map& const_labels = {{"drop", drop}, + {"dir", dir}}; /* Examples ... - # HELP falcosecurity_scap_n_drops_buffer_total https://falco.org/docs/metrics/ - # TYPE falcosecurity_scap_n_drops_buffer_total counter - falcosecurity_scap_n_drops_buffer_total{dir="enter",drop="clone_fork"} 0 - # HELP falcosecurity_scap_n_drops_buffer_total https://falco.org/docs/metrics/ - # TYPE falcosecurity_scap_n_drops_buffer_total counter - falcosecurity_scap_n_drops_buffer_total{dir="exit",drop="clone_fork"} 0 + # HELP falcosecurity_scap_n_drops_buffer_total + https://falco.org/docs/metrics/ # TYPE + falcosecurity_scap_n_drops_buffer_total counter + falcosecurity_scap_n_drops_buffer_total{dir="enter",drop="clone_fork"} 0 + # HELP falcosecurity_scap_n_drops_buffer_total + https://falco.org/docs/metrics/ # TYPE + falcosecurity_scap_n_drops_buffer_total counter + falcosecurity_scap_n_drops_buffer_total{dir="exit",drop="clone_fork"} 0 */ - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus(metric_new, "falcosecurity", prometheus_subsystem, const_labels); + prometheus_text += + prometheus_metrics_converter.convert_metric_to_text_prometheus( + metric_new, + "falcosecurity", + prometheus_subsystem, + const_labels); } - } - else - { - prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "falcosecurity", prometheus_subsystem); + } else { + prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus( + metric, + "falcosecurity", + prometheus_subsystem); } } } diff --git a/userspace/falco/falco_metrics.h b/userspace/falco/falco_metrics.h index af4146d8030..3c82d63f4c3 100644 --- a/userspace/falco/falco_metrics.h +++ b/userspace/falco/falco_metrics.h @@ -6,7 +6,7 @@ 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 + 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, @@ -21,11 +21,10 @@ limitations under the License. #include namespace falco::app { - struct state; +struct state; } -class falco_metrics -{ +class falco_metrics { public: static const std::string content_type; static std::string to_text(const falco::app::state& state); diff --git a/userspace/falco/falco_outputs.cpp b/userspace/falco/falco_outputs.cpp index 2ccddf00874..7808ca8ae63 100644 --- a/userspace/falco/falco_outputs.cpp +++ b/userspace/falco/falco_outputs.cpp @@ -37,32 +37,30 @@ limitations under the License. #include "outputs_grpc.h" #endif -static const char* s_internal_source = "internal"; - -falco_outputs::falco_outputs( - std::shared_ptr engine, - const std::vector& outputs, - bool json_output, - bool json_include_output_property, - bool json_include_tags_property, - bool json_include_message_property, - uint32_t timeout, - bool buffered, - size_t outputs_queue_capacity, - bool time_format_iso_8601, - const std::string& hostname) - : m_formats(std::make_unique( - engine, - json_include_output_property, json_include_tags_property, json_include_message_property, - time_format_iso_8601)), - m_buffered(buffered), - m_json_output(json_output), - m_time_format_iso_8601(time_format_iso_8601), - m_timeout(std::chrono::milliseconds(timeout)), - m_hostname(hostname) -{ - for(const auto& output : outputs) - { +static const char *s_internal_source = "internal"; + +falco_outputs::falco_outputs(std::shared_ptr engine, + const std::vector &outputs, + bool json_output, + bool json_include_output_property, + bool json_include_tags_property, + bool json_include_message_property, + uint32_t timeout, + bool buffered, + size_t outputs_queue_capacity, + bool time_format_iso_8601, + const std::string &hostname): + m_formats(std::make_unique(engine, + json_include_output_property, + json_include_tags_property, + json_include_message_property, + time_format_iso_8601)), + m_buffered(buffered), + m_json_output(json_output), + m_time_format_iso_8601(time_format_iso_8601), + m_timeout(std::chrono::milliseconds(timeout)), + m_hostname(hostname) { + for(const auto &output : outputs) { add_output(output); } @@ -72,91 +70,83 @@ falco_outputs::falco_outputs( #endif } -falco_outputs::~falco_outputs() -{ +falco_outputs::~falco_outputs() { #ifndef __EMSCRIPTEN__ this->stop_worker(); #endif } // This function is called only at initialization-time by the constructor -void falco_outputs::add_output(const falco::outputs::config &oc) -{ +void falco_outputs::add_output(const falco::outputs::config &oc) { std::unique_ptr oo; - if(oc.name == "file") - { + if(oc.name == "file") { oo = std::make_unique(); } #ifndef _WIN32 - else if(oc.name == "program") - { + else if(oc.name == "program") { oo = std::make_unique(); } #endif - else if(oc.name == "stdout") - { + else if(oc.name == "stdout") { oo = std::make_unique(); } #ifndef _WIN32 - else if(oc.name == "syslog") - { + else if(oc.name == "syslog") { oo = std::make_unique(); } #endif #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD) - else if(oc.name == "http") - { + else if(oc.name == "http") { oo = std::make_unique(); - } - else if(oc.name == "grpc") - { + } else if(oc.name == "grpc") { oo = std::make_unique(); } #endif - else - { + else { throw falco_exception("Output not supported: " + oc.name); } std::string init_err; - if (oo->init(oc, m_buffered, m_hostname, m_json_output, init_err)) - { + if(oo->init(oc, m_buffered, m_hostname, m_json_output, init_err)) { m_outputs.push_back(std::move(oo)); - } - else - { + } else { falco_logger::log(falco_logger::level::ERR, "Failed to init output: " + init_err); } } -void falco_outputs::handle_event(sinsp_evt *evt, const std::string &rule, const std::string &source, - falco_common::priority_type priority, const std::string &format, std::set &tags, - extra_output_field_t &extra_fields) -{ +void falco_outputs::handle_event(sinsp_evt *evt, + const std::string &rule, + const std::string &source, + falco_common::priority_type priority, + const std::string &format, + std::set &tags, + extra_output_field_t &extra_fields) { falco_outputs::ctrl_msg cmsg = {}; cmsg.ts = evt->get_ts(); cmsg.priority = priority; cmsg.source = source; cmsg.rule = rule; - cmsg.msg = m_formats->format_event( - evt, rule, source, falco_common::format_priority(priority), format, tags, m_hostname, extra_fields - ); + cmsg.msg = m_formats->format_event(evt, + rule, + source, + falco_common::format_priority(priority), + format, + tags, + m_hostname, + extra_fields); auto fields = m_formats->get_field_values(evt, source, format); - for (auto const& ef : extra_fields) - { + for(auto const &ef : extra_fields) { // when formatting for the control message we always want strings, // so we can simply format raw fields as string std::string fformat = ef.second.first; - if (fformat.size() == 0) - { + if(fformat.size() == 0) { continue; } - if (!(fformat[0] == '*')) - { + if(!(fformat[0] == '*')) { fformat = "*" + fformat; } @@ -172,13 +162,11 @@ void falco_outputs::handle_event(sinsp_evt *evt, const std::string &rule, const } void falco_outputs::handle_msg(uint64_t ts, - falco_common::priority_type priority, - const std::string &msg, - const std::string &rule, - nlohmann::json &output_fields) -{ - if (!output_fields.is_object()) - { + falco_common::priority_type priority, + const std::string &msg, + const std::string &rule, + nlohmann::json &output_fields) { + if(!output_fields.is_object()) { throw falco_exception("falco_outputs: output fields must be key-value maps"); } @@ -189,14 +177,13 @@ void falco_outputs::handle_msg(uint64_t ts, cmsg.rule = rule; cmsg.fields = output_fields; - if(m_json_output) - { + if(m_json_output) { nlohmann::json jmsg; // Convert the time-as-nanoseconds to a more json-friendly ISO8601. time_t evttime = ts / 1000000000; - char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS" - char time_ns[12]; // sizeof ".sssssssssZ" + char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS" + char time_ns[12]; // sizeof ".sssssssssZ" std::string iso8601evttime; strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime)); @@ -213,26 +200,19 @@ void falco_outputs::handle_msg(uint64_t ts, jmsg["source"] = s_internal_source; cmsg.msg = jmsg.dump(); - } - else - { + } else { std::string timestr; bool first = true; sinsp_utils::ts_to_string(ts, ×tr, false, true); cmsg.msg = timestr + ": " + falco_common::format_priority(priority) + " " + msg + " ("; - for(auto &pair : output_fields.items()) - { - if(first) - { + for(auto &pair : output_fields.items()) { + if(first) { first = false; - } - else - { + } else { cmsg.msg += " "; } - if (!pair.value().is_primitive()) - { + if(!pair.value().is_primitive()) { throw falco_exception("falco_outputs: output fields must be key-value maps"); } cmsg.msg += pair.key() + "=" + pair.value().dump(); @@ -244,21 +224,20 @@ void falco_outputs::handle_msg(uint64_t ts, this->push(cmsg); } -void falco_outputs::cleanup_outputs() -{ +void falco_outputs::cleanup_outputs() { this->push_ctrl(falco_outputs::ctrl_msg_type::CTRL_MSG_CLEANUP); } -void falco_outputs::reopen_outputs() -{ +void falco_outputs::reopen_outputs() { this->push_ctrl(falco_outputs::ctrl_msg_type::CTRL_MSG_REOPEN); } -void falco_outputs::stop_worker() -{ +void falco_outputs::stop_worker() { watchdog wd; wd.start([&](void *) -> void { - falco_logger::log(falco_logger::level::NOTICE, "output channels still blocked, discarding all remaining notifications\n"); + falco_logger::log( + falco_logger::level::NOTICE, + "output channels still blocked, discarding all remaining notifications\n"); #ifndef __EMSCRIPTEN__ m_queue.clear(); #endif @@ -267,33 +246,28 @@ void falco_outputs::stop_worker() wd.set_timeout(m_timeout, nullptr); this->push_ctrl(falco_outputs::ctrl_msg_type::CTRL_MSG_STOP); - if(m_worker_thread.joinable()) - { + if(m_worker_thread.joinable()) { m_worker_thread.join(); } } -inline void falco_outputs::push_ctrl(ctrl_msg_type cmt) -{ +inline void falco_outputs::push_ctrl(ctrl_msg_type cmt) { falco_outputs::ctrl_msg cmsg = {}; cmsg.type = cmt; this->push(cmsg); } -inline void falco_outputs::push(const ctrl_msg& cmsg) -{ +inline void falco_outputs::push(const ctrl_msg &cmsg) { #ifndef __EMSCRIPTEN__ - if (!m_queue.try_push(cmsg)) - { - if(m_outputs_queue_num_drops.load() == 0) - { - falco_logger::log(falco_logger::level::ERR, "Outputs queue out of memory. Drop event and continue on ..."); + if(!m_queue.try_push(cmsg)) { + if(m_outputs_queue_num_drops.load() == 0) { + falco_logger::log(falco_logger::level::ERR, + "Outputs queue out of memory. Drop event and continue on ..."); } m_outputs_queue_num_drops++; } #else - for (const auto& o : m_outputs) - { + for(const auto &o : m_outputs) { process_msg(o.get(), cmsg); } #endif @@ -302,59 +276,53 @@ inline void falco_outputs::push(const ctrl_msg& cmsg) // todo(leogr,leodido): this function is not supposed to throw exceptions, and with "noexcept", // the program is terminated if that occurs. Although that's the wanted behavior, // we still need to improve the error reporting since some inner functions can throw exceptions. -void falco_outputs::worker() noexcept -{ +void falco_outputs::worker() noexcept { watchdog wd; - wd.start([&](const std::string& payload) -> void { - falco_logger::log(falco_logger::level::CRIT, "\"" + payload + "\" output timeout, all output channels are blocked\n"); + wd.start([&](const std::string &payload) -> void { + falco_logger::log(falco_logger::level::CRIT, + "\"" + payload + "\" output timeout, all output channels are blocked\n"); }); auto timeout = m_timeout; falco_outputs::ctrl_msg cmsg; - do - { + do { // Block until a message becomes available. #ifndef __EMSCRIPTEN__ m_queue.pop(cmsg); #endif - for(const auto& o : m_outputs) - { + for(const auto &o : m_outputs) { wd.set_timeout(timeout, o->get_name()); - try - { + try { process_msg(o.get(), cmsg); - } - catch(const std::exception &e) - { - falco_logger::log(falco_logger::level::ERR, o->get_name() + ": " + std::string(e.what()) + "\n"); + } catch(const std::exception &e) { + falco_logger::log(falco_logger::level::ERR, + o->get_name() + ": " + std::string(e.what()) + "\n"); } } wd.cancel_timeout(); } while(cmsg.type != ctrl_msg_type::CTRL_MSG_STOP); } -inline void falco_outputs::process_msg(falco::outputs::abstract_output* o, const ctrl_msg& cmsg) -{ - switch(cmsg.type) - { - case ctrl_msg_type::CTRL_MSG_OUTPUT: - o->output(&cmsg); - break; - case ctrl_msg_type::CTRL_MSG_CLEANUP: - case ctrl_msg_type::CTRL_MSG_STOP: - o->cleanup(); - break; - case ctrl_msg_type::CTRL_MSG_REOPEN: - o->reopen(); - break; - default: - falco_logger::log(falco_logger::level::DEBUG, "Outputs worker received an unknown message type\n"); +inline void falco_outputs::process_msg(falco::outputs::abstract_output *o, const ctrl_msg &cmsg) { + switch(cmsg.type) { + case ctrl_msg_type::CTRL_MSG_OUTPUT: + o->output(&cmsg); + break; + case ctrl_msg_type::CTRL_MSG_CLEANUP: + case ctrl_msg_type::CTRL_MSG_STOP: + o->cleanup(); + break; + case ctrl_msg_type::CTRL_MSG_REOPEN: + o->reopen(); + break; + default: + falco_logger::log(falco_logger::level::DEBUG, + "Outputs worker received an unknown message type\n"); } } -uint64_t falco_outputs::get_outputs_queue_num_drops() -{ +uint64_t falco_outputs::get_outputs_queue_num_drops() { return m_outputs_queue_num_drops.load(); } diff --git a/userspace/falco/falco_outputs.h b/userspace/falco/falco_outputs.h index dc678ec32e4..860ffbdbcfa 100644 --- a/userspace/falco/falco_outputs.h +++ b/userspace/falco/falco_outputs.h @@ -29,66 +29,68 @@ limitations under the License. #endif /*! - \brief This class acts as the primary interface between a program and the - falco output engine. The falco rules engine is implemented by a - separate class falco_engine. + \brief This class acts as the primary interface between a program and the + falco output engine. The falco rules engine is implemented by a + separate class falco_engine. - All methods in this class are thread-safe. The output framework supports - a multi-producer model where messages are stored in a queue and consumed - by each configured output asynchronously. + All methods in this class are thread-safe. The output framework supports + a multi-producer model where messages are stored in a queue and consumed + by each configured output asynchronously. */ -class falco_outputs -{ +class falco_outputs { public: - falco_outputs( - std::shared_ptr engine, - const std::vector& outputs, - bool json_output, - bool json_include_output_property, - bool json_include_tags_property, - bool json_include_message_property, - uint32_t timeout, - bool buffered, - size_t outputs_queue_capacity, - bool time_format_iso_8601, - const std::string& hostname); + falco_outputs(std::shared_ptr engine, + const std::vector &outputs, + bool json_output, + bool json_include_output_property, + bool json_include_tags_property, + bool json_include_message_property, + uint32_t timeout, + bool buffered, + size_t outputs_queue_capacity, + bool time_format_iso_8601, + const std::string &hostname); virtual ~falco_outputs(); /*! - \brief Format then send the event to all configured outputs (`evt` - is an event that has matched some rule). + \brief Format then send the event to all configured outputs (`evt` + is an event that has matched some rule). */ - void handle_event(sinsp_evt *evt, const std::string &rule, const std::string &source, - falco_common::priority_type priority, const std::string &format, std::set &tags, - extra_output_field_t &extra_fields); + void handle_event(sinsp_evt *evt, + const std::string &rule, + const std::string &source, + falco_common::priority_type priority, + const std::string &format, + std::set &tags, + extra_output_field_t &extra_fields); /*! - \brief Format then send a generic message to all outputs. - Not necessarily associated with any event. + \brief Format then send a generic message to all outputs. + Not necessarily associated with any event. */ void handle_msg(uint64_t now, - falco_common::priority_type priority, - const std::string &msg, - const std::string &rule, - nlohmann::json &output_fields); + falco_common::priority_type priority, + const std::string &msg, + const std::string &rule, + nlohmann::json &output_fields); /*! - \brief Sends a cleanup message to all outputs. - Each output can have an implementation-specific behavior. - In general, this is used to flush or clean output buffers. + \brief Sends a cleanup message to all outputs. + Each output can have an implementation-specific behavior. + In general, this is used to flush or clean output buffers. */ void cleanup_outputs(); /*! - \brief Sends a message to all outputs that causes them to be closed and - reopened. Each output can have an implementation-specific behavior. + \brief Sends a message to all outputs that causes them to be closed and + reopened. Each output can have an implementation-specific behavior. */ void reopen_outputs(); /*! - \brief Return the number of events currently dropped due to failed push - attempts into the outputs queue + \brief Return the number of events currently dropped due to failed push + attempts into the outputs queue */ uint64_t get_outputs_queue_num_drops(); @@ -103,16 +105,14 @@ class falco_outputs std::chrono::milliseconds m_timeout; std::string m_hostname; - enum ctrl_msg_type - { + enum ctrl_msg_type { CTRL_MSG_STOP = 0, CTRL_MSG_OUTPUT = 1, CTRL_MSG_CLEANUP = 2, CTRL_MSG_REOPEN = 3, }; - struct ctrl_msg : falco::outputs::message - { + struct ctrl_msg : falco::outputs::message { ctrl_msg_type type; }; @@ -123,10 +123,10 @@ class falco_outputs std::atomic m_outputs_queue_num_drops = 0; std::thread m_worker_thread; - inline void push(const ctrl_msg& cmsg); + inline void push(const ctrl_msg &cmsg); inline void push_ctrl(ctrl_msg_type cmt); void worker() noexcept; void stop_worker(); - void add_output(const falco::outputs::config& oc); - inline void process_msg(falco::outputs::abstract_output* o, const ctrl_msg& cmsg); + void add_output(const falco::outputs::config &oc); + inline void process_msg(falco::outputs::abstract_output *o, const ctrl_msg &cmsg); }; diff --git a/userspace/falco/falco_semaphore.h b/userspace/falco/falco_semaphore.h index 458dd436437..866e69848f7 100644 --- a/userspace/falco/falco_semaphore.h +++ b/userspace/falco/falco_semaphore.h @@ -19,46 +19,41 @@ limitations under the License. #include #include -namespace falco -{ - /** - * @brief A simple semaphore implementation. Unfortunately, a standard - * semaphore is only available since C++20, which currently we don't target. - */ - class semaphore - { - public: - /** - * @brief Creates a semaphore with the given initial counter value - */ - explicit semaphore(int c = 0): count(c) {} - - /** - * @brief Increments the internal counter and unblocks acquirers - */ - inline void release() - { - std::unique_lock lock(mtx); - count++; - cv.notify_one(); - } - - /** - * @brief Decrements the internal counter or blocks until it can - */ - inline void acquire() - { - std::unique_lock lock(mtx); - while (count == 0) - { - cv.wait(lock); - } - count--; - } - - private: - std::mutex mtx; - std::condition_variable cv; - int count; - }; +namespace falco { +/** + * @brief A simple semaphore implementation. Unfortunately, a standard + * semaphore is only available since C++20, which currently we don't target. + */ +class semaphore { +public: + /** + * @brief Creates a semaphore with the given initial counter value + */ + explicit semaphore(int c = 0): count(c) {} + + /** + * @brief Increments the internal counter and unblocks acquirers + */ + inline void release() { + std::unique_lock lock(mtx); + count++; + cv.notify_one(); + } + + /** + * @brief Decrements the internal counter or blocks until it can + */ + inline void acquire() { + std::unique_lock lock(mtx); + while(count == 0) { + cv.wait(lock); + } + count--; + } + +private: + std::mutex mtx; + std::condition_variable cv; + int count; }; +}; // namespace falco diff --git a/userspace/falco/grpc_context.cpp b/userspace/falco/grpc_context.cpp index dc0989166bf..e21f2bdfa79 100644 --- a/userspace/falco/grpc_context.cpp +++ b/userspace/falco/grpc_context.cpp @@ -19,9 +19,7 @@ limitations under the License. #include "grpc_context.h" -falco::grpc::context::context(::grpc::ServerContext* ctx): - m_ctx(ctx) -{ +falco::grpc::context::context(::grpc::ServerContext* ctx): m_ctx(ctx) { std::string session_id; std::string request_id; @@ -30,29 +28,25 @@ falco::grpc::context::context(::grpc::ServerContext* ctx): bool has_meta = false; std::stringstream meta; - if(!session_id.empty()) - { + if(!session_id.empty()) { meta << "[sid=" << session_id << "]"; has_meta = true; } - if(!request_id.empty()) - { + if(!request_id.empty()) { meta << "[rid=" << request_id << "]"; has_meta = true; } - if(has_meta) - { + if(has_meta) { meta << " "; } m_prefix = meta.str(); } -void falco::grpc::context::context::get_metadata(std::string key, std::string& val) -{ - const std::multimap<::grpc::string_ref, ::grpc::string_ref>& client_metadata = m_ctx->client_metadata(); +void falco::grpc::context::context::get_metadata(std::string key, std::string& val) { + const std::multimap<::grpc::string_ref, ::grpc::string_ref>& client_metadata = + m_ctx->client_metadata(); auto it = client_metadata.find(key); - if(it != client_metadata.end()) - { + if(it != client_metadata.end()) { val.assign(it->second.data(), it->second.size()); } } diff --git a/userspace/falco/grpc_context.h b/userspace/falco/grpc_context.h index 20b4176b655..7940c2e6f68 100644 --- a/userspace/falco/grpc_context.h +++ b/userspace/falco/grpc_context.h @@ -25,16 +25,13 @@ limitations under the License. #include #endif -namespace falco -{ -namespace grpc -{ +namespace falco { +namespace grpc { const std::string meta_session = "session_id"; const std::string meta_request = "request_id"; -class context -{ +class context { public: explicit context(::grpc::ServerContext* ctx); virtual ~context() = default; @@ -46,32 +43,23 @@ class context std::string m_prefix; }; -class stream_context : public context -{ +class stream_context : public context { public: - explicit stream_context(::grpc::ServerContext* ctx): - context(ctx){}; + explicit stream_context(::grpc::ServerContext* ctx): context(ctx) {}; virtual ~stream_context() = default; - enum : char - { - STREAMING = 1, - SUCCESS, - ERROR - } m_status = STREAMING; + enum : char { STREAMING = 1, SUCCESS, ERROR } m_status = STREAMING; - mutable void* m_stream = nullptr; // todo(fntlnz, leodido) > useful in the future + mutable void* m_stream = nullptr; // todo(fntlnz, leodido) > useful in the future mutable bool m_has_more = false; mutable bool m_is_running = true; }; -class bidi_context : public stream_context -{ +class bidi_context : public stream_context { public: - explicit bidi_context(::grpc::ServerContext* ctx): - stream_context(ctx){}; + explicit bidi_context(::grpc::ServerContext* ctx): stream_context(ctx) {}; virtual ~bidi_context() = default; }; -} // namespace grpc -} // namespace falco +} // namespace grpc +} // namespace falco diff --git a/userspace/falco/grpc_queue.h b/userspace/falco/grpc_queue.h index 2f6c02eeb86..96af3a8e297 100644 --- a/userspace/falco/grpc_queue.h +++ b/userspace/falco/grpc_queue.h @@ -20,35 +20,23 @@ limitations under the License. #include "outputs.pb.h" #include "tbb/concurrent_queue.h" -namespace falco -{ -namespace grpc -{ +namespace falco { +namespace grpc { typedef tbb::concurrent_queue response_cq; -class queue -{ +class queue { public: - static queue& get() - { + static queue& get() { static queue instance; return instance; } - bool try_pop(outputs::response& res) - { - return m_queue.try_pop(res); - } + bool try_pop(outputs::response& res) { return m_queue.try_pop(res); } - void push(outputs::response& res) - { - m_queue.push(res); - } + void push(outputs::response& res) { m_queue.push(res); } private: - queue() - { - } + queue() {} response_cq m_queue; @@ -57,5 +45,5 @@ class queue queue(queue const&) = delete; void operator=(queue const&) = delete; }; -} // namespace grpc -} // namespace falco +} // namespace grpc +} // namespace falco diff --git a/userspace/falco/grpc_request_context.cpp b/userspace/falco/grpc_request_context.cpp index 55ba9a9de4f..66b9d4f49c6 100644 --- a/userspace/falco/grpc_request_context.cpp +++ b/userspace/falco/grpc_request_context.cpp @@ -19,14 +19,12 @@ limitations under the License. #include "grpc_request_context.h" -namespace falco -{ -namespace grpc -{ +namespace falco { +namespace grpc { template<> -void request_stream_context::start(server* srv) -{ +void request_stream_context::start( + server* srv) { m_state = request_context_base::REQUEST; m_srv_ctx = std::make_unique<::grpc::ServerContext>(); auto srvctx = m_srv_ctx.get(); @@ -39,29 +37,26 @@ void request_stream_context -void request_stream_context::process(server* srv) -{ +void request_stream_context::process( + server* srv) { // When it is the 1st process call - if(m_state == request_context_base::REQUEST) - { + if(m_state == request_context_base::REQUEST) { m_state = request_context_base::WRITE; m_stream_ctx = std::make_unique(m_srv_ctx.get()); } // Processing outputs::response res; - (srv->*m_process_func)(*m_stream_ctx, m_req, res); // get() + (srv->*m_process_func)(*m_stream_ctx, m_req, res); // get() - if(!m_stream_ctx->m_is_running) - { + if(!m_stream_ctx->m_is_running) { m_state = request_context_base::FINISH; m_res_writer->Finish(::grpc::Status::OK, this); return; } // When there are still more responses to stream - if(m_stream_ctx->m_has_more) - { + if(m_stream_ctx->m_has_more) { // todo(leodido) > log "write: tag=this, state=m_state" m_res_writer->Write(res, this); return; @@ -76,26 +71,24 @@ void request_stream_context -void request_stream_context::end(server* srv, bool error) -{ - if(m_stream_ctx) - { - if(error) - { - // todo(leodido) > log error "error streaming: tag=this, state=m_state, stream=m_stream_ctx->m_stream" +void request_stream_context::end( + server* srv, + bool error) { + if(m_stream_ctx) { + if(error) { + // todo(leodido) > log error "error streaming: tag=this, state=m_state, + // stream=m_stream_ctx->m_stream" } m_stream_ctx->m_status = error ? stream_context::ERROR : stream_context::SUCCESS; // Complete the processing outputs::response res; - (srv->*m_process_func)(*m_stream_ctx, m_req, res); // get() - } - else - { + (srv->*m_process_func)(*m_stream_ctx, m_req, res); // get() + } else { // Flow enters here when the processing of "m_request_func" fails. - // Since this happens into the `start()` function, the processing does not advance to the `process()` function. - // So, `m_stream_ctx` is null because it is set into the `process()` function. - // The stream haven't started. + // Since this happens into the `start()` function, the processing does not advance to the + // `process()` function. So, `m_stream_ctx` is null because it is set into the `process()` + // function. The stream haven't started. // todo(leodido) > log error "ending streaming: tag=this, state=m_state, stream=null" } @@ -105,8 +98,7 @@ void request_stream_context -void request_context::start(server* srv) -{ +void request_context::start(server* srv) { m_state = request_context_base::REQUEST; m_srv_ctx = std::make_unique<::grpc::ServerContext>(); auto srvctx = m_srv_ctx.get(); @@ -114,14 +106,13 @@ void request_context::sta m_req.Clear(); auto cq = srv->m_completion_queue.get(); // Request to start processing given requests. - // Using "this" - ie., the memory address of this context - as the tag that uniquely identifies the request. - // In this way, different contexts can serve different requests concurrently. + // Using "this" - ie., the memory address of this context - as the tag that uniquely identifies + // the request. In this way, different contexts can serve different requests concurrently. (srv->m_version_svc.*m_request_func)(srvctx, &m_req, m_res_writer.get(), cq, cq, this); } template<> -void request_context::process(server* srv) -{ +void request_context::process(server* srv) { version::response res; (srv->*m_process_func)(context(m_srv_ctx.get()), m_req, res); @@ -132,8 +123,8 @@ void request_context::pro } template<> -void request_context::end(server* srv, bool error) -{ +void request_context::end(server* srv, + bool error) { // todo(leodido) > handle processing errors here // Ask to start processing requests @@ -141,25 +132,26 @@ void request_context::end } template<> -void request_bidi_context::start(server* srv) -{ +void request_bidi_context::start( + server* srv) { m_state = request_context_base::REQUEST; m_srv_ctx = std::make_unique<::grpc::ServerContext>(); auto srvctx = m_srv_ctx.get(); - m_reader_writer = std::make_unique<::grpc::ServerAsyncReaderWriter>(srvctx); + m_reader_writer = + std::make_unique<::grpc::ServerAsyncReaderWriter>( + srvctx); m_req.Clear(); auto cq = srv->m_completion_queue.get(); // Request to start processing given requests. - // Using "this" - ie., the memory address of this context - as the tag that uniquely identifies the request. - // In this way, different contexts can serve different requests concurrently. + // Using "this" - ie., the memory address of this context - as the tag that uniquely identifies + // the request. In this way, different contexts can serve different requests concurrently. (srv->m_output_svc.*m_request_func)(srvctx, m_reader_writer.get(), cq, cq, this); }; template<> -void request_bidi_context::process(server* srv) -{ - switch(m_state) - { +void request_bidi_context::process( + server* srv) { + switch(m_state) { case request_context_base::REQUEST: m_bidi_ctx = std::make_unique(m_srv_ctx.get()); m_bidi_ctx->m_status = bidi_context::STREAMING; @@ -170,17 +162,15 @@ void request_bidi_context // Processing { outputs::response res; - (srv->*m_process_func)(*m_bidi_ctx, m_req, res); // sub() + (srv->*m_process_func)(*m_bidi_ctx, m_req, res); // sub() - if(!m_bidi_ctx->m_is_running) - { + if(!m_bidi_ctx->m_is_running) { m_state = request_context_base::FINISH; m_reader_writer->Finish(::grpc::Status::OK, this); return; } - if(m_bidi_ctx->m_has_more) - { + if(m_bidi_ctx->m_has_more) { m_state = request_context_base::WRITE; m_reader_writer->Write(res, this); return; @@ -197,20 +187,19 @@ void request_bidi_context }; template<> -void request_bidi_context::end(server* srv, bool error) -{ - if(m_bidi_ctx) - { +void request_bidi_context::end(server* srv, + bool error) { + if(m_bidi_ctx) { m_bidi_ctx->m_status = error ? bidi_context::ERROR : bidi_context::SUCCESS; // Complete the processing outputs::response res; - (srv->*m_process_func)(*m_bidi_ctx, m_req, res); // sub() + (srv->*m_process_func)(*m_bidi_ctx, m_req, res); // sub() } // Ask to start processing requests start(srv); }; -} // namespace grpc -} // namespace falco +} // namespace grpc +} // namespace falco diff --git a/userspace/falco/grpc_request_context.h b/userspace/falco/grpc_request_context.h index 09aa35af8ba..95dbe5e2a9f 100644 --- a/userspace/falco/grpc_request_context.h +++ b/userspace/falco/grpc_request_context.h @@ -21,26 +21,17 @@ limitations under the License. #include "grpc_server.h" -namespace falco -{ -namespace grpc -{ +namespace falco { +namespace grpc { -class request_context_base -{ +class request_context_base { public: request_context_base() = default; // virtual to guarantee that the derived classes are destructed properly virtual ~request_context_base() = default; std::unique_ptr<::grpc::ServerContext> m_srv_ctx; - enum : char - { - UNKNOWN = 0, - REQUEST, - WRITE, - FINISH - } m_state = UNKNOWN; + enum : char { UNKNOWN = 0, REQUEST, WRITE, FINISH } m_state = UNKNOWN; virtual void start(server* srv) = 0; virtual void process(server* srv) = 0; @@ -50,19 +41,21 @@ class request_context_base // The responsibility of `request_stream_context` template class // is to handle streaming responses. template -class request_stream_context : public request_context_base -{ +class request_stream_context : public request_context_base { public: - request_stream_context(): - m_process_func(nullptr), - m_request_func(nullptr){}; + request_stream_context(): m_process_func(nullptr), m_request_func(nullptr) {}; ~request_stream_context() = default; // Pointer to function that does actual processing void (server::*m_process_func)(const stream_context&, const Request&, Response&); // Pointer to function that requests the system to start processing given requests - void (Service::AsyncService::*m_request_func)(::grpc::ServerContext*, Request*, ::grpc::ServerAsyncWriter*, ::grpc::CompletionQueue*, ::grpc::ServerCompletionQueue*, void*); + void (Service::AsyncService::*m_request_func)(::grpc::ServerContext*, + Request*, + ::grpc::ServerAsyncWriter*, + ::grpc::CompletionQueue*, + ::grpc::ServerCompletionQueue*, + void*); void start(server* srv) override; void process(server* srv) override; @@ -77,19 +70,21 @@ class request_stream_context : public request_context_base // The responsibility of `request_context` template class // is to handle unary responses. template -class request_context : public request_context_base -{ +class request_context : public request_context_base { public: - request_context(): - m_process_func(nullptr), - m_request_func(nullptr){}; + request_context(): m_process_func(nullptr), m_request_func(nullptr) {}; ~request_context() = default; // Pointer to function that does actual processing void (server::*m_process_func)(const context&, const Request&, Response&); // Pointer to function that requests the system to start processing given requests - void (Service::AsyncService::*m_request_func)(::grpc::ServerContext*, Request*, ::grpc::ServerAsyncResponseWriter*, ::grpc::CompletionQueue*, ::grpc::ServerCompletionQueue*, void*); + void (Service::AsyncService::*m_request_func)(::grpc::ServerContext*, + Request*, + ::grpc::ServerAsyncResponseWriter*, + ::grpc::CompletionQueue*, + ::grpc::ServerCompletionQueue*, + void*); void start(server* srv) override; void process(server* srv) override; @@ -101,19 +96,21 @@ class request_context : public request_context_base }; template -class request_bidi_context : public request_context_base -{ +class request_bidi_context : public request_context_base { public: - request_bidi_context(): - m_process_func(nullptr), - m_request_func(nullptr){}; + request_bidi_context(): m_process_func(nullptr), m_request_func(nullptr) {}; ~request_bidi_context() = default; // Pointer to function that does actual processing void (server::*m_process_func)(const bidi_context&, const Request&, Response&); // Pointer to function that requests the system to start processing given requests - void (Service::AsyncService::*m_request_func)(::grpc::ServerContext*, ::grpc::ServerAsyncReaderWriter*, ::grpc::CompletionQueue*, ::grpc::ServerCompletionQueue*, void*); + void (Service::AsyncService::*m_request_func)( + ::grpc::ServerContext*, + ::grpc::ServerAsyncReaderWriter*, + ::grpc::CompletionQueue*, + ::grpc::ServerCompletionQueue*, + void*); void start(server* srv) override; void process(server* srv) override; @@ -125,5 +122,5 @@ class request_bidi_context : public request_context_base Request m_req; }; -} // namespace grpc -} // namespace falco +} // namespace grpc +} // namespace falco diff --git a/userspace/falco/grpc_server.cpp b/userspace/falco/grpc_server.cpp index c66056b087b..d8578e1361c 100644 --- a/userspace/falco/grpc_server.cpp +++ b/userspace/falco/grpc_server.cpp @@ -30,38 +30,33 @@ limitations under the License. #include "grpc_request_context.h" #include "falco_utils.h" -#define REGISTER_STREAM(req, res, svc, rpc, impl, num) \ +#define REGISTER_STREAM(req, res, svc, rpc, impl, num) \ std::vector> rpc##_contexts(num); \ - for(request_stream_context & c : rpc##_contexts) \ - { \ - c.m_process_func = &server::impl; \ - c.m_request_func = &svc::AsyncService::Request##rpc; \ - c.start(this); \ + for(request_stream_context & c : rpc##_contexts) { \ + c.m_process_func = &server::impl; \ + c.m_request_func = &svc::AsyncService::Request##rpc; \ + c.start(this); \ } -#define REGISTER_UNARY(req, res, svc, rpc, impl, num) \ +#define REGISTER_UNARY(req, res, svc, rpc, impl, num) \ std::vector> rpc##_contexts(num); \ - for(request_context & c : rpc##_contexts) \ - { \ - c.m_process_func = &server::impl; \ - c.m_request_func = &svc::AsyncService::Request##rpc; \ - c.start(this); \ + for(request_context & c : rpc##_contexts) { \ + c.m_process_func = &server::impl; \ + c.m_request_func = &svc::AsyncService::Request##rpc; \ + c.start(this); \ } -#define REGISTER_BIDI(req, res, svc, rpc, impl, num) \ +#define REGISTER_BIDI(req, res, svc, rpc, impl, num) \ std::vector> rpc##_contexts(num); \ - for(request_bidi_context & c : rpc##_contexts) \ - { \ - c.m_process_func = &server::impl; \ - c.m_request_func = &svc::AsyncService::Request##rpc; \ - c.start(this); \ + for(request_bidi_context & c : rpc##_contexts) { \ + c.m_process_func = &server::impl; \ + c.m_request_func = &svc::AsyncService::Request##rpc; \ + c.start(this); \ } -static void gpr_log_dispatcher_func(gpr_log_func_args* args) -{ +static void gpr_log_dispatcher_func(gpr_log_func_args* args) { falco_logger::level priority; - switch(args->severity) - { + switch(args->severity) { case GPR_LOG_SEVERITY_ERROR: priority = falco_logger::level::ERR; break; @@ -79,14 +74,11 @@ static void gpr_log_dispatcher_func(gpr_log_func_args* args) falco_logger::log(priority, std::move(copy)); } -void falco::grpc::server::thread_process(int thread_index) -{ +void falco::grpc::server::thread_process(int thread_index) { void* tag = nullptr; bool event_read_success = false; - while(m_completion_queue->Next(&tag, &event_read_success)) - { - if(tag == nullptr) - { + while(m_completion_queue->Next(&tag, &event_read_success)) { + if(tag == nullptr) { // todo(leodido) > log error "server completion queue error: empty tag" continue; } @@ -94,13 +86,12 @@ void falco::grpc::server::thread_process(int thread_index) // Obtain the context for a given tag request_context_base* ctx = static_cast(tag); - // todo(leodido) > log "next event: tag=tag, read_success=event_read_success, state=ctx->m_state" + // todo(leodido) > log "next event: tag=tag, read_success=event_read_success, + // state=ctx->m_state" // When event has not been read successfully - if(!event_read_success) - { - if(ctx->m_state != request_context_base::REQUEST) - { + if(!event_read_success) { + if(ctx->m_state != request_context_base::REQUEST) { // todo(leodido) > log error "server completion queue failing to read: tag=tag" // End the context with error @@ -110,8 +101,7 @@ void falco::grpc::server::thread_process(int thread_index) } // Process the event - switch(ctx->m_state) - { + switch(ctx->m_state) { case request_context_base::REQUEST: // Completion of m_request_func case request_context_base::WRITE: @@ -123,7 +113,8 @@ void falco::grpc::server::thread_process(int thread_index) ctx->end(this, false); break; default: - // todo(leodido) > log error "unknown completion queue event: tag=tag, state=ctx->m_state" + // todo(leodido) > log error "unknown completion queue event: tag=tag, + // state=ctx->m_state" break; } @@ -131,14 +122,12 @@ void falco::grpc::server::thread_process(int thread_index) } } -void falco::grpc::server::init( - const std::string& server_addr, - int threadiness, - const std::string& private_key, - const std::string& cert_chain, - const std::string& root_certs, - const std::string& log_level) -{ +void falco::grpc::server::init(const std::string& server_addr, + int threadiness, + const std::string& private_key, + const std::string& cert_chain, + const std::string& root_certs, + const std::string& log_level) { m_server_addr = server_addr; m_threadiness = threadiness; m_private_key = private_key; @@ -148,8 +137,7 @@ void falco::grpc::server::init( // Set the verbosity level of gpr logger falco::schema::priority logging_level = falco::schema::INFORMATIONAL; falco::schema::priority_Parse(log_level, &logging_level); - switch(logging_level) - { + switch(logging_level) { case falco::schema::ERROR: gpr_set_log_verbosity(GPR_LOG_SEVERITY_ERROR); break; @@ -165,16 +153,14 @@ void falco::grpc::server::init( gpr_log_verbosity_init(); gpr_set_log_function(gpr_log_dispatcher_func); - if(falco::utils::network::is_unix_scheme(m_server_addr)) - { + if(falco::utils::network::is_unix_scheme(m_server_addr)) { init_unix_server_builder(); return; } init_mtls_server_builder(); } -void falco::grpc::server::init_mtls_server_builder() -{ +void falco::grpc::server::init_mtls_server_builder() { std::string private_key; std::string cert_chain; std::string root_certs; @@ -182,46 +168,49 @@ void falco::grpc::server::init_mtls_server_builder() falco::utils::readfile(m_private_key, private_key); falco::utils::readfile(m_root_certs, root_certs); ::grpc::SslServerCredentialsOptions::PemKeyCertPair cert_pair{private_key, cert_chain}; - ::grpc::SslServerCredentialsOptions ssl_opts(GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY); + ::grpc::SslServerCredentialsOptions ssl_opts( + GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY); ssl_opts.pem_root_certs = root_certs; ssl_opts.pem_key_cert_pairs.push_back(cert_pair); m_server_builder.AddListeningPort(m_server_addr, ::grpc::SslServerCredentials(ssl_opts)); } -void falco::grpc::server::init_unix_server_builder() -{ +void falco::grpc::server::init_unix_server_builder() { m_server_builder.AddListeningPort(m_server_addr, ::grpc::InsecureServerCredentials()); } -void falco::grpc::server::run() -{ +void falco::grpc::server::run() { m_server_builder.RegisterService(&m_output_svc); m_server_builder.RegisterService(&m_version_svc); m_completion_queue = m_server_builder.AddCompletionQueue(); m_server = m_server_builder.BuildAndStart(); - if(m_server == nullptr) - { + if(m_server == nullptr) { falco_logger::log(falco_logger::level::EMERG, "Error starting gRPC server\n"); return; } falco_logger::log(falco_logger::level::INFO, "Starting gRPC server at " + m_server_addr + "\n"); // The number of contexts is multiple of the number of threads - // This defines the number of simultaneous completion queue requests of the same type (service::AsyncService::Request##RPC) - // For this approach to be sufficient server::IMPL have to be fast + // This defines the number of simultaneous completion queue requests of the same type + // (service::AsyncService::Request##RPC) For this approach to be sufficient server::IMPL have to + // be fast int context_num = m_threadiness * 10; // todo(leodido) > take a look at thread_stress_test.cc into grpc repository - REGISTER_UNARY(version::request, version::response, version::service, version, version, context_num) + REGISTER_UNARY(version::request, + version::response, + version::service, + version, + version, + context_num) REGISTER_STREAM(outputs::request, outputs::response, outputs::service, get, get, context_num) REGISTER_BIDI(outputs::request, outputs::response, outputs::service, sub, sub, context_num) m_threads.resize(m_threadiness); int thread_idx = 0; - for(std::thread& thread : m_threads) - { + for(std::thread& thread : m_threads) { thread = std::thread(&server::thread_process, this, thread_idx++); } // todo(leodido) > log "gRPC server running: threadiness=m_threads.size()" @@ -231,16 +220,15 @@ void falco::grpc::server::run() stop(); } -void falco::grpc::server::stop() -{ - falco_logger::log(falco_logger::level::INFO, "Shutting down gRPC server. Waiting until external connections are closed by clients\n"); +void falco::grpc::server::stop() { + falco_logger::log(falco_logger::level::INFO, + "Shutting down gRPC server. Waiting until external connections are closed by " + "clients\n"); m_completion_queue->Shutdown(); falco_logger::log(falco_logger::level::INFO, "Waiting for the gRPC threads to complete\n"); - for(std::thread& t : m_threads) - { - if(t.joinable()) - { + for(std::thread& t : m_threads) { + if(t.joinable()) { t.join(); } } @@ -250,26 +238,23 @@ void falco::grpc::server::stop() // Ignore remaining events void* ignore_tag = nullptr; bool ignore_ok = false; - while(m_completion_queue->Next(&ignore_tag, &ignore_ok)) - { + while(m_completion_queue->Next(&ignore_tag, &ignore_ok)) { } falco_logger::log(falco_logger::level::INFO, "Shutting down gRPC server complete\n"); } -bool falco::grpc::server::is_running() -{ - if(m_stop) - { +bool falco::grpc::server::is_running() { + if(m_stop) { return false; } return true; } -void falco::grpc::server::get(const stream_context& ctx, const outputs::request& req, outputs::response& res) -{ - if(ctx.m_status == stream_context::SUCCESS || ctx.m_status == stream_context::ERROR) - { +void falco::grpc::server::get(const stream_context& ctx, + const outputs::request& req, + outputs::response& res) { + if(ctx.m_status == stream_context::SUCCESS || ctx.m_status == stream_context::ERROR) { // todo(leodido) > log "status=ctx->m_status, stream=ctx->m_stream" ctx.m_stream = nullptr; return; @@ -284,10 +269,10 @@ void falco::grpc::server::get(const stream_context& ctx, const outputs::request& ctx.m_has_more = queue::get().try_pop(res); } -void falco::grpc::server::sub(const bidi_context& ctx, const outputs::request& req, outputs::response& res) -{ - if(ctx.m_status == stream_context::SUCCESS || ctx.m_status == stream_context::ERROR) - { +void falco::grpc::server::sub(const bidi_context& ctx, + const outputs::request& req, + outputs::response& res) { + if(ctx.m_status == stream_context::SUCCESS || ctx.m_status == stream_context::ERROR) { ctx.m_stream = nullptr; return; } @@ -301,8 +286,9 @@ void falco::grpc::server::sub(const bidi_context& ctx, const outputs::request& r ctx.m_has_more = queue::get().try_pop(res); } -void falco::grpc::server::version(const context& ctx, const version::request&, version::response& res) -{ +void falco::grpc::server::version(const context& ctx, + const version::request&, + version::response& res) { auto& build = *res.mutable_build(); build = FALCO_VERSION_BUILD; @@ -313,7 +299,7 @@ void falco::grpc::server::version(const context& ctx, const version::request&, v version = FALCO_VERSION; res.set_engine_version(FALCO_ENGINE_VERSION); - res.set_engine_fields_checksum(FALCO_ENGINE_CHECKSUM); + res.set_engine_fields_checksum(FALCO_ENGINE_CHECKSUM); auto engine_version = falco_engine::engine_version(); res.set_engine_major(engine_version.major()); res.set_engine_minor(engine_version.minor()); @@ -324,8 +310,7 @@ void falco::grpc::server::version(const context& ctx, const version::request&, v res.set_patch(FALCO_VERSION_PATCH); } -void falco::grpc::server::shutdown() -{ +void falco::grpc::server::shutdown() { m_stop = true; m_server->Shutdown(); } diff --git a/userspace/falco/grpc_server.h b/userspace/falco/grpc_server.h index fea50572fef..5c28206a445 100644 --- a/userspace/falco/grpc_server.h +++ b/userspace/falco/grpc_server.h @@ -25,25 +25,20 @@ limitations under the License. #include "version.grpc.pb.h" #include "grpc_context.h" -namespace falco -{ -namespace grpc -{ +namespace falco { +namespace grpc { -class server -{ +class server { public: server() = default; virtual ~server() = default; - void init( - const std::string& server_addr, - int threadiness, - const std::string& private_key, - const std::string& cert_chain, - const std::string& root_certs, - const std::string& log_level - ); + void init(const std::string& server_addr, + int threadiness, + const std::string& private_key, + const std::string& cert_chain, + const std::string& root_certs, + const std::string& log_level); void thread_process(int thread_index); void run(); void stop(); @@ -80,5 +75,5 @@ class server std::atomic m_stop{false}; }; -} // namespace grpc -} // namespace falco +} // namespace grpc +} // namespace falco diff --git a/userspace/falco/outputs.h b/userspace/falco/outputs.h index f6bf3b7c2c9..d3bae64f21f 100644 --- a/userspace/falco/outputs.h +++ b/userspace/falco/outputs.h @@ -23,17 +23,14 @@ limitations under the License. #include "falco_common.h" #include -namespace falco -{ -namespace outputs -{ +namespace falco { +namespace outputs { // // The way to refer to an output (file, syslog, stdout, etc.) // An output has a name and set of options. // -struct config -{ +struct config { std::string name; std::map options; }; @@ -43,8 +40,7 @@ struct config // - an event that has matched some rule, // - or a generic message (e.g., a drop alert). // -struct message -{ +struct message { uint64_t ts; falco_common::priority_type priority; std::string msg; @@ -59,13 +55,15 @@ struct message // a Falco output class. // -class abstract_output -{ +class abstract_output { public: virtual ~abstract_output() = default; - virtual bool init(const config& oc, bool buffered, const std::string& hostname, bool json_output, std::string &err) - { + virtual bool init(const config& oc, + bool buffered, + const std::string& hostname, + bool json_output, + std::string& err) { m_oc = oc; m_buffered = buffered; m_hostname = hostname; @@ -76,13 +74,10 @@ class abstract_output } // Return the output's name as per its configuration. - const std::string get_name() const - { - return m_oc.name; - } + const std::string get_name() const { return m_oc.name; } // Output a message. - virtual void output(const message *msg) = 0; + virtual void output(const message* msg) = 0; // Possibly close the output and open it again. virtual void reopen() {} @@ -97,5 +92,5 @@ class abstract_output bool m_json_output; }; -} // namespace outputs -} // namespace falco +} // namespace outputs +} // namespace falco diff --git a/userspace/falco/outputs_file.cpp b/userspace/falco/outputs_file.cpp index 40a043d567e..a7e89070772 100644 --- a/userspace/falco/outputs_file.cpp +++ b/userspace/falco/outputs_file.cpp @@ -19,43 +19,34 @@ limitations under the License. #include #include -void falco::outputs::output_file::open_file() -{ - if(!m_buffered) - { +void falco::outputs::output_file::open_file() { + if(!m_buffered) { m_outfile.rdbuf()->pubsetbuf(0, 0); } - if(!m_outfile.is_open()) - { + if(!m_outfile.is_open()) { m_outfile.open(m_oc.options["filename"], std::fstream::app); - if (m_outfile.fail()) - { + if(m_outfile.fail()) { throw falco_exception("failed to open output file " + m_oc.options["filename"]); } } } -void falco::outputs::output_file::output(const message *msg) -{ +void falco::outputs::output_file::output(const message *msg) { open_file(); m_outfile << msg->msg + "\n"; - if(m_oc.options["keep_alive"] != "true") - { + if(m_oc.options["keep_alive"] != "true") { cleanup(); } } -void falco::outputs::output_file::cleanup() -{ - if(m_outfile.is_open()) - { +void falco::outputs::output_file::cleanup() { + if(m_outfile.is_open()) { m_outfile.close(); } } -void falco::outputs::output_file::reopen() -{ +void falco::outputs::output_file::reopen() { cleanup(); open_file(); } diff --git a/userspace/falco/outputs_file.h b/userspace/falco/outputs_file.h index 2c6e7a98eed..02785539995 100644 --- a/userspace/falco/outputs_file.h +++ b/userspace/falco/outputs_file.h @@ -21,13 +21,10 @@ limitations under the License. #include #include -namespace falco -{ -namespace outputs -{ +namespace falco { +namespace outputs { -class output_file : public abstract_output -{ +class output_file : public abstract_output { void output(const message *msg) override; void cleanup() override; @@ -40,5 +37,5 @@ class output_file : public abstract_output std::ofstream m_outfile; }; -} // namespace outputs -} // namespace falco +} // namespace outputs +} // namespace falco diff --git a/userspace/falco/outputs_grpc.cpp b/userspace/falco/outputs_grpc.cpp index 13da0d3f239..7aef458d287 100644 --- a/userspace/falco/outputs_grpc.cpp +++ b/userspace/falco/outputs_grpc.cpp @@ -22,21 +22,21 @@ limitations under the License. #include "formats.h" #if __has_attribute(deprecated) -#define DISABLE_WARNING_PUSH _Pragma("GCC diagnostic push") -#define DISABLE_WARNING_POP _Pragma("GCC diagnostic pop") -#define DISABLE_WARNING_DEPRECATED_DECLARATIONS _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#define DISABLE_WARNING_PUSH _Pragma("GCC diagnostic push") +#define DISABLE_WARNING_POP _Pragma("GCC diagnostic pop") +#define DISABLE_WARNING_DEPRECATED_DECLARATIONS \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #elif defined(_MSC_VER) -#define DISABLE_WARNING_PUSH __pragma(warning(push)) -#define DISABLE_WARNING_POP __pragma(warning(pop)) -#define DISABLE_WARNING_DEPRECATED_DECLARATIONS __pragma(warning(disable: 4996)) +#define DISABLE_WARNING_PUSH __pragma(warning(push)) +#define DISABLE_WARNING_POP __pragma(warning(pop)) +#define DISABLE_WARNING_DEPRECATED_DECLARATIONS __pragma(warning(disable : 4996)) #else #define DISABLE_WARNING_PUSH #define DISABLE_WARNING_POP #define DISABLE_WARNING_DEPRECATED_DECLARATIONS #endif -void falco::outputs::output_grpc::output(const message *msg) -{ +void falco::outputs::output_grpc::output(const message *msg) { falco::outputs::response grpc_res; // time @@ -52,11 +52,10 @@ void falco::outputs::output_grpc::output(const message *msg) // 0-index enum element, which is the SYSCALL source in our case. // This can be misleading for clients with an old version of the // protobuf, so for now we deprecate the field and add a new PLUGIN - // enum entry instead. + // enum entry instead. // todo(jasondellaluce): remove source_deprecated and reserve its number falco::schema::source s = falco::schema::source::SYSCALL; - if(!falco::schema::source_Parse(msg->source, &s)) - { + if(!falco::schema::source_Parse(msg->source, &s)) { // unknown source names are expected to come from plugins s = falco::schema::source::PLUGIN; } @@ -67,8 +66,7 @@ void falco::outputs::output_grpc::output(const message *msg) // priority falco::schema::priority p = falco::schema::priority::EMERGENCY; - if(!falco::schema::priority_Parse(falco_common::format_priority(msg->priority), &p)) - { + if(!falco::schema::priority_Parse(falco_common::format_priority(msg->priority), &p)) { throw falco_exception("Unknown priority passed to output_grpc::output()"); } grpc_res.set_priority(p); @@ -79,15 +77,12 @@ void falco::outputs::output_grpc::output(const message *msg) // output fields auto &fields = *grpc_res.mutable_output_fields(); - for(const auto &kv : msg->fields.items()) - { - if (!kv.value().is_primitive()) - { + for(const auto &kv : msg->fields.items()) { + if(!kv.value().is_primitive()) { throw falco_exception("output_grpc: output fields must be key-value maps"); } - fields[kv.key()] = (kv.value().is_string()) - ? kv.value().get() - : kv.value().dump(); + fields[kv.key()] = + (kv.value().is_string()) ? kv.value().get() : kv.value().dump(); } // hostname diff --git a/userspace/falco/outputs_grpc.h b/userspace/falco/outputs_grpc.h index 84264b21a78..b388e8a51ff 100644 --- a/userspace/falco/outputs_grpc.h +++ b/userspace/falco/outputs_grpc.h @@ -19,15 +19,12 @@ limitations under the License. #include "outputs.h" -namespace falco -{ -namespace outputs -{ +namespace falco { +namespace outputs { -class output_grpc : public abstract_output -{ +class output_grpc : public abstract_output { void output(const message *msg) override; }; -} // namespace outputs -} // namespace falco +} // namespace outputs +} // namespace falco diff --git a/userspace/falco/outputs_http.cpp b/userspace/falco/outputs_http.cpp index 44c94c34ba3..1c36651dd6b 100644 --- a/userspace/falco/outputs_http.cpp +++ b/userspace/falco/outputs_http.cpp @@ -20,15 +20,17 @@ limitations under the License. #define CHECK_RES(fn) res = res == CURLE_OK ? fn : res -static size_t noop_write_callback(void *contents, size_t size, size_t nmemb, void *userp) -{ +static size_t noop_write_callback(void *contents, size_t size, size_t nmemb, void *userp) { // We don't want to echo anything. Just return size of bytes ignored return size * nmemb; } -bool falco::outputs::output_http::init(const config& oc, bool buffered, const std::string& hostname, bool json_output, std::string &err) -{ - if (!falco::outputs::abstract_output::init(oc, buffered, hostname, json_output, err)) { +bool falco::outputs::output_http::init(const config &oc, + bool buffered, + const std::string &hostname, + bool json_output, + std::string &err) { + if(!falco::outputs::abstract_output::init(oc, buffered, hostname, json_output, err)) { return false; } @@ -37,28 +39,23 @@ bool falco::outputs::output_http::init(const config& oc, bool buffered, const st CURLcode res = CURLE_FAILED_INIT; m_curl = curl_easy_init(); - if(!m_curl) - { - falco_logger::log(falco_logger::level::ERR, "libcurl failed to initialize the handle: " + std::string(curl_easy_strerror(res))); + if(!m_curl) { + falco_logger::log( + falco_logger::level::ERR, + "libcurl failed to initialize the handle: " + std::string(curl_easy_strerror(res))); return false; } - if(m_json_output) - { + if(m_json_output) { m_http_headers = curl_slist_append(m_http_headers, "Content-Type: application/json"); - } - else - { + } else { m_http_headers = curl_slist_append(m_http_headers, "Content-Type: text/plain"); } res = curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_http_headers); - + // if the URL is quoted the quotes should be removed to satisfy libcurl expected format std::string unquotedUrl = m_oc.options["url"]; - if (!unquotedUrl.empty() && ( - (unquotedUrl.front() == '\"' && unquotedUrl.back() == '\"') || - (unquotedUrl.front() == '\'' && unquotedUrl.back() == '\'') - )) - { + if(!unquotedUrl.empty() && ((unquotedUrl.front() == '\"' && unquotedUrl.back() == '\"') || + (unquotedUrl.front() == '\'' && unquotedUrl.back() == '\''))) { unquotedUrl = libsinsp::filter::unescape_str(unquotedUrl); } CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_URL, unquotedUrl.c_str())); @@ -66,67 +63,55 @@ bool falco::outputs::output_http::init(const config& oc, bool buffered, const st CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_USERAGENT, m_oc.options["user_agent"].c_str())); CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, -1L)); - if(m_oc.options["insecure"] == std::string("true")) - { + if(m_oc.options["insecure"] == std::string("true")) { CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L)); CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 0L)); } - if(m_oc.options["mtls"] == std::string("true")) - { + if(m_oc.options["mtls"] == std::string("true")) { CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSLCERT, m_oc.options["client_cert"].c_str())); CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSLKEY, m_oc.options["client_key"].c_str())); } - if (!m_oc.options["ca_cert"].empty()) - { + if(!m_oc.options["ca_cert"].empty()) { CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_CAINFO, m_oc.options["ca_cert"].c_str())); - } - else if(!m_oc.options["ca_bundle"].empty()) - { + } else if(!m_oc.options["ca_bundle"].empty()) { CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_CAINFO, m_oc.options["ca_bundle"].c_str())); - } - else - { + } else { CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_CAPATH, m_oc.options["ca_path"].c_str())); } - if(m_oc.options["echo"] == std::string("false")) - { + if(m_oc.options["echo"] == std::string("false")) { // If echo==true, libcurl defaults to fwrite to stdout, ie: echoing CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, noop_write_callback)); } - if(m_oc.options["compress_uploads"] == std::string("true")) - { + if(m_oc.options["compress_uploads"] == std::string("true")) { CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_TRANSFER_ENCODING, 1L)); } - if(m_oc.options["keep_alive"] == std::string("true")) - { + if(m_oc.options["keep_alive"] == std::string("true")) { CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_TCP_KEEPALIVE, 1L)); } - if(res != CURLE_OK) - { + if(res != CURLE_OK) { err = "libcurl error: " + std::string(curl_easy_strerror(res)); return false; } return true; } -void falco::outputs::output_http::output(const message *msg) -{ +void falco::outputs::output_http::output(const message *msg) { CURLcode res = curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, msg->msg.c_str()); CHECK_RES(curl_easy_perform(m_curl)); - if(res != CURLE_OK) - { - falco_logger::log(falco_logger::level::ERR, "libcurl failed to perform call: " + std::string(curl_easy_strerror(res))); + if(res != CURLE_OK) { + falco_logger::log( + falco_logger::level::ERR, + "libcurl failed to perform call: " + std::string(curl_easy_strerror(res))); } } -void falco::outputs::output_http::cleanup() -{ +void falco::outputs::output_http::cleanup() { curl_easy_cleanup(m_curl); m_curl = nullptr; curl_slist_free_all(m_http_headers); diff --git a/userspace/falco/outputs_http.h b/userspace/falco/outputs_http.h index 1f17269e659..653872b83f9 100644 --- a/userspace/falco/outputs_http.h +++ b/userspace/falco/outputs_http.h @@ -19,14 +19,15 @@ limitations under the License. #include "outputs.h" -namespace falco -{ -namespace outputs -{ - -class output_http : public abstract_output -{ - bool init(const config& oc, bool buffered, const std::string& hostname, bool json_output, std::string &err) override; +namespace falco { +namespace outputs { + +class output_http : public abstract_output { + bool init(const config &oc, + bool buffered, + const std::string &hostname, + bool json_output, + std::string &err) override; void output(const message *msg) override; void cleanup() override; @@ -35,5 +36,5 @@ class output_http : public abstract_output struct curl_slist *m_http_headers; }; -} // namespace outputs -} // namespace falco +} // namespace outputs +} // namespace falco diff --git a/userspace/falco/outputs_program.cpp b/userspace/falco/outputs_program.cpp index e87bac11e56..b6b16124817 100644 --- a/userspace/falco/outputs_program.cpp +++ b/userspace/falco/outputs_program.cpp @@ -18,42 +18,34 @@ limitations under the License. #include "outputs_program.h" #include -void falco::outputs::output_program::open_pfile() -{ - if(m_pfile == nullptr) - { +void falco::outputs::output_program::open_pfile() { + if(m_pfile == nullptr) { m_pfile = popen(m_oc.options["program"].c_str(), "w"); - if(!m_buffered) - { + if(!m_buffered) { setvbuf(m_pfile, NULL, _IONBF, 0); } } } -void falco::outputs::output_program::output(const message *msg) -{ +void falco::outputs::output_program::output(const message *msg) { open_pfile(); fprintf(m_pfile, "%s\n", msg->msg.c_str()); - if(m_oc.options["keep_alive"] != "true") - { + if(m_oc.options["keep_alive"] != "true") { cleanup(); } } -void falco::outputs::output_program::cleanup() -{ - if(m_pfile != nullptr) - { +void falco::outputs::output_program::cleanup() { + if(m_pfile != nullptr) { pclose(m_pfile); m_pfile = nullptr; } } -void falco::outputs::output_program::reopen() -{ +void falco::outputs::output_program::reopen() { cleanup(); open_pfile(); } diff --git a/userspace/falco/outputs_program.h b/userspace/falco/outputs_program.h index 387881842c2..24c1eccd129 100644 --- a/userspace/falco/outputs_program.h +++ b/userspace/falco/outputs_program.h @@ -19,13 +19,10 @@ limitations under the License. #include "outputs.h" -namespace falco -{ -namespace outputs -{ +namespace falco { +namespace outputs { -class output_program : public abstract_output -{ +class output_program : public abstract_output { void output(const message *msg) override; void cleanup() override; @@ -38,5 +35,5 @@ class output_program : public abstract_output FILE *m_pfile; }; -} // namespace outputs -} // namespace falco +} // namespace outputs +} // namespace falco diff --git a/userspace/falco/outputs_stdout.cpp b/userspace/falco/outputs_stdout.cpp index e63610b82d9..468cbc39532 100644 --- a/userspace/falco/outputs_stdout.cpp +++ b/userspace/falco/outputs_stdout.cpp @@ -18,22 +18,19 @@ limitations under the License. #include "outputs_stdout.h" #include -void falco::outputs::output_stdout::output(const message *msg) -{ +void falco::outputs::output_stdout::output(const message *msg) { // // By default, the stdout stream is fully buffered or line buffered // (if the stream can be determined to refer to an interactive device, e.g. in a TTY). // Just enable automatic flushing when unbuffered output is desired. // Note that it is set every time since other writings to the stdout can disable it. // - if(!m_buffered) - { + if(!m_buffered) { std::cout << std::unitbuf; } std::cout << msg->msg + "\n"; } -void falco::outputs::output_stdout::cleanup() -{ +void falco::outputs::output_stdout::cleanup() { std::cout.flush(); } diff --git a/userspace/falco/outputs_stdout.h b/userspace/falco/outputs_stdout.h index af98cf24cd7..546faf33701 100644 --- a/userspace/falco/outputs_stdout.h +++ b/userspace/falco/outputs_stdout.h @@ -19,17 +19,14 @@ limitations under the License. #include "outputs.h" -namespace falco -{ -namespace outputs -{ +namespace falco { +namespace outputs { -class output_stdout : public abstract_output -{ +class output_stdout : public abstract_output { void output(const message *msg) override; void cleanup() override; }; -} // namespace outputs -} // namespace falco +} // namespace outputs +} // namespace falco diff --git a/userspace/falco/outputs_syslog.cpp b/userspace/falco/outputs_syslog.cpp index 3637b2f9849..37c7afe9e87 100644 --- a/userspace/falco/outputs_syslog.cpp +++ b/userspace/falco/outputs_syslog.cpp @@ -18,8 +18,7 @@ limitations under the License. #include "outputs_syslog.h" #include -void falco::outputs::output_syslog::output(const message *msg) -{ +void falco::outputs::output_syslog::output(const message *msg) { // Syslog output should not have any trailing newline ::syslog(msg->priority, "%s", msg->msg.c_str()); } diff --git a/userspace/falco/outputs_syslog.h b/userspace/falco/outputs_syslog.h index 3e5d2054c2b..586062cd64c 100644 --- a/userspace/falco/outputs_syslog.h +++ b/userspace/falco/outputs_syslog.h @@ -19,15 +19,12 @@ limitations under the License. #include "outputs.h" -namespace falco -{ -namespace outputs -{ +namespace falco { +namespace outputs { -class output_syslog : public abstract_output -{ +class output_syslog : public abstract_output { void output(const message *msg) override; }; -} // namespace outputs -} // namespace falco +} // namespace outputs +} // namespace falco diff --git a/userspace/falco/stats_writer.cpp b/userspace/falco/stats_writer.cpp index ca986fec1d7..25d55c31e22 100644 --- a/userspace/falco/stats_writer.cpp +++ b/userspace/falco/stats_writer.cpp @@ -37,7 +37,7 @@ namespace fs = std::filesystem; // note: ticker_t is an uint16_t, which is enough because we don't care about // overflows here. Threads calling stats_writer::handle() will just // check that this value changed since their last observation. -static std::atomic s_timer((stats_writer::ticker_t) 0); +static std::atomic s_timer((stats_writer::ticker_t)0); #if !defined(__APPLE__) && !defined(_WIN32) static timer_t s_timerid; #else @@ -50,27 +50,23 @@ static uint16_t s_timerid; // remains a nullptr somehow. bool s_timerid_exists = false; -static void timer_handler(int signum) -{ +static void timer_handler(int signum) { s_timer.fetch_add(1, std::memory_order_relaxed); } #if defined(_WIN32) -bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) -{ +bool stats_writer::init_ticker(uint32_t interval_msec, std::string& err) { return true; } #endif #if defined(__APPLE__) -bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) -{ +bool stats_writer::init_ticker(uint32_t interval_msec, std::string& err) { struct sigaction handler = {}; - memset (&handler, 0, sizeof(handler)); + memset(&handler, 0, sizeof(handler)); handler.sa_handler = &timer_handler; - if (sigaction(SIGALRM, &handler, NULL) == -1) - { + if(sigaction(SIGALRM, &handler, NULL) == -1) { err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno); return false; } @@ -86,15 +82,13 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) #endif #if defined(EMSCRIPTEN) -bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) -{ +bool stats_writer::init_ticker(uint32_t interval_msec, std::string& err) { struct itimerspec timer = {}; struct sigaction handler = {}; - memset (&handler, 0, sizeof(handler)); + memset(&handler, 0, sizeof(handler)); handler.sa_handler = &timer_handler; - if (sigaction(SIGALRM, &handler, NULL) == -1) - { + if(sigaction(SIGALRM, &handler, NULL) == -1) { err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno); return false; } @@ -114,15 +108,13 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) #endif #if defined(__linux__) -bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) -{ +bool stats_writer::init_ticker(uint32_t interval_msec, std::string& err) { struct itimerspec timer = {}; struct sigaction handler = {}; - memset (&handler, 0, sizeof(handler)); + memset(&handler, 0, sizeof(handler)); handler.sa_handler = &timer_handler; - if (sigaction(SIGALRM, &handler, NULL) == -1) - { + if(sigaction(SIGALRM, &handler, NULL) == -1) { err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno); return false; } @@ -133,18 +125,15 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) sev.sigev_signo = SIGALRM; sev.sigev_value.sival_ptr = &s_timerid; // delete any previously set timer - if (s_timerid_exists) - { - if (timer_delete(s_timerid) == -1) - { + if(s_timerid_exists) { + if(timer_delete(s_timerid) == -1) { err = std::string("Could not delete previous timer: ") + strerror(errno); return false; } s_timerid_exists = false; } - if (timer_create(CLOCK_MONOTONIC, &sev, &s_timerid) == -1) - { + if(timer_create(CLOCK_MONOTONIC, &sev, &s_timerid) == -1) { err = std::string("Could not create periodic timer: ") + strerror(errno); return false; } @@ -154,8 +143,7 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) timer.it_value.tv_nsec = (interval_msec % 1000) * 1000 * 1000; timer.it_interval = timer.it_value; - if (timer_settime(s_timerid, 0, &timer, NULL) == -1) - { + if(timer_settime(s_timerid, 0, &timer, NULL) == -1) { err = std::string("Could not set up periodic timer: ") + strerror(errno); return false; } @@ -164,39 +152,33 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) } #endif -stats_writer::ticker_t stats_writer::get_ticker() -{ +stats_writer::ticker_t stats_writer::get_ticker() { return s_timer.load(std::memory_order_relaxed); } -stats_writer::stats_writer( - const std::shared_ptr& outputs, - const std::shared_ptr& config, - const std::shared_ptr& engine) - : m_config(config), m_engine(engine) -{ - if (config->m_metrics_enabled) - { +stats_writer::stats_writer(const std::shared_ptr& outputs, + const std::shared_ptr& config, + const std::shared_ptr& engine): + m_config(config), + m_engine(engine) { + if(config->m_metrics_enabled) { /* m_outputs should always be initialized because we use it * to extract output-queue stats in both cases: rule output and file output. */ m_outputs = outputs; - if (!config->m_metrics_output_file.empty()) - { + if(!config->m_metrics_output_file.empty()) { m_file_output.exceptions(std::ofstream::failbit | std::ofstream::badbit); m_file_output.open(config->m_metrics_output_file, std::ios_base::app); m_initialized = true; } - if (config->m_metrics_stats_rule_enabled) - { + if(config->m_metrics_stats_rule_enabled) { m_initialized = true; } } - if (m_initialized) - { + if(m_initialized) { #ifndef __EMSCRIPTEN__ // Adopt capacity for completeness, even if it's likely not relevant m_queue.set_capacity(config->m_outputs_queue_capacity); @@ -205,21 +187,17 @@ stats_writer::stats_writer( } } -stats_writer::~stats_writer() -{ - if (m_initialized) - { +stats_writer::~stats_writer() { + if(m_initialized) { #ifndef __EMSCRIPTEN__ stop_worker(); #endif - if (!m_config->m_metrics_output_file.empty()) - { + if(!m_config->m_metrics_output_file.empty()) { m_file_output.close(); } // delete timerID and reset timer #ifdef __linux__ - if (s_timerid_exists) - { + if(s_timerid_exists) { timer_delete(s_timerid); s_timerid_exists = false; } @@ -227,30 +205,25 @@ stats_writer::~stats_writer() } } -void stats_writer::stop_worker() -{ +void stats_writer::stop_worker() { stats_writer::msg msg; msg.stop = true; push(msg); - if(m_worker.joinable()) - { + if(m_worker.joinable()) { m_worker.join(); } } -inline void stats_writer::push(const stats_writer::msg& m) -{ - #ifndef __EMSCRIPTEN__ - if (!m_queue.try_push(m)) - { +inline void stats_writer::push(const stats_writer::msg& m) { +#ifndef __EMSCRIPTEN__ + if(!m_queue.try_push(m)) { fprintf(stderr, "Fatal error: Stats queue reached maximum capacity. Exiting.\n"); exit(EXIT_FAILURE); } - #endif +#endif } -void stats_writer::worker() noexcept -{ +void stats_writer::worker() noexcept { stats_writer::msg m; bool use_outputs = m_config->m_metrics_stats_rule_enabled; bool use_file = !m_config->m_metrics_output_file.empty(); @@ -258,61 +231,52 @@ void stats_writer::worker() noexcept auto last_tick = tick; auto first_tick = tick; - while(true) - { - // blocks until a message becomes availables - #ifndef __EMSCRIPTEN__ + while(true) { +// blocks until a message becomes availables +#ifndef __EMSCRIPTEN__ m_queue.pop(m); - #endif - if (m.stop) - { +#endif + if(m.stop) { return; } // this helps waiting for the first tick tick = stats_writer::get_ticker(); - if (first_tick != tick) - { - if (last_tick != tick) - { + if(first_tick != tick) { + if(last_tick != tick) { m_total_samples++; } last_tick = tick; - try - { - if (use_outputs) - { + try { + if(use_outputs) { std::string rule = "Falco internal: metrics snapshot"; std::string msg = "Falco metrics snapshot"; - m_outputs->handle_msg(m.ts, falco_common::PRIORITY_INFORMATIONAL, msg, rule, m.output_fields); + m_outputs->handle_msg(m.ts, + falco_common::PRIORITY_INFORMATIONAL, + msg, + rule, + m.output_fields); } - if (use_file) - { + if(use_file) { nlohmann::json jmsg; jmsg["sample"] = m_total_samples; jmsg["output_fields"] = m.output_fields; m_file_output << jmsg.dump() << std::endl; } - } - catch(const std::exception &e) - { - falco_logger::log(falco_logger::level::ERR, "stats_writer (worker): " + std::string(e.what()) + "\n"); + } catch(const std::exception& e) { + falco_logger::log(falco_logger::level::ERR, + "stats_writer (worker): " + std::string(e.what()) + "\n"); } } } } -stats_writer::collector::collector(const std::shared_ptr& writer) - : m_writer(writer) -{ -} +stats_writer::collector::collector(const std::shared_ptr& writer): m_writer(writer) {} -void add_netinfo_metrics_output_fields( - nlohmann::json& output_fields, - const std::shared_ptr& inspector) -{ +void add_netinfo_metrics_output_fields(nlohmann::json& output_fields, + const std::shared_ptr& inspector) { const auto ipv4_ifinfo = inspector->get_ifaddr_list().get_ipv4_list(); const auto ipv6_ifinfo = inspector->get_ifaddr_list().get_ipv6_list(); @@ -320,64 +284,62 @@ void add_netinfo_metrics_output_fields( std::map> ifnames_to_ipv4_addresses; std::map> ifnames_to_ipv6_addresses; - for (const auto& ifinfo : *ipv4_ifinfo) - { - if(ifinfo.m_name == "lo") - { + for(const auto& ifinfo : *ipv4_ifinfo) { + if(ifinfo.m_name == "lo") { continue; } auto it = ifnames_to_ipv4_addresses.find(ifinfo.m_name); auto address = ifinfo.addr_to_string(); - if (it == ifnames_to_ipv4_addresses.end()) - { + if(it == ifnames_to_ipv4_addresses.end()) { ifnames_to_ipv4_addresses.emplace(ifinfo.m_name, std::vector{address}); continue; } it->second.emplace_back(address); } - for (const auto& ifinfo : *ipv6_ifinfo) - { - if(ifinfo.m_name == "lo") - { + for(const auto& ifinfo : *ipv6_ifinfo) { + if(ifinfo.m_name == "lo") { continue; } auto it = ifnames_to_ipv6_addresses.find(ifinfo.m_name); auto address = ifinfo.addr_to_string(); - if (it == ifnames_to_ipv6_addresses.end()) - { + if(it == ifnames_to_ipv6_addresses.end()) { ifnames_to_ipv6_addresses.emplace(ifinfo.m_name, std::vector{address}); continue; } it->second.emplace_back(address); } - for (const auto& item : ifnames_to_ipv4_addresses) - { - auto metric_name = "falco.host_netinfo.interfaces." + item.first + ".protocols.ipv4.addresses"; - auto addresses = sinsp_join(item.second.cbegin(), item.second.cend(), ','); + for(const auto& item : ifnames_to_ipv4_addresses) { + auto metric_name = + "falco.host_netinfo.interfaces." + item.first + ".protocols.ipv4.addresses"; + auto addresses = sinsp_join(item.second.cbegin(), item.second.cend(), ','); output_fields.emplace(metric_name, addresses); } - for (const auto& item : ifnames_to_ipv6_addresses) - { - auto metric_name = "falco.host_netinfo.interfaces." + item.first + ".protocols.ipv6.addresses"; + for(const auto& item : ifnames_to_ipv6_addresses) { + auto metric_name = + "falco.host_netinfo.interfaces." + item.first + ".protocols.ipv6.addresses"; auto addresses = sinsp_join(item.second.cbegin(), item.second.cend(), ','); output_fields.emplace(metric_name, addresses); } } void stats_writer::collector::get_metrics_output_fields_wrapper( - nlohmann::json& output_fields, - const std::shared_ptr& inspector, - const std::string& src, uint64_t num_evts, - uint64_t now, double stats_snapshot_time_delta_sec) -{ - static const char* all_driver_engines[] = { - BPF_ENGINE, KMOD_ENGINE, MODERN_BPF_ENGINE, - SOURCE_PLUGIN_ENGINE, NODRIVER_ENGINE, GVISOR_ENGINE }; + nlohmann::json& output_fields, + const std::shared_ptr& inspector, + const std::string& src, + uint64_t num_evts, + uint64_t now, + double stats_snapshot_time_delta_sec) { + static const char* all_driver_engines[] = {BPF_ENGINE, + KMOD_ENGINE, + MODERN_BPF_ENGINE, + SOURCE_PLUGIN_ENGINE, + NODRIVER_ENGINE, + GVISOR_ENGINE}; const scap_agent_info* agent_info = inspector->get_agent_info(); const scap_machine_info* machine_info = inspector->get_machine_info(); @@ -385,36 +347,39 @@ void stats_writer::collector::get_metrics_output_fields_wrapper( // /* Wrapper fields useful for statistical analyses and attributions. Always enabled. */ - output_fields["evt.time"] = now; /* Some ETLs may prefer a consistent timestamp within output_fields. */ + output_fields["evt.time"] = + now; /* Some ETLs may prefer a consistent timestamp within output_fields. */ output_fields["falco.version"] = FALCO_VERSION; - if (agent_info) - { + if(agent_info) { output_fields["falco.start_ts"] = agent_info->start_ts_epoch; - output_fields["falco.duration_sec"] = (uint64_t)((now - agent_info->start_ts_epoch) / ONE_SECOND_IN_NS); + output_fields["falco.duration_sec"] = + (uint64_t)((now - agent_info->start_ts_epoch) / ONE_SECOND_IN_NS); output_fields["falco.kernel_release"] = agent_info->uname_r; } - if (machine_info) - { - output_fields["evt.hostname"] = machine_info->hostname; /* Explicitly add hostname to log msg in case hostname rule output field is disabled. */ + if(machine_info) { + output_fields["evt.hostname"] = + machine_info->hostname; /* Explicitly add hostname to log msg in case hostname rule + output field is disabled. */ output_fields["falco.host_boot_ts"] = machine_info->boot_ts_epoch; output_fields["falco.host_num_cpus"] = machine_info->num_cpus; } - output_fields["falco.outputs_queue_num_drops"] = m_writer->m_outputs->get_outputs_queue_num_drops(); + output_fields["falco.outputs_queue_num_drops"] = + m_writer->m_outputs->get_outputs_queue_num_drops(); #if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) - for (const auto& item : m_writer->m_config->m_loaded_rules_filenames_sha256sum) - { + for(const auto& item : m_writer->m_config->m_loaded_rules_filenames_sha256sum) { fs::path fs_path = item.first; std::string metric_name_file_sha256 = fs_path.filename(); - metric_name_file_sha256 = "falco.sha256_rules_file." + falco::utils::sanitize_rule_name(metric_name_file_sha256); + metric_name_file_sha256 = "falco.sha256_rules_file." + + falco::utils::sanitize_rule_name(metric_name_file_sha256); output_fields[metric_name_file_sha256] = item.second; } - for (const auto& item : m_writer->m_config->m_loaded_configs_filenames_sha256sum) - { + for(const auto& item : m_writer->m_config->m_loaded_configs_filenames_sha256sum) { fs::path fs_path = item.first; std::string metric_name_file_sha256 = fs_path.filename(); - metric_name_file_sha256 = "falco.sha256_config_file." + falco::utils::sanitize_rule_name(metric_name_file_sha256); + metric_name_file_sha256 = "falco.sha256_config_file." + + falco::utils::sanitize_rule_name(metric_name_file_sha256); output_fields[metric_name_file_sha256] = item.second; } @@ -422,20 +387,21 @@ void stats_writer::collector::get_metrics_output_fields_wrapper( #endif output_fields["evt.source"] = src; - for (size_t i = 0; i < sizeof(all_driver_engines) / sizeof(const char*); i++) - { - if (inspector->check_current_engine(all_driver_engines[i])) - { + for(size_t i = 0; i < sizeof(all_driver_engines) / sizeof(const char*); i++) { + if(inspector->check_current_engine(all_driver_engines[i])) { output_fields["scap.engine_name"] = all_driver_engines[i]; break; } } /* Falco userspace event counters. Always enabled. */ - if (m_last_num_evts != 0 && stats_snapshot_time_delta_sec > 0) - { + if(m_last_num_evts != 0 && stats_snapshot_time_delta_sec > 0) { /* Successfully processed userspace event rate. */ - output_fields["falco.evts_rate_sec"] = std::round((double)((num_evts - m_last_num_evts) / (double)stats_snapshot_time_delta_sec) * 10.0) / 10.0; // round to 1 decimal + output_fields["falco.evts_rate_sec"] = + std::round((double)((num_evts - m_last_num_evts) / + (double)stats_snapshot_time_delta_sec) * + 10.0) / + 10.0; // round to 1 decimal } output_fields["falco.num_evts"] = num_evts; output_fields["falco.num_evts_prev"] = m_last_num_evts; @@ -443,34 +409,31 @@ void stats_writer::collector::get_metrics_output_fields_wrapper( } void stats_writer::collector::get_metrics_output_fields_additional( - nlohmann::json& output_fields, - double stats_snapshot_time_delta_sec) -{ + nlohmann::json& output_fields, + double stats_snapshot_time_delta_sec) { // Falco metrics categories // // rules_counters_enabled - if(m_writer->m_config->m_metrics_flags & METRICS_V2_RULE_COUNTERS) - { + if(m_writer->m_config->m_metrics_flags & METRICS_V2_RULE_COUNTERS) { const stats_manager& rule_stats_manager = m_writer->m_engine->get_rule_stats_manager(); const indexed_vector& rules = m_writer->m_engine->get_rules(); output_fields["falco.rules.matches_total"] = rule_stats_manager.get_total().load(); - const std::vector>>& rules_by_id = rule_stats_manager.get_by_rule_id(); - for (size_t i = 0; i < rules_by_id.size(); i++) - { + const std::vector>>& rules_by_id = + rule_stats_manager.get_by_rule_id(); + for(size_t i = 0; i < rules_by_id.size(); i++) { auto rule_count = rules_by_id[i]->load(); - if (rule_count == 0 && !m_writer->m_config->m_metrics_include_empty_values) - { + if(rule_count == 0 && !m_writer->m_config->m_metrics_include_empty_values) { continue; } auto rule = rules.at(i); - std::string rules_metric_name = "falco.rules." + falco::utils::sanitize_rule_name(rule->name); + std::string rules_metric_name = + "falco.rules." + falco::utils::sanitize_rule_name(rule->name); output_fields[rules_metric_name] = rule_count; } } #if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) - if (m_writer->m_libs_metrics_collector && m_writer->m_output_rule_metrics_converter) - { + if(m_writer->m_libs_metrics_collector && m_writer->m_output_rule_metrics_converter) { // Libs metrics categories // // resource_utilization_enabled @@ -488,108 +451,97 @@ void stats_writer::collector::get_metrics_output_fields_additional( uint64_t n_drops_delta = 0; // Note: Because of possible metric unit conversions, get a non-const ref to the metric. - for (auto& metric: metrics_snapshot) - { - if (metric.name[0] == '\0') - { + for(auto& metric : metrics_snapshot) { + if(metric.name[0] == '\0') { break; } - if (m_writer->m_config->m_metrics_convert_memory_to_mb) - { - m_writer->m_output_rule_metrics_converter->convert_metric_to_unit_convention(metric); + if(m_writer->m_config->m_metrics_convert_memory_to_mb) { + m_writer->m_output_rule_metrics_converter->convert_metric_to_unit_convention( + metric); } char metric_name[METRIC_NAME_MAX] = "falco."; - if((metric.flags & METRICS_V2_LIBBPF_STATS) || (metric.flags & METRICS_V2_KERNEL_COUNTERS) || (metric.flags & METRICS_V2_KERNEL_COUNTERS_PER_CPU) ) - { + if((metric.flags & METRICS_V2_LIBBPF_STATS) || + (metric.flags & METRICS_V2_KERNEL_COUNTERS) || + (metric.flags & METRICS_V2_KERNEL_COUNTERS_PER_CPU)) { strlcpy(metric_name, "scap.", sizeof(metric_name)); } - if(metric.flags & METRICS_V2_PLUGINS) - { + if(metric.flags & METRICS_V2_PLUGINS) { strlcpy(metric_name, "plugins.", sizeof(metric_name)); } strlcat(metric_name, metric.name, sizeof(metric_name)); - switch (metric.type) - { + switch(metric.type) { case METRIC_VALUE_TYPE_U32: - if (metric.value.u32 == 0 && !m_writer->m_config->m_metrics_include_empty_values) - { + if(metric.value.u32 == 0 && !m_writer->m_config->m_metrics_include_empty_values) { break; } output_fields[metric_name] = metric.value.u32; break; case METRIC_VALUE_TYPE_S32: - if (metric.value.s32 == 0 && !m_writer->m_config->m_metrics_include_empty_values) - { + if(metric.value.s32 == 0 && !m_writer->m_config->m_metrics_include_empty_values) { break; } output_fields[metric_name] = metric.value.s32; break; case METRIC_VALUE_TYPE_U64: - if (strncmp(metric.name, "n_evts", 7) == 0) - { + if(strncmp(metric.name, "n_evts", 7) == 0) { n_evts = metric.value.u64; - // Always send high level n_evts related fields, even if zero and configs are set to exclude empty values. + // Always send high level n_evts related fields, even if zero and configs are + // set to exclude empty values. output_fields[metric_name] = n_evts; output_fields["scap.n_evts_prev"] = m_last_n_evts; n_evts_delta = n_evts - m_last_n_evts; - if (n_evts_delta != 0 && stats_snapshot_time_delta_sec > 0) - { - output_fields["scap.evts_rate_sec"] = std::round((double)(n_evts_delta / stats_snapshot_time_delta_sec) * 10.0) / 10.0; // round to 1 decimal - } - else - { + if(n_evts_delta != 0 && stats_snapshot_time_delta_sec > 0) { + output_fields["scap.evts_rate_sec"] = + std::round((double)(n_evts_delta / stats_snapshot_time_delta_sec) * + 10.0) / + 10.0; // round to 1 decimal + } else { output_fields["scap.evts_rate_sec"] = (double)(0); } m_last_n_evts = n_evts; - } - else if (strncmp(metric.name, "n_drops", 8) == 0) - { + } else if(strncmp(metric.name, "n_drops", 8) == 0) { n_drops = metric.value.u64; - // Always send high level n_drops related fields, even if zero and configs are set to exclude empty values. + // Always send high level n_drops related fields, even if zero and configs are + // set to exclude empty values. output_fields[metric_name] = n_drops; output_fields["scap.n_drops_prev"] = m_last_n_drops; n_drops_delta = n_drops - m_last_n_drops; - if (n_drops_delta != 0 && stats_snapshot_time_delta_sec > 0) - { - output_fields["scap.evts_drop_rate_sec"] = std::round((double)(n_drops_delta / stats_snapshot_time_delta_sec) * 10.0) / 10.0; // round to 1 decimal - } - else - { + if(n_drops_delta != 0 && stats_snapshot_time_delta_sec > 0) { + output_fields["scap.evts_drop_rate_sec"] = + std::round((double)(n_drops_delta / stats_snapshot_time_delta_sec) * + 10.0) / + 10.0; // round to 1 decimal + } else { output_fields["scap.evts_drop_rate_sec"] = (double)(0); } m_last_n_drops = n_drops; } - if (metric.value.u64 == 0 && !m_writer->m_config->m_metrics_include_empty_values) - { + if(metric.value.u64 == 0 && !m_writer->m_config->m_metrics_include_empty_values) { break; } output_fields[metric_name] = metric.value.u64; break; case METRIC_VALUE_TYPE_S64: - if (metric.value.s64 == 0 && !m_writer->m_config->m_metrics_include_empty_values) - { + if(metric.value.s64 == 0 && !m_writer->m_config->m_metrics_include_empty_values) { break; } output_fields[metric_name] = metric.value.s64; break; case METRIC_VALUE_TYPE_D: - if (metric.value.d == 0 && !m_writer->m_config->m_metrics_include_empty_values) - { + if(metric.value.d == 0 && !m_writer->m_config->m_metrics_include_empty_values) { break; } output_fields[metric_name] = metric.value.d; break; case METRIC_VALUE_TYPE_F: - if (metric.value.f == 0 && !m_writer->m_config->m_metrics_include_empty_values) - { + if(metric.value.f == 0 && !m_writer->m_config->m_metrics_include_empty_values) { break; } output_fields[metric_name] = metric.value.f; break; case METRIC_VALUE_TYPE_I: - if (metric.value.i == 0 && !m_writer->m_config->m_metrics_include_empty_values) - { + if(metric.value.i == 0 && !m_writer->m_config->m_metrics_include_empty_values) { break; } output_fields[metric_name] = metric.value.i; @@ -600,64 +552,66 @@ void stats_writer::collector::get_metrics_output_fields_additional( } /* n_drops_perc needs to be calculated outside the loop given no field ordering guarantees. * Always send n_drops_perc, even if zero and configs are set to exclude empty values. */ - if(n_evts_delta > 0) - { + if(n_evts_delta > 0) { output_fields["scap.n_drops_perc"] = (double)((100.0 * n_drops_delta) / n_evts_delta); - } - else - { + } else { output_fields["scap.n_drops_perc"] = (double)(0); } } #endif } -void stats_writer::collector::collect(const std::shared_ptr& inspector, const std::string &src, uint64_t num_evts) -{ - if (m_writer->has_output()) - { +void stats_writer::collector::collect(const std::shared_ptr& inspector, + const std::string& src, + uint64_t num_evts) { + if(m_writer->has_output()) { #if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) - if(!m_writer->m_libs_metrics_collector) - { + if(!m_writer->m_libs_metrics_collector) { uint32_t flags = m_writer->m_config->m_metrics_flags; - // Note: ENGINE_FLAG_BPF_STATS_ENABLED check has been moved to libs, that is, when libbpf stats is not enabled - // in the kernel settings we won't collect them even if the end user enabled the libbpf stats option - if (!(inspector->check_current_engine(BPF_ENGINE) || inspector->check_current_engine(MODERN_BPF_ENGINE))) - { + // Note: ENGINE_FLAG_BPF_STATS_ENABLED check has been moved to libs, that is, when + // libbpf stats is not enabled in the kernel settings we won't collect them even if the + // end user enabled the libbpf stats option + if(!(inspector->check_current_engine(BPF_ENGINE) || + inspector->check_current_engine(MODERN_BPF_ENGINE))) { flags &= ~METRICS_V2_LIBBPF_STATS; } // Note: src is static for live captures - if (src != falco_common::syscall_source) - { - flags &= ~(METRICS_V2_KERNEL_COUNTERS | METRICS_V2_KERNEL_COUNTERS_PER_CPU | METRICS_V2_STATE_COUNTERS | METRICS_V2_LIBBPF_STATS); - + if(src != falco_common::syscall_source) { + flags &= ~(METRICS_V2_KERNEL_COUNTERS | METRICS_V2_KERNEL_COUNTERS_PER_CPU | + METRICS_V2_STATE_COUNTERS | METRICS_V2_LIBBPF_STATS); } - m_writer->m_libs_metrics_collector = std::make_unique(inspector.get(), flags); + m_writer->m_libs_metrics_collector = + std::make_unique(inspector.get(), flags); } - if(!m_writer->m_output_rule_metrics_converter) - { - m_writer->m_output_rule_metrics_converter = std::make_unique(); + if(!m_writer->m_output_rule_metrics_converter) { + m_writer->m_output_rule_metrics_converter = + std::make_unique(); } #endif /* Collect stats / metrics once per ticker period. */ auto tick = stats_writer::get_ticker(); - if (tick != m_last_tick) - { + if(tick != m_last_tick) { m_last_tick = tick; auto now = std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()).count(); + std::chrono::system_clock::now().time_since_epoch()) + .count(); uint64_t stats_snapshot_time_delta = 0; - if (m_last_now != 0) - { + if(m_last_now != 0) { stats_snapshot_time_delta = now - m_last_now; } m_last_now = now; - double stats_snapshot_time_delta_sec = (stats_snapshot_time_delta / (double)ONE_SECOND_IN_NS); + double stats_snapshot_time_delta_sec = + (stats_snapshot_time_delta / (double)ONE_SECOND_IN_NS); /* Get respective metrics output_fields. */ nlohmann::json output_fields; - get_metrics_output_fields_wrapper(output_fields, inspector, src, num_evts, now, stats_snapshot_time_delta_sec); + get_metrics_output_fields_wrapper(output_fields, + inspector, + src, + num_evts, + now, + stats_snapshot_time_delta_sec); get_metrics_output_fields_additional(output_fields, stats_snapshot_time_delta_sec); /* Send message in the queue */ diff --git a/userspace/falco/stats_writer.h b/userspace/falco/stats_writer.h index b25ed4dd609..0dd0a7ff89d 100644 --- a/userspace/falco/stats_writer.h +++ b/userspace/falco/stats_writer.h @@ -30,49 +30,56 @@ limitations under the License. #include "configuration.h" /*! - \brief Writes stats samples collected from inspectors into a given output. - Users must use a stats_writer::collector in order to collect and write stats - into a given stats_writer. This class is thread-safe, and can be shared - across multiple stats_writer::collector instances from different threads. + \brief Writes stats samples collected from inspectors into a given output. + Users must use a stats_writer::collector in order to collect and write stats + into a given stats_writer. This class is thread-safe, and can be shared + across multiple stats_writer::collector instances from different threads. */ -class stats_writer -{ +class stats_writer { public: /*! - \brief Value of a ticker that dictates when stats are collected + \brief Value of a ticker that dictates when stats are collected */ typedef uint16_t ticker_t; /*! - \brief Collects stats samples from an inspector and uses a writer - to print them in a given output. Stats are collected periodically every - time the value of stats_writer::get_ticker() changes. - This class is not thread-safe. + \brief Collects stats samples from an inspector and uses a writer + to print them in a given output. Stats are collected periodically every + time the value of stats_writer::get_ticker() changes. + This class is not thread-safe. */ - class collector - { + class collector { public: /*! - \brief Initializes the collector with the given writer + \brief Initializes the collector with the given writer */ explicit collector(const std::shared_ptr& writer); /*! - \brief Collects one stats sample from an inspector - and for the given event source name + \brief Collects one stats sample from an inspector + and for the given event source name */ - void collect(const std::shared_ptr& inspector, const std::string& src, uint64_t num_evts); + void collect(const std::shared_ptr& inspector, + const std::string& src, + uint64_t num_evts); private: /*! - \brief Collect snapshot metrics wrapper fields as internal rule formatted output fields. + \brief Collect snapshot metrics wrapper fields as internal rule formatted output fields. */ - void get_metrics_output_fields_wrapper(nlohmann::json& output_fields, const std::shared_ptr& inspector, const std::string& src, uint64_t num_evts, uint64_t now, double stats_snapshot_time_delta_sec); + void get_metrics_output_fields_wrapper(nlohmann::json& output_fields, + const std::shared_ptr& inspector, + const std::string& src, + uint64_t num_evts, + uint64_t now, + double stats_snapshot_time_delta_sec); /*! - \brief Collect the configurable snapshot metrics as internal rule formatted output fields. + \brief Collect the configurable snapshot metrics as internal rule formatted output + fields. */ - void get_metrics_output_fields_additional(nlohmann::json& output_fields, double stats_snapshot_time_delta_sec); + void get_metrics_output_fields_additional(nlohmann::json& output_fields, + double stats_snapshot_time_delta_sec); std::shared_ptr m_writer; stats_writer::ticker_t m_last_tick = 0; @@ -93,42 +100,38 @@ class stats_writer ~stats_writer(); /*! - \brief Initializes a writer. + \brief Initializes a writer. */ stats_writer(const std::shared_ptr& outputs, - const std::shared_ptr& config, - const std::shared_ptr& engine); + const std::shared_ptr& config, + const std::shared_ptr& engine); /*! - \brief Returns true if the writer is configured with a valid output. + \brief Returns true if the writer is configured with a valid output. */ - inline bool has_output() const - { - return m_initialized; - } + inline bool has_output() const { return m_initialized; } /*! - \brief Initializes the ticker with a given interval period defined - in milliseconds. Subsequent calls to init_ticker will dismiss the - previously-initialized ticker. Internally, this uses a timer - signal handler. + \brief Initializes the ticker with a given interval period defined + in milliseconds. Subsequent calls to init_ticker will dismiss the + previously-initialized ticker. Internally, this uses a timer + signal handler. */ - static bool init_ticker(uint32_t interval_msec, std::string &err); + static bool init_ticker(uint32_t interval_msec, std::string& err); /*! - \brief Returns the current value of the ticker. - This function is thread-safe. + \brief Returns the current value of the ticker. + This function is thread-safe. */ inline static ticker_t get_ticker(); private: - struct msg - { + struct msg { msg() {} msg(msg&&) = default; - msg& operator = (msg&&) = default; + msg& operator=(msg&&) = default; msg(const msg&) = default; - msg& operator = (const msg&) = default; + msg& operator=(const msg&) = default; bool stop = false; uint64_t ts = 0; diff --git a/userspace/falco/versions_info.cpp b/userspace/falco/versions_info.cpp index a183fe5dcba..fb59d776b7f 100644 --- a/userspace/falco/versions_info.cpp +++ b/userspace/falco/versions_info.cpp @@ -20,60 +20,64 @@ limitations under the License. #include // todo: move string conversion to scap -static std::string get_driver_api_version(const std::shared_ptr& s) -{ - auto driver_api_version = s->get_scap_api_version(); - unsigned long driver_api_major = PPM_API_VERSION_MAJOR(driver_api_version); - unsigned long driver_api_minor = PPM_API_VERSION_MINOR(driver_api_version); - unsigned long driver_api_patch = PPM_API_VERSION_PATCH(driver_api_version); +static std::string get_driver_api_version(const std::shared_ptr& s) { + auto driver_api_version = s->get_scap_api_version(); + unsigned long driver_api_major = PPM_API_VERSION_MAJOR(driver_api_version); + unsigned long driver_api_minor = PPM_API_VERSION_MINOR(driver_api_version); + unsigned long driver_api_patch = PPM_API_VERSION_PATCH(driver_api_version); - char driver_api_version_string[32]; - snprintf(driver_api_version_string, sizeof(driver_api_version_string), "%lu.%lu.%lu", driver_api_major, driver_api_minor, driver_api_patch); - return std::string(driver_api_version_string); + char driver_api_version_string[32]; + snprintf(driver_api_version_string, + sizeof(driver_api_version_string), + "%lu.%lu.%lu", + driver_api_major, + driver_api_minor, + driver_api_patch); + return std::string(driver_api_version_string); } // todo: move string conversion to scap -static inline std::string get_driver_schema_version(const std::shared_ptr& s) -{ - auto driver_schema_version = s->get_scap_schema_version(); - unsigned long driver_schema_major = PPM_API_VERSION_MAJOR(driver_schema_version); - unsigned long driver_schema_minor = PPM_API_VERSION_MINOR(driver_schema_version); - unsigned long driver_schema_patch = PPM_API_VERSION_PATCH(driver_schema_version); +static inline std::string get_driver_schema_version(const std::shared_ptr& s) { + auto driver_schema_version = s->get_scap_schema_version(); + unsigned long driver_schema_major = PPM_API_VERSION_MAJOR(driver_schema_version); + unsigned long driver_schema_minor = PPM_API_VERSION_MINOR(driver_schema_version); + unsigned long driver_schema_patch = PPM_API_VERSION_PATCH(driver_schema_version); - char driver_schema_version_string[32]; - snprintf(driver_schema_version_string, sizeof(driver_schema_version_string), "%lu.%lu.%lu", driver_schema_major, driver_schema_minor, driver_schema_patch); - return std::string(driver_schema_version_string); + char driver_schema_version_string[32]; + snprintf(driver_schema_version_string, + sizeof(driver_schema_version_string), + "%lu.%lu.%lu", + driver_schema_major, + driver_schema_minor, + driver_schema_patch); + return std::string(driver_schema_version_string); } -falco::versions_info::versions_info(const std::shared_ptr& inspector) - : plugin_api_version(inspector->get_plugin_api_version()) - , driver_api_version(get_driver_api_version(inspector)) - , driver_schema_version(get_driver_schema_version(inspector)) -{ - for (const auto &p : inspector->get_plugin_manager()->plugins()) - { - plugin_versions[p->name()] = p->plugin_version().as_string(); - } +falco::versions_info::versions_info(const std::shared_ptr& inspector): + plugin_api_version(inspector->get_plugin_api_version()), + driver_api_version(get_driver_api_version(inspector)), + driver_schema_version(get_driver_schema_version(inspector)) { + for(const auto& p : inspector->get_plugin_manager()->plugins()) { + plugin_versions[p->name()] = p->plugin_version().as_string(); + } } -nlohmann::json falco::versions_info::as_json() const -{ - nlohmann::json version_info; - version_info["falco_version"] = falco_version; - version_info["libs_version"] = libs_version; - version_info["plugin_api_version"] = plugin_api_version; - version_info["driver_api_version"] = driver_api_version; - version_info["driver_schema_version"] = driver_schema_version; - version_info["default_driver_version"] = default_driver_version; - // note: the 'engine_version' key below must be removed in the next major bump (0.x.y -> 1.0.0) - // the two keys are kept for existing tooling that relies on the old key - // (falcoctl will match old rules artifacts configs by using this key, and the new ones using - // the engine_version_semver key) - version_info["engine_version"] = std::to_string(FALCO_ENGINE_VERSION_MINOR); - version_info["engine_version_semver"] = engine_version; - for (const auto& pv : plugin_versions) - { - version_info["plugin_versions"][pv.first] = pv.second; - } - return version_info; +nlohmann::json falco::versions_info::as_json() const { + nlohmann::json version_info; + version_info["falco_version"] = falco_version; + version_info["libs_version"] = libs_version; + version_info["plugin_api_version"] = plugin_api_version; + version_info["driver_api_version"] = driver_api_version; + version_info["driver_schema_version"] = driver_schema_version; + version_info["default_driver_version"] = default_driver_version; + // note: the 'engine_version' key below must be removed in the next major bump (0.x.y -> 1.0.0) + // the two keys are kept for existing tooling that relies on the old key + // (falcoctl will match old rules artifacts configs by using this key, and the new ones using + // the engine_version_semver key) + version_info["engine_version"] = std::to_string(FALCO_ENGINE_VERSION_MINOR); + version_info["engine_version_semver"] = engine_version; + for(const auto& pv : plugin_versions) { + version_info["plugin_versions"][pv.first] = pv.second; + } + return version_info; } diff --git a/userspace/falco/versions_info.h b/userspace/falco/versions_info.h index a826bd839cf..6c588c3a19c 100644 --- a/userspace/falco/versions_info.h +++ b/userspace/falco/versions_info.h @@ -26,35 +26,33 @@ limitations under the License. #include "config_falco.h" #include "falco_engine_version.h" -namespace falco -{ - /** - * @brief Container for the version of Falco components - */ - struct versions_info - { - /** - * @brief Construct a versions info by using an inspector to obtain - * versions about the drivers and the loaded plugins. - */ - explicit versions_info(const std::shared_ptr& inspector); - versions_info(versions_info&&) = default; - versions_info& operator = (versions_info&&) = default; - versions_info(const versions_info& s) = default; - versions_info& operator = (const versions_info& s) = default; - - /** - * @brief Encode the versions info as a JSON object - */ - nlohmann::json as_json() const; - - std::string falco_version = FALCO_VERSION; - std::string engine_version = FALCO_ENGINE_VERSION; - std::string libs_version = FALCOSECURITY_LIBS_VERSION; - std::string plugin_api_version; - std::string driver_api_version; - std::string driver_schema_version; - std::string default_driver_version = DRIVER_VERSION; - std::unordered_map plugin_versions; - }; +namespace falco { +/** + * @brief Container for the version of Falco components + */ +struct versions_info { + /** + * @brief Construct a versions info by using an inspector to obtain + * versions about the drivers and the loaded plugins. + */ + explicit versions_info(const std::shared_ptr& inspector); + versions_info(versions_info&&) = default; + versions_info& operator=(versions_info&&) = default; + versions_info(const versions_info& s) = default; + versions_info& operator=(const versions_info& s) = default; + + /** + * @brief Encode the versions info as a JSON object + */ + nlohmann::json as_json() const; + + std::string falco_version = FALCO_VERSION; + std::string engine_version = FALCO_ENGINE_VERSION; + std::string libs_version = FALCOSECURITY_LIBS_VERSION; + std::string plugin_api_version; + std::string driver_api_version; + std::string driver_schema_version; + std::string default_driver_version = DRIVER_VERSION; + std::unordered_map plugin_versions; }; +}; // namespace falco diff --git a/userspace/falco/watchdog.h b/userspace/falco/watchdog.h index 4527c4a4efc..12293649dab 100644 --- a/userspace/falco/watchdog.h +++ b/userspace/falco/watchdog.h @@ -21,38 +21,27 @@ limitations under the License. #include template -class watchdog -{ +class watchdog { public: - watchdog(): - m_timeout(nullptr), - m_is_running(false) - { - } + watchdog(): m_timeout(nullptr), m_is_running(false) {} - ~watchdog() - { - stop(); - } + ~watchdog() { stop(); } void start(std::function cb, - std::chrono::milliseconds resolution = std::chrono::milliseconds(100)) - { + std::chrono::milliseconds resolution = std::chrono::milliseconds(100)) { stop(); m_is_running.store(true, std::memory_order_release); m_thread = std::thread([this, cb, resolution]() { const auto no_deadline = time_point{}; timeout_data curr; - while(m_is_running.load(std::memory_order_acquire)) - { + while(m_is_running.load(std::memory_order_acquire)) { auto t = m_timeout.exchange(nullptr, std::memory_order_release); - if(t) - { + if(t) { curr = *t; delete t; } - if(curr.deadline != no_deadline && curr.deadline < std::chrono::steady_clock::now()) - { + if(curr.deadline != no_deadline && + curr.deadline < std::chrono::steady_clock::now()) { cb(curr.payload); curr.deadline = no_deadline; } @@ -61,33 +50,29 @@ class watchdog }); } - void stop() - { - if(m_is_running.load(std::memory_order_acquire)) - { + void stop() { + if(m_is_running.load(std::memory_order_acquire)) { m_is_running.store(false, std::memory_order_release); - if(m_thread.joinable()) - { + if(m_thread.joinable()) { m_thread.join(); } delete m_timeout.exchange(nullptr, std::memory_order_release); } } - inline void set_timeout(std::chrono::milliseconds timeout, _T payload) noexcept - { - delete m_timeout.exchange(new timeout_data{std::chrono::steady_clock::now() + timeout, payload}, std::memory_order_release); + inline void set_timeout(std::chrono::milliseconds timeout, _T payload) noexcept { + delete m_timeout.exchange( + new timeout_data{std::chrono::steady_clock::now() + timeout, payload}, + std::memory_order_release); } - inline void cancel_timeout() noexcept - { + inline void cancel_timeout() noexcept { delete m_timeout.exchange(new timeout_data, std::memory_order_release); } private: typedef std::chrono::time_point time_point; - struct timeout_data - { + struct timeout_data { time_point deadline; _T payload; }; diff --git a/userspace/falco/webserver.cpp b/userspace/falco/webserver.cpp index c9bfde6e27a..c08f02687ce 100644 --- a/userspace/falco/webserver.cpp +++ b/userspace/falco/webserver.cpp @@ -22,107 +22,87 @@ limitations under the License. #include "versions_info.h" #include -falco_webserver::~falco_webserver() -{ - stop(); +falco_webserver::~falco_webserver() { + stop(); } -void falco_webserver::start( - const falco::app::state& state, - const falco_configuration::webserver_config& webserver_config) -{ - if (m_running) - { - throw falco_exception( - "attempted restarting webserver without stopping it first"); - } +void falco_webserver::start(const falco::app::state &state, + const falco_configuration::webserver_config &webserver_config) { + if(m_running) { + throw falco_exception("attempted restarting webserver without stopping it first"); + } - // allocate and configure server - if (webserver_config.m_ssl_enabled) - { - m_server = std::make_unique( - webserver_config.m_ssl_certificate.c_str(), - webserver_config.m_ssl_certificate.c_str()); - } - else - { - m_server = std::make_unique(); - } + // allocate and configure server + if(webserver_config.m_ssl_enabled) { + m_server = std::make_unique(webserver_config.m_ssl_certificate.c_str(), + webserver_config.m_ssl_certificate.c_str()); + } else { + m_server = std::make_unique(); + } - // configure server - m_server->new_task_queue = [webserver_config] { return new httplib::ThreadPool(webserver_config.m_threadiness); }; + // configure server + m_server->new_task_queue = [webserver_config] { + return new httplib::ThreadPool(webserver_config.m_threadiness); + }; - // setup healthz endpoint - m_server->Get(webserver_config.m_k8s_healthz_endpoint, - [](const httplib::Request &, httplib::Response &res) { - res.set_content("{\"status\": \"ok\"}", "application/json"); - }); + // setup healthz endpoint + m_server->Get(webserver_config.m_k8s_healthz_endpoint, + [](const httplib::Request &, httplib::Response &res) { + res.set_content("{\"status\": \"ok\"}", "application/json"); + }); - // setup versions endpoint - const auto versions_json_str = falco::versions_info(state.offline_inspector).as_json().dump(); - m_server->Get("/versions", - [versions_json_str](const httplib::Request &, httplib::Response &res) { - res.set_content(versions_json_str, "application/json"); - }); + // setup versions endpoint + const auto versions_json_str = falco::versions_info(state.offline_inspector).as_json().dump(); + m_server->Get("/versions", + [versions_json_str](const httplib::Request &, httplib::Response &res) { + res.set_content(versions_json_str, "application/json"); + }); - if (state.config->m_metrics_enabled && webserver_config.m_prometheus_metrics_enabled) - { - m_server->Get("/metrics", - [&state](const httplib::Request &, httplib::Response &res) { - res.set_content(falco_metrics::to_text(state), falco_metrics::content_type); - }); - } - // run server in a separate thread - if (!m_server->is_valid()) - { - m_server = nullptr; - throw falco_exception("invalid webserver configuration"); - } + if(state.config->m_metrics_enabled && webserver_config.m_prometheus_metrics_enabled) { + m_server->Get("/metrics", [&state](const httplib::Request &, httplib::Response &res) { + res.set_content(falco_metrics::to_text(state), falco_metrics::content_type); + }); + } + // run server in a separate thread + if(!m_server->is_valid()) { + m_server = nullptr; + throw falco_exception("invalid webserver configuration"); + } - std::atomic failed; - failed.store(false, std::memory_order_release); - m_server_thread = std::thread([this, webserver_config, &failed] - { - try - { - this->m_server->listen(webserver_config.m_listen_address, webserver_config.m_listen_port); - } - catch(std::exception &e) - { - falco_logger::log( - falco_logger::level::ERR, - "falco_webserver: " + std::string(e.what()) + "\n"); - } - failed.store(true, std::memory_order_release); - }); + std::atomic failed; + failed.store(false, std::memory_order_release); + m_server_thread = std::thread([this, webserver_config, &failed] { + try { + this->m_server->listen(webserver_config.m_listen_address, + webserver_config.m_listen_port); + } catch(std::exception &e) { + falco_logger::log(falco_logger::level::ERR, + "falco_webserver: " + std::string(e.what()) + "\n"); + } + failed.store(true, std::memory_order_release); + }); - // wait for the server to actually start up - // note: is_running() is atomic - while (!m_server->is_running() && !failed.load(std::memory_order_acquire)) - { - std::this_thread::yield(); - } - m_running = true; - if (failed.load(std::memory_order_acquire)) - { - stop(); - throw falco_exception("an error occurred while starting webserver"); - } + // wait for the server to actually start up + // note: is_running() is atomic + while(!m_server->is_running() && !failed.load(std::memory_order_acquire)) { + std::this_thread::yield(); + } + m_running = true; + if(failed.load(std::memory_order_acquire)) { + stop(); + throw falco_exception("an error occurred while starting webserver"); + } } -void falco_webserver::stop() -{ - if (m_running) - { - if (m_server != nullptr) - { - m_server->stop(); - } - if(m_server_thread.joinable()) - { - m_server_thread.join(); - } - m_server = nullptr; - m_running = false; - } +void falco_webserver::stop() { + if(m_running) { + if(m_server != nullptr) { + m_server->stop(); + } + if(m_server_thread.joinable()) { + m_server_thread.join(); + } + m_server = nullptr; + m_running = false; + } } diff --git a/userspace/falco/webserver.h b/userspace/falco/webserver.h index 47834778678..8e3b4ba215e 100644 --- a/userspace/falco/webserver.h +++ b/userspace/falco/webserver.h @@ -26,21 +26,19 @@ limitations under the License. #include namespace falco::app { - struct state; +struct state; } -class falco_webserver -{ +class falco_webserver { public: falco_webserver() = default; virtual ~falco_webserver(); falco_webserver(falco_webserver&&) = default; - falco_webserver& operator = (falco_webserver&&) = default; + falco_webserver& operator=(falco_webserver&&) = default; falco_webserver(const falco_webserver&) = delete; - falco_webserver& operator = (const falco_webserver&) = delete; - virtual void start( - const falco::app::state& state, - const falco_configuration::webserver_config& webserver_config); + falco_webserver& operator=(const falco_webserver&) = delete; + virtual void start(const falco::app::state& state, + const falco_configuration::webserver_config& webserver_config); virtual void stop(); private: From b1ded2442c6949301217b8e6a4b5bd176ca6e1db Mon Sep 17 00:00:00 2001 From: Luca Guerra Date: Mon, 30 Sep 2024 11:33:38 +0000 Subject: [PATCH 3/4] cleanup(falco): ignore lint commit Signed-off-by: Luca Guerra --- .git-blame-ignore-revs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index df0ba12c4ec..ab45fc1d6f0 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1 +1,2 @@ -# Add here new files to ignore +# This commit formatted the Falco code for the first time. +50b98b30e588eadce641136da85bc94a60eb6a3d \ No newline at end of file From 25d349116d2fcb094b8c85e2c814e7ef9cff3731 Mon Sep 17 00:00:00 2001 From: Luca Guerra Date: Mon, 30 Sep 2024 11:20:22 +0000 Subject: [PATCH 4/4] fix(falco): allow disable_cri_async from both CLI and config Signed-off-by: Luca Guerra --- userspace/falco/app/actions/init_inspectors.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/userspace/falco/app/actions/init_inspectors.cpp b/userspace/falco/app/actions/init_inspectors.cpp index ab767f67410..cf3e3849d6c 100644 --- a/userspace/falco/app/actions/init_inspectors.cpp +++ b/userspace/falco/app/actions/init_inspectors.cpp @@ -67,7 +67,14 @@ static void init_syscall_inspector(falco::app::state& s, std::shared_ptr "Enabled container runtime socket at '" + p + "' via config file"); } } - inspector->set_cri_async(!s.config->m_container_engines_disable_cri_async); + + bool disable_cri_async = + s.config->m_container_engines_disable_cri_async || s.options.disable_cri_async; + inspector->set_cri_async(!disable_cri_async); + + if(disable_cri_async) { + falco_logger::log(falco_logger::level::DEBUG, "Disabling async lookups for 'CRI'"); + } // Container engines configs via CLI args // If required, set the CRI paths @@ -79,13 +86,6 @@ static void init_syscall_inspector(falco::app::state& s, std::shared_ptr } } - // Decide whether to do sync or async for CRI metadata fetch - inspector->set_cri_async(!s.options.disable_cri_async); - - if(s.options.disable_cri_async || s.config->m_container_engines_disable_cri_async) { - falco_logger::log(falco_logger::level::DEBUG, "Disabling async lookups for 'CRI'"); - } - // // If required, set the snaplen //