Compare commits

...

28 Commits

Author SHA1 Message Date
Federico Di Pierro
b0d3bef3e5 update(changelog): updated changelog for 0.39.2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-11-21 12:51:22 +01:00
Federico Di Pierro
89a024bfdf update(cmake): bumped falcoctl to v0.10.1.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-11-21 10:56:21 +01:00
Luca Guerra
3bc95a290a update(ci): replace aarch64 actuated runners with oracle
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-11-21 10:56:21 +01:00
Federico Di Pierro
c20907332d chore(cmake): bump libs to 0.18.2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-11-21 10:56:21 +01:00
Federico Di Pierro
2804d60bd2 update(changelog): updated changelog for 0.39.1.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-10-08 12:54:09 +02:00
Luca Guerra
7c8209ed8e update(tests): add tests for plugin init_config
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-10-08 12:54:09 +02:00
Luca Guerra
3c4b315ff2 fix(engine): allow null init_config for plugin info
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-10-08 12:54:09 +02:00
Luca Guerra
92d6c4bab6 fix(engine): disable comma separated vectors in cxxopts
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-10-08 12:54:09 +02:00
Federico Di Pierro
51a19ea6cb fix(userspace/falco): fix event set selection for plugin with parsing capability.
In live mode we need to use the source_info inspectors instead of the offline inspector.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-10-08 12:54:09 +02:00
Aldo Lacuku
88d73505b0 update(changelog): add changelog for falco 0.39.0
Signed-off-by: Aldo Lacuku <aldo@lacuku.eu>
2024-10-01 09:58:36 +02:00
Luca Guerra
f2d23af415 fix(falco): allow disable_cri_async from both CLI and config
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-09-30 16:10:32 +02:00
Luca Guerra
10f87e515e cleanup(falco): ignore lint commit
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-09-30 16:10:32 +02:00
Poiana
82016080d0 chore(falco): apply code formatting
Signed-off-by: Poiana <poiana.bot@gmail.com>
2024-09-30 16:10:32 +02:00
Andrea Terzolo
bbb4d6e9b6 update: ignore_some_files
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-09-30 16:10:32 +02:00
Leonardo Di Giovanna
e34507c739 feat(stats): add host_netinfo networking information stats family
Introduce host_netinfo stats family to hold information regarding host
networking. At the moment, it only provides ipv4 and ipv6 addresses
list for each interface available on the host. The naming schema for
the introduced stats is
falco.host_netinfo.interfaces.<ifname>.protocols.<ipv4|ipv6>.addresses.

Signed-off-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
2024-09-27 11:56:20 +02:00
Luca Guerra
ff32882a7f chore(build): update libs to 0.18.1
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-09-26 08:18:14 +02:00
Luca Guerra
f1b208f8fb fix(engine): sync outputs before printing stats at shutdown
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-09-24 10:15:05 +02:00
Leonardo Di Giovanna
ff65dc75ae cleanup(falco_metrics): remove unused falco_utils import
Signed-off-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
2024-09-24 10:15:05 +02:00
Leonardo Di Giovanna
a1ff7c7384 fix(falco_metrics): remove ifinfo_json stat/metric
Using JSON as value prevents any meaningful aggregation for the stats.
Splitting these information into multiple labels can drastically
increase the number of dimensions, as the number of interfaces and
addresses can be high in some environment. Moreover, these information
are not currently refreshed, even if they can frequently change. Given
these reasons, remove ifinfo_json from stats and metrics.

Signed-off-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
2024-09-24 10:15:05 +02:00
Leonardo Di Giovanna
fb47e816ae fix(falco_metrics)!: use full name for configs and rules files
Signed-off-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
2024-09-24 10:15:05 +02:00
Leonardo Di Giovanna
39dfd6765a fix(falco_metrics)!: split tags label into multiple tag_ labels
Signed-off-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
2024-09-24 10:15:05 +02:00
Luca Guerra
f4477f1ac2 update(tests): add test for plugin init_config map
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-09-24 10:15:05 +02:00
Luca Guerra
92fa3b5347 fix(falco): allow plugin init_config map in json schema
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-09-24 10:15:05 +02:00
Federico Di Pierro
fad91ea080 fix(userspace/falco): properly account for plugin with CAP_PARSING when computing interesting sc set.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-09-24 10:15:05 +02:00
Leonardo Di Giovanna
5e9a8fd665 update(systemd): add falco.service alias to all systemd units
Signed-off-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
2024-09-24 10:15:05 +02:00
Federico Di Pierro
241f620956 update(cmake): bump libs to 0.18.0 and driver to 7.3.0+driver.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-09-18 11:11:52 +02:00
Federico Di Pierro
80816e67d6 chore(userspace/falco): deprecate cri related CLI options.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-09-18 11:11:52 +02:00
Federico Di Pierro
5874dc1f95 fix(userspace/engine): improve rule json schema to account for source and required_plugin_versions.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-09-18 11:11:52 +02:00
181 changed files with 9031 additions and 9589 deletions

View File

@@ -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

View File

@@ -1 +1,2 @@
# Add here new files to ignore
# This commit formatted the Falco code for the first time.
50b98b30e588eadce641136da85bc94a60eb6a3d

View File

@@ -39,7 +39,7 @@ permissions:
jobs:
build-and-test:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-22.04' }}
runs-on: ${{ (inputs.arch == 'aarch64' && 'oracle-aarch64-4cpu-16gb') || 'ubuntu-22.04' }}
outputs:
cmdout: ${{ steps.run_cmd.outputs.out }}
steps:

View File

@@ -31,7 +31,7 @@ permissions:
jobs:
build-docker:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-latest' }}
runs-on: ${{ (inputs.arch == 'aarch64' && 'oracle-aarch64-4cpu-16gb') || 'ubuntu-latest' }}
env:
TARGETARCH: ${{ (inputs.arch == 'aarch64' && 'arm64') || 'amd64' }}
steps:

View File

@@ -27,7 +27,7 @@ permissions:
jobs:
build-modern-bpf-skeleton:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-latest' }}
runs-on: ${{ (inputs.arch == 'aarch64' && 'oracle-aarch64-4cpu-16gb') || 'ubuntu-latest' }}
container: fedora:latest
steps:
# Always install deps before invoking checkout action, to properly perform a full clone.
@@ -55,7 +55,7 @@ jobs:
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-latest' }}
runs-on: ${{ (inputs.arch == 'aarch64' && 'oracle-aarch64-4cpu-16gb') || 'ubuntu-latest' }}
needs: [build-modern-bpf-skeleton]
container: centos:7
steps:

View File

@@ -27,7 +27,7 @@ permissions:
jobs:
test-packages:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-latest' }}
runs-on: ${{ (inputs.arch == 'aarch64' && 'oracle-aarch64-4cpu-16gb') || 'ubuntu-latest' }}
steps:
- name: Download binary
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2

View File

@@ -1,5 +1,136 @@
# Change Log
## v0.39.2
Released on 2024-11-21
### Minor Changes
* update(cmake): bumped falcoctl to v0.10.1. [[#3408](https://github.com/falcosecurity/falco/pull/3408)] - [@FedeDP](https://github.com/FedeDP)
* update(cmake): bump yaml-cpp to latest master. [[#3394](https://github.com/falcosecurity/falco/pull/3394)] - [@FedeDP](https://github.com/FedeDP)
### Non user-facing changes
* update(ci): use arm64 CNCF runners for GH actions [[#3386](https://github.com/falcosecurity/falco/pull/3386)] - [@LucaGuerra](https://github.com/LucaGuerra)
### Statistics
| MERGED PRS | NUMBER |
|-----------------|--------|
| Not user-facing | 1 |
| Release note | 2 |
| Total | 3 |
## v0.39.1
Released on 2024-10-09
### Bug Fixes
* fix(engine): allow null init_config for plugin info [[#3372](https://github.com/falcosecurity/falco/pull/3372)] - [@LucaGuerra](https://github.com/LucaGuerra)
* fix(engine): fix parsing issues in -o key={object} when the object definition contains a comma [[#3363](https://github.com/falcosecurity/falco/pull/3363)] - [@LucaGuerra](https://github.com/LucaGuerra)
* fix(userspace/falco): fix event set selection for plugin with parsing capability [[#3368](https://github.com/falcosecurity/falco/pull/3368)] - [@FedeDP](https://github.com/FedeDP)
### Statistics
| MERGED PRS | NUMBER |
|-----------------|--------|
| Not user-facing | 0 |
| Release note | 3 |
| Total | 3 |
## v0.39.0
Released on 2024-10-01
### Breaking Changes :warning:
* fix(falco_metrics)!: split tags label into multiple `tag_`-prefixed labels [[#3337](https://github.com/falcosecurity/falco/pull/3337)] - [@ekoops](https://github.com/ekoops)
* fix(falco_metrics)!: use full name for configs and rules files [[#3337](https://github.com/falcosecurity/falco/pull/3337)] - [@ekoops](https://github.com/ekoops)
* update(falco_metrics)!: rearrange `n_evts_cpu` and `n_drops_cpu` Prometheus metrics to follow best practices [[#3319](https://github.com/falcosecurity/falco/pull/3319)] - [@incertum](https://github.com/incertum)
* cleanup(userspace/falco)!: drop deprecated -t,-T,-D options. [[#3311](https://github.com/falcosecurity/falco/pull/3311)] - [@FedeDP](https://github.com/FedeDP)
### Major Changes
* feat(stats): add host_netinfo networking information stats family [[#3344](https://github.com/falcosecurity/falco/pull/3344)] - [@ekoops](https://github.com/ekoops)
* new(falco): add json_include_message_property to have a message field without date and priority [[#3314](https://github.com/falcosecurity/falco/pull/3314)] - [@LucaGuerra](https://github.com/LucaGuerra)
* new(userspace/falco,userspace/engine): rule json schema validation [[#3313](https://github.com/falcosecurity/falco/pull/3313)] - [@FedeDP](https://github.com/FedeDP)
* new(falco): introduce append_output configuration [[#3308](https://github.com/falcosecurity/falco/pull/3308)] - [@LucaGuerra](https://github.com/LucaGuerra)
* new(userspace/falco): added --config-schema action to print config schema [[#3312](https://github.com/falcosecurity/falco/pull/3312)] - [@FedeDP](https://github.com/FedeDP)
* new(falco): enable CLI options with -o key={object} [[#3310](https://github.com/falcosecurity/falco/pull/3310)] - [@LucaGuerra](https://github.com/LucaGuerra)
* new(config): add `container_engines` config to falco.yaml [[#3266](https://github.com/falcosecurity/falco/pull/3266)] - [@incertum](https://github.com/incertum)
* new(metrics): add host_ifinfo metric [[#3253](https://github.com/falcosecurity/falco/pull/3253)] - [@incertum](https://github.com/incertum)
* new(userspace,unit_tests): validate configs against schema [[#3302](https://github.com/falcosecurity/falco/pull/3302)] - [@FedeDP](https://github.com/FedeDP)
### Minor Changes
* update(falco): upgrade libs to 0.18.1 [[#3349](https://github.com/falcosecurity/falco/pull/3349)] - [@LucaGuerra](https://github.com/LucaGuerra)
* update(systemd): users can refer to systemd falco services with a consistent unique alias falco.service [[#3332](https://github.com/falcosecurity/falco/pull/3332)] - [@ekoops](https://github.com/ekoops)
* update(cmake): bump libs to 0.18.0 and driver to 7.3.0+driver. [[#3330](https://github.com/falcosecurity/falco/pull/3330)] - [@FedeDP](https://github.com/FedeDP)
* chore(userspace/falco): deprecate `cri` related CLI options. [[#3329](https://github.com/falcosecurity/falco/pull/3329)] - [@FedeDP](https://github.com/FedeDP)
* update(cmake): bumped falcoctl to v0.10.0 and rules to 3.2.0 [[#3327](https://github.com/falcosecurity/falco/pull/3327)] - [@FedeDP](https://github.com/FedeDP)
* update(falco_metrics): change prometheus rules metric naming [[#3324](https://github.com/falcosecurity/falco/pull/3324)] - [@incertum](https://github.com/incertum)
### Bug Fixes
* fix(falco): allow disable_cri_async from both CLI and config [[#3353](https://github.com/falcosecurity/falco/pull/3353)] - [@LucaGuerra](https://github.com/LucaGuerra)
* fix(engine): sync outputs before printing stats at shutdown [[#3338](https://github.com/falcosecurity/falco/pull/3338)] - [@LucaGuerra](https://github.com/LucaGuerra)
* fix(falco): allow plugin init_config map in json schema [[#3335](https://github.com/falcosecurity/falco/pull/3335)] - [@LucaGuerra](https://github.com/LucaGuerra)
* fix(userspace/falco): properly account for plugin with CAP_PARSING when computing interesting sc set [[#3334](https://github.com/falcosecurity/falco/pull/3334)] - [@FedeDP](https://github.com/FedeDP)
### Non user-facing changes
* feat(cmake): add conditional builds for falcoctl and rules paths [[#3305](https://github.com/falcosecurity/falco/pull/3305)] - [@tembleking](https://github.com/tembleking)
* cleanup(falco): ignore lint commit [[#3354](https://github.com/falcosecurity/falco/pull/3354)] - [@LucaGuerra](https://github.com/LucaGuerra)
* chore(falco): apply code formatting [[#3350](https://github.com/falcosecurity/falco/pull/3350)] - [@poiana](https://github.com/poiana)
* chore: ignore_some_files for clang format [[#3351](https://github.com/falcosecurity/falco/pull/3351)] - [@Andreagit97](https://github.com/Andreagit97)
* sync: release 0.39.x [[#3340](https://github.com/falcosecurity/falco/pull/3340)] - [@FedeDP](https://github.com/FedeDP)
* fix(userspace/engine): improve rule json schema to account for `source` and `required_plugin_versions` [[#3328](https://github.com/falcosecurity/falco/pull/3328)] - [@FedeDP](https://github.com/FedeDP)
* cleanup(falco): use header file for json schema [[#3325](https://github.com/falcosecurity/falco/pull/3325)] - [@LucaGuerra](https://github.com/LucaGuerra)
* update(engine): modify append_output format [[#3322](https://github.com/falcosecurity/falco/pull/3322)] - [@LucaGuerra](https://github.com/LucaGuerra)
* chore: scaffolding for enabling code formatting [[#3321](https://github.com/falcosecurity/falco/pull/3321)] - [@Andreagit97](https://github.com/Andreagit97)
* update(cmake): bump libs and driver to 0.18.0-rc1. [[#3320](https://github.com/falcosecurity/falco/pull/3320)] - [@FedeDP](https://github.com/FedeDP)
* fix(ci): restore master and release CI workflow permissions. [[#3317](https://github.com/falcosecurity/falco/pull/3317)] - [@FedeDP](https://github.com/FedeDP)
* fixed the token-permission and pinned-dependencies issue [[#3299](https://github.com/falcosecurity/falco/pull/3299)] - [@harshitasao](https://github.com/harshitasao)
* update(cmake): bump falcoctl to v0.10.0-rc1 [[#3316](https://github.com/falcosecurity/falco/pull/3316)] - [@alacuku](https://github.com/alacuku)
* ci(insecure-api): update semgrep docker image [[#3315](https://github.com/falcosecurity/falco/pull/3315)] - [@francesco-furlan](https://github.com/francesco-furlan)
* Add demo environment instructions and docker-config files [[#3295](https://github.com/falcosecurity/falco/pull/3295)] - [@bbl232](https://github.com/bbl232)
* chore(deps): Bump submodules/falcosecurity-rules from `baecf18` to `b6ad373` [[#3301](https://github.com/falcosecurity/falco/pull/3301)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* update(cmake): bump libs and driver to latest master [[#3283](https://github.com/falcosecurity/falco/pull/3283)] - [@jasondellaluce](https://github.com/jasondellaluce)
* chore(deps): Bump submodules/falcosecurity-rules from `342b20d` to `baecf18` [[#3298](https://github.com/falcosecurity/falco/pull/3298)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* chore(deps): Bump submodules/falcosecurity-rules from `068f0f2` to `342b20d` [[#3288](https://github.com/falcosecurity/falco/pull/3288)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* vote: add sgaist to OWNERS [[#3264](https://github.com/falcosecurity/falco/pull/3264)] - [@sgaist](https://github.com/sgaist)
* Add Tulip Retail to adopters list [[#3291](https://github.com/falcosecurity/falco/pull/3291)] - [@bbl232](https://github.com/bbl232)
* chore(deps): Bump submodules/falcosecurity-rules from `28b98b6` to `068f0f2` [[#3282](https://github.com/falcosecurity/falco/pull/3282)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* chore(deps): Bump submodules/falcosecurity-rules from `c0a9bf1` to `28b98b6` [[#3267](https://github.com/falcosecurity/falco/pull/3267)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* Added the OpenSSF Scorecard Badge [[#3250](https://github.com/falcosecurity/falco/pull/3250)] - [@harshitasao](https://github.com/harshitasao)
* chore(deps): Bump submodules/falcosecurity-rules from `ea57e78` to `c0a9bf1` [[#3247](https://github.com/falcosecurity/falco/pull/3247)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* update(cmake,userspace): bump libs and driver to latest master. [[#3263](https://github.com/falcosecurity/falco/pull/3263)] - [@FedeDP](https://github.com/FedeDP)
* If rule compilation fails, return immediately [[#3260](https://github.com/falcosecurity/falco/pull/3260)] - [@mstemm](https://github.com/mstemm)
* new(userspace/engine): generalize indexable ruleset [[#3251](https://github.com/falcosecurity/falco/pull/3251)] - [@mstemm](https://github.com/mstemm)
* update(cmake): bump libs to master. [[#3249](https://github.com/falcosecurity/falco/pull/3249)] - [@FedeDP](https://github.com/FedeDP)
* chore(deps): Bump submodules/falcosecurity-rules from `df963b6` to `ea57e78` [[#3240](https://github.com/falcosecurity/falco/pull/3240)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* chore(ci): enable dummy tests on the testing framework. [[#3233](https://github.com/falcosecurity/falco/pull/3233)] - [@FedeDP](https://github.com/FedeDP)
* chore(deps): Bump submodules/falcosecurity-rules from `679a50a` to `df963b6` [[#3231](https://github.com/falcosecurity/falco/pull/3231)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* update(cmake): bump libs and driver to master. [[#3225](https://github.com/falcosecurity/falco/pull/3225)] - [@FedeDP](https://github.com/FedeDP)
* chore(deps): Bump submodules/falcosecurity-rules from `9e56293` to `679a50a` [[#3222](https://github.com/falcosecurity/falco/pull/3222)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* update(docs): update CHANGELOG for 0.38.0 (master branch) [[#3224](https://github.com/falcosecurity/falco/pull/3224)] - [@LucaGuerra](https://github.com/LucaGuerra)
### Statistics
| MERGED PRS | NUMBER |
|-----------------|--------|
| Not user-facing | 35 |
| Release note | 22 |
| Total | 57 |
## v0.38.2
Released on 2024-08-19

View File

@@ -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 $<TARGET_PROPERTY:falco,SOURCES> COMMENT "Formatting ..." VERBATIM)
# Clang format add_custom_target(format COMMAND clang-format --style=file -i
# $<TARGET_PROPERTY:falco,SOURCES> 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()

View File

@@ -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")

View File

@@ -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)

View File

@@ -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$<$<CONFIG:Debug>: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")

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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/* ."
)

View File

@@ -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 (<org name>/<repo 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=<your-gh-handle>/libs ..`
if (NOT DRIVER_REPO)
set(DRIVER_REPO "falcosecurity/libs")
endif()
# DRIVER_REPO accepts a repository name (<org name>/<repo 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=<your-gh-handle>/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 "0.18.0-rc2")
set(DRIVER_CHECKSUM "SHA256=e016ee1113eb5a14c85d9c4828244f5fba37cd663ecd38f5b58fbc4142348782")
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})
# 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")
# 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)

View File

@@ -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}")

View File

@@ -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)
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} FALCOCTL_SYSTEM_NAME)
set(FALCOCTL_VERSION "0.10.0")
set(FALCOCTL_VERSION "0.10.1")
message(STATUS "Building with falcoctl: ${FALCOCTL_VERSION}")
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()
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(FALCOCTL_SYSTEM_PROC_GO "amd64")
set(FALCOCTL_HASH "039961004a72d27409ab6ba82542134bd5df8a69ad341c897f3d26b6596b9e6a")
else() # aarch64
set(FALCOCTL_SYSTEM_PROC_GO "arm64")
set(FALCOCTL_HASH "fbaf83512cc73e99f14f90cb14ed4eee83f40efde3d398c7b7ef02163116f2fc")
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 "")
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}")
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()

View File

@@ -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 ""
)

View File

@@ -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 (<org name>/<repo 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=<your-gh-handle>/libs ..`
if (NOT FALCOSECURITY_LIBS_REPO)
set(FALCOSECURITY_LIBS_REPO "falcosecurity/libs")
endif()
# FALCOSECURITY_LIBS_REPO accepts a repository name (<org name>/<repo 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=<your-gh-handle>/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.0-rc2")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=e016ee1113eb5a14c85d9c4828244f5fba37cd663ecd38f5b58fbc4142348782")
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.2")
set(FALCOSECURITY_LIBS_CHECKSUM
"SHA256=b2e3e42c3255a6d41960afe086e8189d73e27f1dbc23abefaf6b05cf118eb6f4"
)
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})
# 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")
# 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(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(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)

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View File

@@ -24,3 +24,4 @@ StandardOutput=null
[Install]
WantedBy=multi-user.target
Alias=falco.service

View File

@@ -24,3 +24,4 @@ StandardOutput=null
[Install]
WantedBy=multi-user.target
Alias=falco.service

View File

@@ -24,3 +24,4 @@ StandardOutput=null
[Install]
WantedBy=multi-user.target
Alias=falco.service

View File

@@ -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()

View File

@@ -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<sinsp_filter_factory> 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<filter_ruleset> new_ruleset() override
{
return ruleset;
}
inline std::shared_ptr<filter_ruleset> new_ruleset() override { return ruleset; }
std::shared_ptr<filter_ruleset> 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<sinsp_filter_factory>(&inspector, filterchecks);
auto formatter_factory = std::make_shared<sinsp_evt_formatter_factory>(&inspector, filterchecks);
auto formatter_factory =
std::make_shared<sinsp_evt_formatter_factory>(&inspector, filterchecks);
auto ruleset_factory = std::make_shared<test_ruleset_factory>(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));

View File

@@ -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<std::string> 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<rule_loader::compile_output> new_compile_output() override
{
std::unique_ptr<rule_loader::compile_output> new_compile_output() override {
return std::make_unique<test_compile_output>();
}
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 @@ public:
indexed_vector<test_object_info> 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<test_collector&>(collector);
rule_loader::collector& collector,
const YAML::Node& item,
const rule_loader::context& parent) override {
test_collector& test_col = dynamic_cast<test_collector&>(collector);
if(item["test_object"].IsDefined())
{
if(item["test_object"].IsDefined()) {
rule_loader::context tmp = create_context(item, parent);
test_object_info obj;
std::string name;
@@ -113,37 +101,29 @@ protected:
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<sinsp_filter_factory> 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<filter_ruleset> ruleset;
get_engine_state().get_ruleset(source, ruleset);
EXPECT_EQ(this, ruleset.get());
const test_compile_output& test_output =
dynamic_cast<const test_compile_output&>(compile_output);
dynamic_cast<const test_compile_output&>(compile_output);
defined_properties = test_output.defined_test_properties;
};
@@ -151,40 +131,31 @@ public:
std::set<std::string> 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<sinsp_filter_factory> factory):
m_filter_factory(factory)
{
}
m_filter_factory(factory) {}
virtual ~test_ruleset_factory() = default;
inline std::shared_ptr<filter_ruleset> new_ruleset() override
{
inline std::shared_ptr<filter_ruleset> new_ruleset() override {
return std::make_shared<test_ruleset>(m_filter_factory);
}
std::shared_ptr<sinsp_filter_factory> 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<const test_collector&>(col);
const test_collector& test_col = dynamic_cast<const test_collector&>(col);
test_compile_output& test_output =
dynamic_cast<test_compile_output&>(out);
test_compile_output& test_output = dynamic_cast<test_compile_output&>(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<rule_loader::configuration> create_configuration(sinsp& inspector,
sinsp_filter_check_list& filterchecks,
indexed_vector<falco_source>& sources)
{
static std::shared_ptr<rule_loader::configuration> create_configuration(
sinsp& inspector,
sinsp_filter_check_list& filterchecks,
indexed_vector<falco_source>& sources) {
auto filter_factory = std::make_shared<sinsp_filter_factory>(&inspector, filterchecks);
auto formatter_factory = std::make_shared<sinsp_evt_formatter_factory>(&inspector, filterchecks);
auto formatter_factory =
std::make_shared<sinsp_evt_formatter_factory>(&inspector, filterchecks);
auto ruleset_factory = std::make_shared<evttype_index_ruleset_factory>(filter_factory);
falco_source syscall_source;
@@ -247,17 +219,15 @@ static std::shared_ptr<rule_loader::configuration> create_configuration(sinsp& i
sources.insert(syscall_source, syscall_source_name);
return std::make_shared<rule_loader::configuration>(content,
sources,
"test configuration");
return std::make_shared<rule_loader::configuration>(content, sources, "test configuration");
}
static void load_rules(sinsp& inspector,
sinsp_filter_check_list& filterchecks,
std::unique_ptr<rule_loader::compile_output>& compile_output,
indexed_vector<falco_source>& sources)
{
std::shared_ptr<rule_loader::configuration> cfg = create_configuration(inspector, filterchecks, sources);
sinsp_filter_check_list& filterchecks,
std::unique_ptr<rule_loader::compile_output>& compile_output,
indexed_vector<falco_source>& sources) {
std::shared_ptr<rule_loader::configuration> 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<rule_loader::compile_output> 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<rule_loader::compile_output> compile_output;
@@ -304,8 +272,8 @@ TEST(engine_loader_alt_loader, pass_compile_output_to_ruleset)
std::shared_ptr<filter_ruleset> 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<sinsp_filter_factory>(&inspector, filterchecks);
auto formatter_factory = std::make_shared<sinsp_evt_formatter_factory>(&inspector, filterchecks);
auto formatter_factory =
std::make_shared<sinsp_evt_formatter_factory>(&inspector, filterchecks);
auto ruleset_factory = std::make_shared<test_ruleset_factory>(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<filter_ruleset> ruleset = engine.ruleset_for_source(syscall_source_name);
std::set<std::string>& defined_properties = std::dynamic_pointer_cast<test_ruleset>(ruleset)->defined_properties;
std::set<std::string>& defined_properties =
std::dynamic_pointer_cast<test_ruleset>(ruleset)->defined_properties;
EXPECT_TRUE(defined_properties.find("my-value") != defined_properties.end());
EXPECT_TRUE(defined_properties.find("other-value") != defined_properties.end());

View File

@@ -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<std::string> 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<std::string> 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));
}

View File

@@ -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<std::string, std::string> 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<std::string, std::string> 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;

View File

@@ -18,8 +18,7 @@ limitations under the License.
#include <gtest/gtest.h>
#include <engine/falco_utils.h>
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("*", ""));

View File

@@ -18,33 +18,33 @@ limitations under the License.
#include <gtest/gtest.h>
#include <engine/filter_details_resolver.h>
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);
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 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 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 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());
// Assert lists
ASSERT_EQ(details.lists.size(), 1);
ASSERT_NE(details.lists.find("known_procs"), details.lists.end());
}

View File

@@ -21,33 +21,37 @@ limitations under the License.
namespace filter_ast = libsinsp::filter::ast;
static std::vector<filter_macro_resolver::value_info>::const_iterator find_value(
const std::vector<filter_macro_resolver::value_info>& values,
const std::string& ref)
{
const std::vector<filter_macro_resolver::value_info>& 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<filter_ast::expr> macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), "exists");
std::shared_ptr<filter_ast::expr> macro =
filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""),
"exists");
std::vector<std::unique_ptr<filter_ast::expr>> 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_ast::expr> filter = filter_ast::and_expr::create(filter_and);
std::vector<std::unique_ptr<filter_ast::expr>> 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<filter_ast::expr> 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<filter_ast::expr> macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), "exists");
std::shared_ptr<filter_ast::expr> macro =
filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""),
"exists");
std::shared_ptr<filter_ast::expr> filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos);
std::shared_ptr<filter_ast::expr> 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<filter_ast::expr> a_macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), "exists");
std::shared_ptr<filter_ast::expr> b_macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("another.field", ""), "exists");
std::shared_ptr<filter_ast::expr> a_macro =
filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""),
"exists");
std::shared_ptr<filter_ast::expr> b_macro = filter_ast::unary_check_expr::create(
filter_ast::field_expr::create("another.field", ""),
"exists");
std::vector<std::unique_ptr<filter_ast::expr>> 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<std::unique_ptr<filter_ast::expr>> 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<filter_ast::expr> a_macro = filter_ast::and_expr::create(a_macro_and);
std::shared_ptr<filter_ast::expr> b_macro =
filter_ast::unary_check_expr::create(filter_ast::field_expr::create("another.field", ""), "exists");
std::shared_ptr<filter_ast::expr> b_macro = filter_ast::unary_check_expr::create(
filter_ast::field_expr::create("another.field", ""),
"exists");
std::shared_ptr<filter_ast::expr> filter = filter_ast::identifier_expr::create(MACRO_A_NAME, a_macro_pos);
std::shared_ptr<filter_ast::expr> filter =
filter_ast::identifier_expr::create(MACRO_A_NAME, a_macro_pos);
std::vector<std::unique_ptr<filter_ast::expr>> 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<filter_ast::expr> 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<std::unique_ptr<filter_ast::expr>> 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_ast::expr> 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<std::unique_ptr<filter_ast::expr>> 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<filter_ast::expr> a_macro = filter_ast::and_expr::create(a_macro_and);
std::shared_ptr<filter_ast::expr> filter = filter_ast::identifier_expr::create(MACRO_A_NAME, a_macro_pos);
std::shared_ptr<filter_ast::expr> 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<filter_ast::expr> macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), "exists");
std::shared_ptr<filter_ast::expr> a_filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos_1);
std::shared_ptr<filter_ast::expr> b_filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos_2);
std::shared_ptr<filter_ast::expr> macro =
filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""),
"exists");
std::shared_ptr<filter_ast::expr> a_filter =
filter_ast::identifier_expr::create(MACRO_NAME, macro_pos_1);
std::shared_ptr<filter_ast::expr> 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<filter_ast::unary_check_expr> macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), "exists");
std::shared_ptr<filter_ast::expr> filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos);
std::shared_ptr<filter_ast::unary_check_expr> macro =
filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""),
"exists");
std::shared_ptr<filter_ast::expr> filter =
filter_ast::identifier_expr::create(MACRO_NAME, macro_pos);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);

View File

@@ -18,16 +18,14 @@ limitations under the License.
#include <gtest/gtest.h>
#include <engine/filter_warning_resolver.h>
static bool warns(const std::string& condition)
{
static bool warns(const std::string& condition) {
std::set<falco::load_result::warning_code> 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 = <NA>"));
ASSERT_TRUE(warns("jevt.field = <NA>"));

View File

@@ -20,22 +20,19 @@ limitations under the License.
#include <gtest/gtest.h>
static bool check_requirements(std::string& err,
const std::vector<falco_engine::plugin_version_requirement>& plugins,
const std::string& ruleset_content)
{
const std::vector<falco_engine::plugin_version_requirement>& 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;
}

View File

@@ -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<std::string>(),
"evt.type=open and proc.name = cat");
"evt.type=open and proc.name = cat");
ASSERT_EQ(rule_description["rules"][0]["info"]["output"].template get<std::string>(),
"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<std::string>(),
"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<std::string>(),
"evt.type = close");
"evt.type = close");
ASSERT_EQ(rule_description["rules"][0]["info"]["output"].template get<std::string>(),
"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<std::string>(),
"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<std::string>(),
"evt.type = close and proc.name = cat");
"evt.type = close and proc.name = cat");
ASSERT_EQ(rule_description["rules"][0]["info"]["output"].template get<std::string>(),
"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<std::string>(),
"a replaced legit description");
"a replaced legit description");
ASSERT_EQ(rule_description["rules"][0]["info"]["priority"].template get<std::string>(),
"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<std::string>(), "non_escaped_val");
ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"][1].template get<std::string>(), "escaped val");
ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"][0]
.template get<std::string>(),
"non_escaped_val");
ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"][1]
.template get<std::string>(),
"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)");
}

View File

@@ -23,32 +23,28 @@ limitations under the License.
#define RULESET_2 2
/* Helpers methods */
static std::shared_ptr<sinsp_filter_factory> create_factory(sinsp* inspector, filter_check_list& list)
{
static std::shared_ptr<sinsp_filter_factory> create_factory(sinsp* inspector,
filter_check_list& list) {
return std::make_shared<sinsp_filter_factory>(inspector, list);
}
static std::shared_ptr<filter_ruleset> create_ruleset(std::shared_ptr<sinsp_filter_factory> f)
{
static std::shared_ptr<filter_ruleset> create_ruleset(std::shared_ptr<sinsp_filter_factory> f) {
return std::make_shared<evttype_index_ruleset>(f);
}
static std::shared_ptr<libsinsp::filter::ast::expr> create_ast(std::shared_ptr<sinsp_filter_factory> f)
{
static std::shared_ptr<libsinsp::filter::ast::expr> create_ast(
std::shared_ptr<sinsp_filter_factory> f) {
libsinsp::filter::parser parser("evt.type=open");
return parser.parse();
}
static std::shared_ptr<sinsp_filter> create_filter(
std::shared_ptr<sinsp_filter_factory> f,
libsinsp::filter::ast::expr* ast)
{
static std::shared_ptr<sinsp_filter> create_filter(std::shared_ptr<sinsp_filter_factory> f,
libsinsp::filter::ast::expr* ast) {
sinsp_filter_compiler compiler(f, ast);
return std::shared_ptr<sinsp_filter>(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;

View File

@@ -19,5 +19,17 @@ limitations under the License.
#include <falco/app/state.h>
#include <falco/app/actions/actions.h>
#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, ""); \
}

View File

@@ -23,23 +23,21 @@ limitations under the License.
#include <falco/app/app.h>
#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<std::string>;
static std::set<std::string> _order(const strset_t& s)
{
static std::set<std::string> _order(const strset_t& s) {
return std::set<std::string>(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);
}

View File

@@ -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";
}

View File

@@ -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));

View File

@@ -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));
}
}

View File

@@ -25,13 +25,11 @@ limitations under the License.
#include <memory>
#include <vector>
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<std::future<task_result_t>> 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<std::chrono::seconds>(diff);
return res;
}));
}
auto diff = std::chrono::high_resolution_clock::now() - start;
res.duration_secs = std::chrono::duration_cast<std::chrono::seconds>(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());

View File

@@ -19,20 +19,19 @@ limitations under the License.
#include <falco/configuration.h>
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";
"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)
{
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<bool>("base_value.subvalue.subvalue2.boolean", false), true);
/* get list field elements */
ASSERT_STREQ(conf.get_scalar<std::string>("base_value_2.sample_list[0]", "none").c_str(), "elem1");
ASSERT_STREQ(conf.get_scalar<std::string>("base_value_2.sample_list[1]", "none").c_str(), "elem2");
ASSERT_STREQ(conf.get_scalar<std::string>("base_value_2.sample_list[2]", "none").c_str(), "elem3");
ASSERT_STREQ(conf.get_scalar<std::string>("base_value_2.sample_list[0]", "none").c_str(),
"elem1");
ASSERT_STREQ(conf.get_scalar<std::string>("base_value_2.sample_list[1]", "none").c_str(),
"elem2");
ASSERT_STREQ(conf.get_scalar<std::string>("base_value_2.sample_list[2]", "none").c_str(),
"elem3");
/* get sequence */
std::vector<std::string> 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<bool>(key, false), true);
/* Modify the original value */
conf.set_scalar<bool>(key, false);
/* Modify the original value */
conf.set_scalar<bool>(key, false);
ASSERT_EQ(conf.get_scalar<bool>(key, true), false);
/* Modify it again */
conf.set_scalar<bool>(key, true);
/* Modify it again */
conf.set_scalar<bool>(key, true);
ASSERT_EQ(conf.get_scalar<bool>(key, false), true);
}
TEST(Configuration, configuration_webserver_ip)
{
falco_configuration falco_config;
TEST(Configuration, configuration_webserver_ip) {
falco_configuration falco_config;
std::vector<std::string> 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"};
std::vector<std::string> 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);
for(const std::string &address : valid_addresses) {
std::string option = "webserver.listen_address=";
option.append(address);
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back(option);
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back(option);
EXPECT_NO_THROW(falco_config.init_from_content("", cmdline_config_options));
EXPECT_NO_THROW(falco_config.init_from_content("", cmdline_config_options));
ASSERT_EQ(falco_config.m_webserver_config.m_listen_address, address);
}
ASSERT_EQ(falco_config.m_webserver_config.m_listen_address, address);
}
std::vector<std::string> 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",};
std::vector<std::string> 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);
for(const std::string &address : invalid_addresses) {
std::string option = "webserver.listen_address=";
option.append(address);
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back(option);
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back(option);
EXPECT_ANY_THROW(falco_config.init_from_content("", cmdline_config_options));
}
EXPECT_ANY_THROW(falco_config.init_from_content("", cmdline_config_options));
}
}

View File

@@ -18,23 +18,23 @@ limitations under the License.
#include <gtest/gtest.h>
#include <falco/configuration.h>
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<int>("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<std::string>("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<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.m_config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.m_config.get_scalar<int>("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<int>("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<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.m_config.is_defined("base_value_2.id"));
ASSERT_EQ(falco_config.m_config.get_scalar<int>("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<std::string> 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");
}
}

View File

@@ -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<std::string>("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<std::string>("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<std::string>("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<std::string>("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<std::string>("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<std::string>("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<std::string>("base_value.invalid_embedded_env", default_value);
auto base_value_embedded_invalid =
conf.get_scalar<std::string>("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<std::string>("base_value.invalid_valid_env", default_value);
auto base_value_valid_invalid =
conf.get_scalar<std::string>("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<std::string>("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<std::string>("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<std::string>("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<std::string>("base_value.subvalue.subvalue2.boolean", default_value);
auto unknown_boolean =
conf.get_scalar<std::string>("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<std::string>("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_0 =
conf.get_scalar<std::string>("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<std::string>("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_1 =
conf.get_scalar<std::string>("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<std::string>("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_2 =
conf.get_scalar<std::string>("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<std::string>("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_3 =
conf.get_scalar<std::string>("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<std::string>("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<std::string>("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<std::string>("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<std::string>("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<std::string>("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<bool>("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<std::string>("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<int32_t>("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<int32_t>("num_test", -1);
ASSERT_EQ(integer, 12);
@@ -182,9 +209,11 @@ TEST(Configuration, configuration_environment_variables)
ASSERT_EQ(empty_default_str, "");
std::list<falco_configuration::plugin_config> plugins;
conf.get_sequence<std::list<falco_configuration::plugin_config>>(plugins, std::string("plugins"));
std::vector<falco_configuration::plugin_config> m_plugins{ std::make_move_iterator(std::begin(plugins)),
std::make_move_iterator(std::end(plugins)) };
conf.get_sequence<std::list<falco_configuration::plugin_config>>(plugins,
std::string("plugins"));
std::vector<falco_configuration::plugin_config> 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");

View File

@@ -18,8 +18,7 @@ limitations under the License.
#include <gtest/gtest.h>
#include <falco/configuration.h>
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 @@ append_output:
- ka.verb
- static_field: "static content"
)", {}));
)",
{}));
EXPECT_EQ(falco_config.m_append_output.size(), 3);
@@ -53,17 +53,22 @@ append_output:
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 @@ append_output:
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<std::string>{
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<std::string>{
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");

View File

@@ -18,8 +18,7 @@ limitations under the License.
#include <gtest/gtest.h>
#include <falco/configuration.h>
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 @@ rules:
- 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<std::string>{"rules[].disable.tag=maturity_incubating", "rules[].enable.rule=Adding ssh keys to authorized_keys"}));
ASSERT_NO_THROW(falco_config.init_from_content(
"",
std::vector<std::string>{"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<std::string>{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<std::string>{
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");
}

View File

@@ -18,94 +18,142 @@ limitations under the License.
#include <gtest/gtest.h>
#include <falco/configuration.h>
#include <falco_test_var.h>
#include <nlohmann/json.hpp>
#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, schema_yaml_helper_validator)
{
TEST(Configuration, plugin_init_config) {
falco_configuration falco_config;
config_loaded_res res;
std::string config = R"(
plugins:
- name: k8saudit
library_path: libk8saudit.so
init_config:
maxEventSize: 262144
sslCertificate: /etc/falco/falco.pem
)";
auto plugin_config_json = nlohmann::json::parse(
R"({"maxEventSize": 262144, "sslCertificate": "/etc/falco/falco.pem"})");
EXPECT_NO_THROW(res = falco_config.init_from_content(config, {}));
EXPECT_VALIDATION_STATUS(res, yaml_helper::validation_ok);
auto parsed_init_config = nlohmann::json::parse(falco_config.m_plugins[0].m_init_config);
EXPECT_EQ(parsed_init_config, plugin_config_json);
config = R"(
plugins:
- name: k8saudit
library_path: libk8saudit.so
init_config: '{"maxEventSize": 262144, "sslCertificate": "/etc/falco/falco.pem"}'
)";
EXPECT_NO_THROW(res = falco_config.init_from_content(config, {}));
EXPECT_VALIDATION_STATUS(res, yaml_helper::validation_ok);
parsed_init_config = nlohmann::json::parse(falco_config.m_plugins[0].m_init_config);
EXPECT_EQ(parsed_init_config, plugin_config_json);
config = R"(
plugins:
- name: k8saudit
library_path: libk8saudit.so
init_config: ""
)";
EXPECT_NO_THROW(res = falco_config.init_from_content(config, {}));
EXPECT_VALIDATION_STATUS(res, yaml_helper::validation_ok);
EXPECT_EQ(falco_config.m_plugins[0].m_init_config, "");
config = R"(
plugins:
- name: k8saudit
library_path: libk8saudit.so
init_config: null
)";
EXPECT_NO_THROW(res = falco_config.init_from_content(config, {}));
EXPECT_VALIDATION_STATUS(res, yaml_helper::validation_ok);
EXPECT_EQ(falco_config.m_plugins[0].m_init_config, "");
}
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));
@@ -121,4 +169,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);
}
}

View File

@@ -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<sinsp_filter_factory>(&m_inspector, m_filterlist);
m_formatter_factory = std::make_shared<sinsp_evt_formatter_factory>(&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<std::string>();
return rule_description["rules"][0]["details"]["condition_compiled"]
.template get<std::string>();
}
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::string>();
}
std::unordered_map<std::string, std::string> test_falco_engine::get_compiled_rule_formatted_fields(std::string rule_name) const
{
std::unordered_map<std::string, std::string> 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<std::unordered_map<std::string, std::string>>();
return rule_description["rules"][0]["details"]["extra_output_formatted_fields"]
.template get<std::unordered_map<std::string, std::string>>();
}

View File

@@ -8,8 +8,7 @@
#include <gtest/gtest.h>
#include <unordered_map>
class test_falco_engine : public testing::Test
{
class test_falco_engine : public testing::Test {
protected:
test_falco_engine();
@@ -21,7 +20,8 @@ protected:
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<std::string, std::string> get_compiled_rule_formatted_fields(std::string rule_name) const;
std::unordered_map<std::string, std::string> 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;

View File

@@ -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)

View File

@@ -21,57 +21,43 @@ limitations under the License.
#include <algorithm>
evttype_index_ruleset::evttype_index_ruleset(
std::shared_ptr<sinsp_filter_factory> f):
m_filter_factory(f)
{
}
evttype_index_ruleset::evttype_index_ruleset(std::shared_ptr<sinsp_filter_factory> 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<sinsp_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition)
{
try
{
void evttype_index_ruleset::add(const falco_rule &rule,
std::shared_ptr<sinsp_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition) {
try {
auto wrap = std::make_shared<evttype_index_wrapper>();
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<falco_rule> &matches)
{
bool evttype_index_ruleset::run_wrappers(sinsp_evt *evt,
filter_wrapper_list &wrappers,
uint16_t ruleset_id,
std::vector<falco_rule> &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<evttype_index_wrapper> wrap)
{
auto logger = [](std::shared_ptr<evttype_index_wrapper> 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");
}

View File

@@ -24,12 +24,11 @@ limitations under the License.
#include <vector>
/*!
\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<std::string> &tags() { return m_rule.tags; }
const libsinsp::events::set<ppm_sc_code> &sc_codes() { return m_sc_codes; }
@@ -41,23 +40,27 @@ struct evttype_index_wrapper
std::shared_ptr<sinsp_filter> m_filter;
};
class evttype_index_ruleset : public indexable_ruleset<evttype_index_wrapper>
{
class evttype_index_ruleset : public indexable_ruleset<evttype_index_wrapper> {
public:
explicit evttype_index_ruleset(std::shared_ptr<sinsp_filter_factory> factory);
virtual ~evttype_index_ruleset();
// From filter_ruleset
void add(
const falco_rule& rule,
std::shared_ptr<sinsp_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition) override;
void add(const falco_rule &rule,
std::shared_ptr<sinsp_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> 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<falco_rule> &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<falco_rule> &matches) override;
// Print each enabled rule when running Falco with falco logger
// log_level=debug; invoked within on_loading_complete()
@@ -67,15 +70,12 @@ private:
std::shared_ptr<sinsp_filter_factory> 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<sinsp_filter_factory> factory
): m_filter_factory(factory) { }
inline explicit evttype_index_ruleset_factory(std::shared_ptr<sinsp_filter_factory> factory):
m_filter_factory(factory) {}
inline std::shared_ptr<filter_ruleset> new_ruleset() override
{
inline std::shared_ptr<filter_ruleset> new_ruleset() override {
return std::make_shared<evttype_index_ruleset>(m_filter_factory);
}

View File

@@ -17,83 +17,57 @@ limitations under the License.
#include "falco_common.h"
static std::vector<std::string> priority_names = {
"Emergency",
"Alert",
"Critical",
"Error",
"Warning",
"Notice",
"Informational",
"Debug"
};
static std::vector<std::string> priority_names =
{"Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Informational", "Debug"};
static std::vector<std::string> rule_matching_names = {
"first",
"all"
};
static std::vector<std::string> 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;
}
}

View File

@@ -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
{
namespace falco_common {
const std::string syscall_source = sinsp_syscall_event_source_name;
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);
// 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<std::string, std::pair<std::string, bool>> extra_output_field_t;

File diff suppressed because it is too large Load Diff

View File

@@ -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 @@ public:
// 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 @@ public:
//
// Load rules and returns a result object.
//
std::unique_ptr<falco::load_result> load_rules(const std::string &rules_content, const std::string &name);
std::unique_ptr<falco::load_result> load_rules(const std::string &rules_content,
const std::string &name);
//
// Enable/Disable any rules matching the provided substring.
@@ -91,30 +90,42 @@ public:
// 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<std::string> &tags, bool enabled, const std::string &ruleset = s_default_ruleset);
void enable_rule_by_tag(const std::set<std::string> &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<std::string> &tags, bool enabled, const uint16_t ruleset_id);
void enable_rule_by_tag(const std::set<std::string> &tags,
bool enabled,
const uint16_t ruleset_id);
//
// Must be called after the engine has been configured and all rulesets
@@ -147,12 +158,13 @@ public:
// 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<std::shared_ptr<sinsp_plugin>>& plugins) const;
nlohmann::json describe_rule(std::string *rule_name,
const std::vector<std::shared_ptr<sinsp_plugin>> &plugins) const;
//
// Return const /ref to rules stored in the Falco engine.
//
inline const indexed_vector<falco_rule>& get_rules() const { return m_rules; }
inline const indexed_vector<falco_rule> &get_rules() const { return m_rules; }
//
// Print statistics on how many events matched each rule.
@@ -160,9 +172,10 @@ public:
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 @@ public:
// add k8s/container information to outputs when
// available.
//
void add_extra_output_format(
const std::string &format,
const std::string &source,
const std::set<std::string> &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<std::string> &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<std::string> &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<std::string> &tags,
const std::string &rule);
void add_extra_output_raw_field(
const std::string &key,
const std::string &source,
const std::set<std::string> &tags,
const std::string &rule
);
void add_extra_output_raw_field(const std::string &key,
const std::string &source,
const std::set<std::string> &tags,
const std::string &rule);
// Represents the result of matching an event against a set of
// rules.
@@ -249,7 +256,9 @@ public:
// concurrently with the same source_idx would inherently cause data races
// and lead to undefined behavior.
std::unique_ptr<std::vector<rule_result>> 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 @@ public:
// This inherits the same thread-safety guarantees.
//
std::unique_ptr<std::vector<rule_result>> 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 @@ public:
// Return source index for fast lookup.
//
std::size_t add_source(const std::string &source,
std::shared_ptr<sinsp_filter_factory> filter_factory,
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory);
std::shared_ptr<sinsp_filter_factory> filter_factory,
std::shared_ptr<sinsp_evt_formatter_factory> 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<sinsp_filter_factory> filter_factory,
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory,
std::shared_ptr<filter_ruleset_factory> ruleset_factory);
std::shared_ptr<sinsp_filter_factory> filter_factory,
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory,
std::shared_ptr<filter_ruleset_factory> ruleset_factory);
// Return whether or not there is a valid filter/formatter
// factory for this source.
@@ -285,25 +295,27 @@ public:
// Given a source, return a formatter factory that can create
// filters for events of that source.
//
std::shared_ptr<sinsp_filter_factory> filter_factory_for_source(const std::string& source);
std::shared_ptr<sinsp_filter_factory> filter_factory_for_source(const std::string &source);
std::shared_ptr<sinsp_filter_factory> 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<sinsp_evt_formatter_factory> formatter_factory_for_source(const std::string& source);
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory_for_source(std::size_t source_idx);
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory_for_source(
const std::string &source);
std::shared_ptr<sinsp_evt_formatter_factory> 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<filter_ruleset_factory> ruleset_factory_for_source(const std::string& source);
std::shared_ptr<filter_ruleset_factory> ruleset_factory_for_source(const std::string &source);
std::shared_ptr<filter_ruleset_factory> ruleset_factory_for_source(std::size_t source_idx);
// Return the filter_ruleset used for a given source.
std::shared_ptr<filter_ruleset> ruleset_for_source(const std::string& source);
std::shared_ptr<filter_ruleset> ruleset_for_source(const std::string &source);
std::shared_ptr<filter_ruleset> ruleset_for_source(std::size_t source_idx);
//
@@ -314,24 +326,24 @@ public:
// todo(jasondellaluce): remove this in future code refactors
//
void evttypes_for_ruleset(const std::string &source,
std::set<uint16_t> &evttypes,
const std::string &ruleset = s_default_ruleset);
std::set<uint16_t> &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<ppm_sc_code> 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<ppm_event_code> 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 @@ public:
// event.
//
std::shared_ptr<sinsp_evt_formatter> 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 @@ public:
// 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<plugin_version_requirement>& plugins,
std::string& err) const;
bool check_plugin_requirements(const std::vector<plugin_version_requirement> &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<filter_ruleset> create_ruleset(std::shared_ptr<filter_ruleset_factory>& ruleset_factory);
std::shared_ptr<filter_ruleset> create_ruleset(
std::shared_ptr<filter_ruleset_factory> &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<falco_source> 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 @@ private:
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 @@ private:
// 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<size_t> m_syscall_source_idx;
//
@@ -425,31 +428,26 @@ private:
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<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_details(
nlohmann::json& out,
const falco_macro& m,
const rule_loader::macro_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_details(
nlohmann::json& out,
const falco_list& l,
const rule_loader::list_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& 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<std::string>& evttypes,
const std::unordered_set<std::string>& fields,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_details(nlohmann::json &out,
const falco_rule &r,
const rule_loader::rule_info &info,
const std::vector<std::shared_ptr<sinsp_plugin>> &plugins) const;
void get_json_details(nlohmann::json &out,
const falco_macro &m,
const rule_loader::macro_info &info,
const std::vector<std::shared_ptr<sinsp_plugin>> &plugins) const;
void get_json_details(nlohmann::json &out,
const falco_list &l,
const rule_loader::list_info &info,
const std::vector<std::shared_ptr<sinsp_plugin>> &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<std::string> &evttypes,
const std::unordered_set<std::string> &fields,
const std::vector<std::shared_ptr<sinsp_plugin>> &plugins) const;
indexed_vector<falco_rule> m_rules;
std::shared_ptr<rule_loader::reader> m_rule_reader;

View File

@@ -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.

View File

@@ -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"
};
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)
{
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"
};
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)
{
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"
};
"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)
{
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"
};
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)
{
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 <NA> 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"
};
static const std::string warning_strings[] = {"Unknown event source",
"Unsafe <NA> 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)
{
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 <NA> 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"
};
"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 <NA> 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)
{
const std::string& falco::load_result::warning_desc(warning_code wc) {
return warning_descs[wc];
}

View File

@@ -21,13 +21,11 @@ limitations under the License.
#include <string>
#include <nlohmann/json.hpp>
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 @@ public:
virtual const nlohmann::json& as_json(const rules_contents_t& contents) = 0;
};
} // namespace falco
} // namespace falco

View File

@@ -24,16 +24,15 @@ limitations under the License.
#include <libsinsp/filter/ast.h>
/*!
\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;

View File

@@ -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<falco_rule> 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;
}
}

View File

@@ -30,19 +30,22 @@ limitations under the License.
#include <iomanip>
#include <thread>
#define RGX_PROMETHEUS_TIME_DURATION "^((?P<y>[0-9]+)y)?((?P<w>[0-9]+)w)?((?P<d>[0-9]+)d)?((?P<h>[0-9]+)h)?((?P<m>[0-9]+)m)?((?P<s>[0-9]+)s)?((?P<ms>[0-9]+)ms)?$"
#define RGX_PROMETHEUS_TIME_DURATION \
"^((?P<y>[0-9]+)y)?((?P<w>[0-9]+)w)?((?P<d>[0-9]+)d)?((?P<h>[0-9]+)h)?((?P<m>[0-9]+)m)?((?P<" \
"s>[0-9]+)s)?((?P<ms>[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 re2::RE2::Arg* const matches[14] = {&arg0,
&arg1,
&arg2,
&arg3,
&arg4,
&arg5,
&arg6,
&arg7,
&arg8,
&arg9,
&arg10,
&arg11,
&arg12,
&arg13};
const std::map<std::string, int>& named_groups = s_rgx_prometheus_time_duration.NamedCapturingGroups();
const std::map<std::string, int>& 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 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 };
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++)
{
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<unsigned>(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

View File

@@ -23,8 +23,7 @@ limitations under the License.
#include <cstdint>
#include <string>
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

View File

@@ -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);
}

View File

@@ -22,8 +22,7 @@ limitations under the License.
#include <unordered_set>
#include <unordered_map>
struct filter_details
{
struct filter_details {
// input macros and lists
std::unordered_set<std::string> known_macros;
std::unordered_set<std::string> 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;

View File

@@ -20,8 +20,7 @@ limitations under the License.
using namespace libsinsp::filter;
bool filter_macro_resolver::run(std::shared_ptr<libsinsp::filter::ast::expr>& filter)
{
bool filter_macro_resolver::run(std::shared_ptr<libsinsp::filter::ast::expr>& filter) {
m_unknown_macros.clear();
m_resolved_macros.clear();
m_errors.clear();
@@ -29,110 +28,90 @@ bool filter_macro_resolver::run(std::shared_ptr<libsinsp::filter::ast::expr>& 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<libsinsp::filter::ast::expr>& macro)
{
void filter_macro_resolver::set_macro(const std::string& name,
const std::shared_ptr<libsinsp::filter::ast::expr>& macro) {
m_macros[name] = macro;
}
const std::vector<filter_macro_resolver::value_info>& filter_macro_resolver::get_unknown_macros() const
{
const std::vector<filter_macro_resolver::value_info>& filter_macro_resolver::get_unknown_macros()
const {
return m_unknown_macros;
}
const std::vector<filter_macro_resolver::value_info>& filter_macro_resolver::get_errors() const
{
const std::vector<filter_macro_resolver::value_info>& filter_macro_resolver::get_errors() const {
return m_errors;
}
const std::vector<filter_macro_resolver::value_info>& filter_macro_resolver::get_resolved_macros() const
{
const std::vector<filter_macro_resolver::value_info>& 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()});
}

View File

@@ -24,114 +24,107 @@ limitations under the License.
#include <memory>
/*!
\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<libsinsp::filter::ast::expr>& filter);
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<libsinsp::filter::ast::expr>& 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<libsinsp::filter::ast::expr>& macro);
/*!
\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<libsinsp::filter::ast::expr>& 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<std::string,libsinsp::filter::ast::pos_info> value_info;
/*!
\brief used in get_{resolved,unknown}_macros and get_errors
to represent an identifier/string value along with an AST position.
*/
typedef std::pair<std::string, libsinsp::filter::ast::pos_info> 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<value_info>& get_resolved_macros() const;
/*!
\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<value_info>& 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<value_info>& get_unknown_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<value_info>& get_unknown_macros() const;
/*!
\brief Returns a list of errors occurred during
the latest invocation of run().
*/
const std::vector<value_info>& get_errors() const;
/*!
\brief Returns a list of errors occurred during
the latest invocation of run().
*/
const std::vector<value_info>& 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();
}
/*!
\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<libsinsp::filter::ast::expr>
> macro_defs;
private:
typedef std::unordered_map<std::string, std::shared_ptr<libsinsp::filter::ast::expr> >
macro_defs;
struct visitor : public libsinsp::filter::ast::expr_visitor
{
visitor(
std::vector<value_info>& errors,
std::vector<value_info>& unknown_macros,
std::vector<value_info>& resolved_macros,
macro_defs& macros):
m_errors(errors),
m_unknown_macros(unknown_macros),
m_resolved_macros(resolved_macros),
m_macros(macros) {}
struct visitor : public libsinsp::filter::ast::expr_visitor {
visitor(std::vector<value_info>& errors,
std::vector<value_info>& unknown_macros,
std::vector<value_info>& resolved_macros,
macro_defs& macros):
m_errors(errors),
m_unknown_macros(unknown_macros),
m_resolved_macros(resolved_macros),
m_macros(macros) {}
std::vector<std::string> m_macros_path;
std::unique_ptr<libsinsp::filter::ast::expr> m_node_substitute;
std::vector<value_info>& m_errors;
std::vector<value_info>& m_unknown_macros;
std::vector<value_info>& m_resolved_macros;
macro_defs& m_macros;
std::vector<std::string> m_macros_path;
std::unique_ptr<libsinsp::filter::ast::expr> m_node_substitute;
std::vector<value_info>& m_errors;
std::vector<value_info>& m_unknown_macros;
std::vector<value_info>& 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;
};
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<value_info> m_errors;
std::vector<value_info> m_unknown_macros;
std::vector<value_info> m_resolved_macros;
macro_defs m_macros;
std::vector<value_info> m_errors;
std::vector<value_info> m_unknown_macros;
std::vector<value_info> m_resolved_macros;
macro_defs m_macros;
};

View File

@@ -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;
}

View File

@@ -25,25 +25,22 @@ limitations under the License.
#include <libsinsp/events/sinsp_events.h>
/*!
\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<bool(const std::string &, std::shared_ptr<filter_ruleset> &ruleset)>;
struct engine_state_funcs {
using ruleset_retriever_func_t =
std::function<bool(const std::string &, std::shared_ptr<filter_ruleset> &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 @@ public:
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<sinsp_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition) = 0;
virtual void add(const falco_rule &rule,
std::shared_ptr<sinsp_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> 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;
/*!
\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<falco_rule>& matches,
uint16_t ruleset_id) = 0;
virtual bool run(sinsp_evt *evt, falco_rule &match, 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 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<falco_rule> &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
*/
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<uint16_t> &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
*/
virtual libsinsp::events::set<ppm_sc_code> 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
*/
virtual libsinsp::events::set<ppm_event_code> enabled_event_codes(
uint16_t ruleset) = 0;
virtual void enabled_evttypes(std::set<uint16_t> &evttypes, 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 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 void enable(
const std::string &pattern,
match_type match,
uint16_t ruleset_id) = 0;
virtual libsinsp::events::set<ppm_sc_code> enabled_sc_codes(uint16_t ruleset) = 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 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 void disable(
const std::string &pattern,
match_type match,
uint16_t ruleset_id) = 0;
virtual libsinsp::events::set<ppm_event_code> enabled_event_codes(uint16_t ruleset) = 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 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_tags(
const std::set<std::string> &tags,
uint16_t ruleset_id) = 0;
virtual void enable(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
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 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_tags(
const std::set<std::string> &tags,
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
*/
virtual void enable_tags(const std::set<std::string> &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
*/
virtual void disable_tags(const std::set<std::string> &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;

View File

@@ -22,22 +22,18 @@ using namespace falco;
static const char* no_value = "<NA>";
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<load_result::warning_code>& warnings) const
{
bool filter_warning_resolver::run(libsinsp::filter::ast::expr* filter,
std::set<load_result::warning_code>& 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);
}
}

View File

@@ -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<falco::load_result::warning_code>& warnings) const;
bool run(libsinsp::filter::ast::expr* filter,
std::set<falco::load_result::warning_code>& 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;

View File

@@ -21,41 +21,37 @@ limitations under the License.
#include "falco_engine.h"
falco_formats::falco_formats(std::shared_ptr<const falco_engine> 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)
{
}
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()
{
}
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<std::string> &tags,
const std::string &hostname, const extra_output_field_t &extra_fields) const
{
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<std::string> &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<sinsp_evt_formatter> formatter;
@@ -180,14 +170,14 @@ std::string falco_formats::format_string(sinsp_evt *evt, const std::string &form
return line;
}
std::map<std::string, std::string> falco_formats::get_field_values(sinsp_evt *evt, const std::string &source,
const std::string &format) const
{
std::map<std::string, std::string> falco_formats::get_field_values(
sinsp_evt *evt,
const std::string &source,
const std::string &format) const {
std::shared_ptr<sinsp_evt_formatter> formatter;
std::string fformat = format;
if(fformat[0] != '*')
{
if(fformat[0] != '*') {
fformat = "*" + fformat;
}
@@ -195,8 +185,7 @@ std::map<std::string, std::string> falco_formats::get_field_values(sinsp_evt *ev
std::map<std::string, std::string> 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");
}

View File

@@ -21,24 +21,31 @@ limitations under the License.
#include <map>
#include "falco_engine.h"
class falco_formats
{
class falco_formats {
public:
falco_formats(std::shared_ptr<const falco_engine> 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<std::string> &tags,
const std::string &hostname, const extra_output_field_t &extra_fields) 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<std::string> &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::string format_string(sinsp_evt *evt,
const std::string &format,
const std::string &source) const;
std::map<std::string, std::string> get_field_values(sinsp_evt *evt, const std::string &source,
const std::string &format) const ;
std::map<std::string, std::string> get_field_values(sinsp_evt *evt,
const std::string &source,
const std::string &format) const;
protected:
std::shared_ptr<const falco_engine> m_falco_engine;

View File

@@ -43,139 +43,98 @@ limitations under the License.
// const libsinsp::events::set<ppm_event_code> &filter_wrapper::event_codes();
template<class filter_wrapper>
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<ruleset_filters>(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<ruleset_filters>(m_rulesets.size()));
}
return m_rulesets[ruleset_id]->num_filters();
}
void enabled_evttypes(
std::set<uint16_t> &evttypes,
uint16_t ruleset_id) override
{
void enabled_evttypes(std::set<uint16_t> &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<ppm_sc_code> enabled_sc_codes(
uint16_t ruleset_id) override
{
if(m_rulesets.size() < (size_t)ruleset_id + 1)
{
libsinsp::events::set<ppm_sc_code> 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<ppm_event_code> enabled_event_codes(
uint16_t ruleset_id) override
{
if(m_rulesets.size() < (size_t)ruleset_id + 1)
{
libsinsp::events::set<ppm_event_code> 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<std::string> &tags,
uint16_t ruleset_id) override
{
void enable_tags(const std::set<std::string> &tags, uint16_t ruleset_id) override {
enable_disable_tags(tags, true, ruleset_id);
}
void disable_tags(
const std::set<std::string> &tags,
uint16_t ruleset_id) override
{
void disable_tags(const std::set<std::string> &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<falco_rule> &matches, uint16_t ruleset_id) override
{
if(m_rulesets.size() < (size_t)ruleset_id + 1)
{
bool run(sinsp_evt *evt, std::vector<falco_rule> &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<std::shared_ptr<filter_wrapper>>
filter_wrapper_list;
typedef std::list<std::shared_ptr<filter_wrapper>> 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<filter_wrapper> wrap)
{
m_filters.insert(wrap);
}
void add_wrapper(std::shared_ptr<filter_wrapper> 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<void(const std::shared_ptr<filter_wrapper> &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 @@ public:
// 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<falco_rule> &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<falco_rule> &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<ruleset_filters>(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 @@ private:
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 @@ private:
}
// Helper used by enable_tags()/disable_tags()
void enable_disable_tags(
const std::set<std::string> &tags,
bool enabled,
uint16_t ruleset_id)
{
while(m_rulesets.size() < (size_t)ruleset_id + 1)
{
void enable_disable_tags(const std::set<std::string> &tags, bool enabled, uint16_t ruleset_id) {
while(m_rulesets.size() < (size_t)ruleset_id + 1) {
m_rulesets.emplace_back(std::make_shared<ruleset_filters>(m_rulesets.size()));
}
for(const auto &wrap : m_filters)
{
for(const auto &wrap : m_filters) {
std::set<std::string> 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 @@ private:
}
// 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<filter_wrapper> wrap)
{
if(wrap->event_codes().empty())
{
void add_filter(std::shared_ptr<filter_wrapper> 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 @@ private:
m_filters.insert(wrap);
}
void remove_filter(std::shared_ptr<filter_wrapper> wrap)
{
if(wrap->event_codes().empty())
{
void remove_filter(std::shared_ptr<filter_wrapper> 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 @@ private:
m_filters.erase(wrap);
}
uint64_t num_filters()
{
return m_filters.size();
}
uint64_t num_filters() { return m_filters.size(); }
inline const std::set<std::shared_ptr<filter_wrapper>> &get_filters() const
{
inline const std::set<std::shared_ptr<filter_wrapper>> &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 @@ private:
// Evaluate an event against the ruleset and return all the
// matching rules.
bool run(indexable_ruleset &ruleset, sinsp_evt *evt, std::vector<falco_rule> &matches)
{
bool run(indexable_ruleset &ruleset, sinsp_evt *evt, std::vector<falco_rule> &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 @@ private:
return false;
}
libsinsp::events::set<ppm_sc_code> sc_codes()
{
libsinsp::events::set<ppm_sc_code> sc_codes() {
libsinsp::events::set<ppm_sc_code> 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<ppm_event_code> event_codes()
{
libsinsp::events::set<ppm_event_code> event_codes() {
libsinsp::events::set<ppm_event_code> 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<filter_wrapper> wrap)
{
void add_wrapper_to_list(filter_wrapper_list &wrappers,
std::shared_ptr<filter_wrapper> 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<filter_wrapper> wrap)
{
void remove_wrapper_from_list(filter_wrapper_list &wrappers,
std::shared_ptr<filter_wrapper> 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);
}
}

View File

@@ -22,63 +22,54 @@ limitations under the License.
#include <unordered_map>
/*!
\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 <typename T>
class indexed_vector
{
template<typename T>
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 @@ public:
}
/*!
\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<T>::iterator begin()
{
virtual inline typename std::vector<T>::iterator begin() { return m_entries.begin(); }
virtual inline typename std::vector<T>::iterator end() { return m_entries.end(); }
virtual inline typename std::vector<T>::const_iterator begin() const {
return m_entries.begin();
}
virtual inline typename std::vector<T>::iterator end()
{
return m_entries.end();
}
virtual inline typename std::vector<T>::const_iterator begin() const
{
return m_entries.begin();
}
virtual inline typename std::vector<T>::const_iterator end() const
{
return m_entries.end();
}
virtual inline typename std::vector<T>::const_iterator end() const { return m_entries.end(); }
private:
std::vector<T> m_entries;

View File

@@ -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());

View File

@@ -22,28 +22,18 @@ limitations under the License.
#include <syslog.h>
#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);

View File

@@ -35,6 +35,12 @@ const char rule_schema_string[] = LONG_STRING_CONST(
"required_engine_version": {
"type": "string"
},
"required_plugin_versions": {
"type": "array",
"items": {
"$ref": "#/definitions/RequiredPluginVersion"
}
},
"macro": {
"type": "string"
},
@@ -68,6 +74,9 @@ const char rule_schema_string[] = LONG_STRING_CONST(
"priority": {
"$ref": "#/definitions/Priority"
},
"source": {
"type": "string"
},
"exceptions": {
"type": "array",
"items": {
@@ -166,6 +175,46 @@ const char rule_schema_string[] = LONG_STRING_CONST(
},
"minProperties": 1,
"title": "Override"
},
"RequiredPluginVersion": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"version": {
"type": "string"
},
"alternatives": {
"type": "array",
"items": {
"$ref": "#/definitions/Alternative"
}
}
},
"required": [
"name",
"version"
],
"title": "RequiredPluginVersion"
},
"Alternative": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"version": {
"type": "string"
}
},
"required": [
"name",
"version"
],
"title": "Alternative"
}
}
}

View File

@@ -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"};
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)
{
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 "<No context for file + " + loc.name + ">\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 "<No context available>\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 "<No context available>\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<std::string>& status)
{
void rule_loader::result::set_schema_validation_status(const std::vector<std::string>& 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();
}

View File

@@ -28,487 +28,473 @@ limitations under the License.
#include "indexed_vector.h"
#include <libsinsp/version.h>
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<location> 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;
static const std::string& item_type_as_string(enum item_type it);
falco::load_result::warning_code wc;
std::string msg;
context ctx;
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;
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;
falco::load_result::error_code ec;
std::string msg;
context ctx;
};
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();
const char* what() const noexcept override;
falco::load_result::error_code ec;
std::string msg;
context ctx;
};
/*!
\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<std::string>& 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<std::string> schema_validation_status;
std::vector<error> errors;
std::vector<warning> warnings;
std::string res_summary_string;
std::string res_verbose_string;
nlohmann::json res_json;
};
struct extra_output_format_conf
{
std::string m_format;
std::string m_source;
std::set<std::string> m_tags;
std::string m_rule;
bool m_replace_container_info;
};
struct extra_output_field_conf
{
std::string m_key;
std::string m_format;
std::string m_source;
std::set<std::string> m_tags;
std::string m_rule;
bool m_raw;
};
/*!
\brief Contains the info required to load rule definitions
*/
struct configuration
{
explicit configuration(
const std::string& cont,
const indexed_vector<falco_source>& srcs,
const std::string& name)
: content(cont), sources(srcs), name(name), res(std::make_unique<result>(name))
{
}
// inputs
const std::string& content;
const indexed_vector<falco_source>& sources;
// 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;
std::vector<extra_output_format_conf> extra_output_format;
std::vector<extra_output_field_conf> extra_output_fields;
// The original location in the document
position pos;
// outputs
std::unique_ptr<result> res;
// 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;
};
/*!
\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;
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);
context ctx;
sinsp_version version;
};
// 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);
/*!
\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;
virtual ~context() = default;
std::string name;
std::string version;
};
context(context&&) = default;
context& operator=(context&&) = default;
context(const context&) = default;
context& operator=(const context&) = default;
typedef std::vector<requirement> requirement_alternatives;
// Return the content name (generally filename) for
// this context
const std::string& name() const;
// 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;
// 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;
context ctx;
requirement_alternatives alternatives;
};
std::string as_string();
nlohmann::json as_json();
/*!
\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;
private:
void init(const std::string& name,
const position& pos,
const item_type item_type,
const std::string& item_name,
const context& parent);
context ctx;
size_t index;
size_t visibility;
std::string name;
std::vector<std::string> items;
};
// A chain of locations from the current item, its
// parent, possibly older ancestors.
std::vector<location> m_locs;
/*!
\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 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<entry>& 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<entry> 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<entry> values;
};
/*!
\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<std::string> tags;
std::vector<rule_exception_info> exceptions;
falco_common::priority_type priority;
bool enabled;
bool warn_evttypes;
bool 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<std::string> cond;
std::optional<std::string> output;
std::optional<std::string> desc;
std::optional<std::set<std::string>> tags;
std::optional<std::vector<rule_exception_info>> exceptions;
std::optional<falco_common::priority_type> priority;
std::optional<bool> enabled;
std::optional<bool> warn_evttypes;
std::optional<bool> skip_if_unknown_filter;
};
// If non-empty, this content will be used when
// creating snippets. Used for contexts involving
// condition expressions.
std::string alt_content;
};
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;
};
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;
};
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();
const char* what() const noexcept override;
falco::load_result::error_code ec;
std::string msg;
context ctx;
};
/*!
\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<std::string>& 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<std::string> schema_validation_status;
std::vector<error> errors;
std::vector<warning> warnings;
std::string res_summary_string;
std::string res_verbose_string;
nlohmann::json res_json;
};
struct extra_output_format_conf {
std::string m_format;
std::string m_source;
std::set<std::string> m_tags;
std::string m_rule;
bool m_replace_container_info;
};
struct extra_output_field_conf {
std::string m_key;
std::string m_format;
std::string m_source;
std::set<std::string> m_tags;
std::string m_rule;
bool m_raw;
};
/*!
\brief Contains the info required to load rule definitions
*/
struct configuration {
explicit configuration(const std::string& cont,
const indexed_vector<falco_source>& srcs,
const std::string& name):
content(cont),
sources(srcs),
name(name),
res(std::make_unique<result>(name)) {}
// inputs
const std::string& content;
const indexed_vector<falco_source>& sources;
std::string name;
std::vector<extra_output_format_conf> extra_output_format;
std::vector<extra_output_field_conf> extra_output_fields;
// outputs
std::unique_ptr<result> res;
};
/*!
\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 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> 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<std::string> 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 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<entry>& 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<entry> 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<entry> values;
};
/*!
\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<std::string> tags;
std::vector<rule_exception_info> exceptions;
falco_common::priority_type priority;
bool enabled;
bool warn_evttypes;
bool 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<std::string> cond;
std::optional<std::string> output;
std::optional<std::string> desc;
std::optional<std::set<std::string>> tags;
std::optional<std::vector<rule_exception_info>> exceptions;
std::optional<falco_common::priority_type> priority;
std::optional<bool> enabled;
std::optional<bool> warn_evttypes;
std::optional<bool> skip_if_unknown_filter;
};
}; // namespace rule_loader

View File

@@ -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 <typename T>
static inline void define_info(indexed_vector<T>& infos, T& info, uint32_t id)
{
template<typename T>
static inline void define_info(indexed_vector<T>& 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 <typename T, typename U>
static inline void append_info(T* prev, U& info, uint32_t id)
{
template<typename T, typename U>
static inline void append_info(T* prev, U& info, uint32_t id) {
prev->visibility = id;
}
template <typename T, typename U>
static inline void replace_info(T* prev, U& info, uint32_t id)
{
template<typename T, typename U>
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::plugin_version_info::requirement_alternatives>& rule_loader::collector::required_plugin_versions() const
{
const std::vector<rule_loader::plugin_version_info::requirement_alternatives>&
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::list_info>& rule_loader::collector::lists() const
{
const indexed_vector<rule_loader::list_info>& rule_loader::collector::lists() const {
return m_list_infos;
}
const indexed_vector<rule_loader::macro_info>& rule_loader::collector::macros() const
{
const indexed_vector<rule_loader::macro_info>& rule_loader::collector::macros() const {
return m_macro_infos;
}
const indexed_vector<rule_loader::rule_info>& rule_loader::collector::rules() const
{
const indexed_vector<rule_loader::rule_info>& 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<std::string> 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;
}

View File

@@ -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<plugin_version_info::requirement_alternatives>& required_plugin_versions() const;
virtual const std::vector<plugin_version_info::requirement_alternatives>&
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<list_info>& lists() const;
/*!
\brief Returns the list of defined macros
\brief Returns the list of defined macros
*/
virtual const indexed_vector<macro_info>& macros() const;
/*!
\brief Returns the list of defined rules
\brief Returns the list of defined rules
*/
virtual const indexed_vector<rule_info>& 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 @@ public:
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 @@ private:
engine_version_info m_required_engine_version;
};
}; // namespace rule_loader
}; // namespace rule_loader

View File

@@ -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;
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<falco_list> lists;
indexed_vector<falco_macro> macros;
indexed_vector<falco_rule> rules;
};
indexed_vector<falco_list> lists;
indexed_vector<falco_macro> macros;
indexed_vector<falco_rule> rules;
};
}; // namespace rule_loader

View File

@@ -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 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 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<sinsp_evt_formatter> 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<rule_loader::rule_exception_info>& exceptions,
std::set<std::string>& exception_fields,
std::string& condition)
{
const std::vector<rule_loader::rule_exception_info>& exceptions,
std::set<std::string>& 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<rule_loader::macro_info>& infos,
indexed_vector<falco_macro>& macros,
std::shared_ptr<ast::expr>& 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<rule_loader::macro_info>& infos,
indexed_vector<falco_macro>& macros,
std::shared_ptr<ast::expr>& 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<ast::expr> parse_condition(
std::string condition,
indexed_vector<falco_list>& lists,
const rule_loader::context &ctx)
{
for (auto &l : lists)
{
if (resolve_list(condition, l))
{
static std::shared_ptr<ast::expr> parse_condition(std::string condition,
indexed_vector<falco_list>& 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<ast::expr> 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<falco_list>& out) const
{
void rule_loader::compiler::compile_list_infos(configuration& cfg,
const collector& col,
indexed_vector<falco_list>& out) const {
std::list<std::string> 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<falco_list>& lists,
indexed_vector<falco_macro>& out) const
{
for (const auto &m : col.macros())
{
void rule_loader::compiler::compile_macros_infos(configuration& cfg,
const collector& col,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& 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<falco_list>& lists,
const indexed_vector<rule_loader::macro_info>& macros,
const std::string& condition,
std::shared_ptr<sinsp_filter_factory> filter_factory,
const rule_loader::context& cond_ctx,
const rule_loader::context& parent_ctx,
bool allow_unknown_fields,
indexed_vector<falco_macro>& macros_out,
std::shared_ptr<libsinsp::filter::ast::expr>& ast_out,
std::shared_ptr<sinsp_filter>& filter_out) const
{
bool rule_loader::compiler::compile_condition(configuration& cfg,
filter_macro_resolver& macro_resolver,
indexed_vector<falco_list>& lists,
const indexed_vector<rule_loader::macro_info>& macros,
const std::string& condition,
std::shared_ptr<sinsp_filter_factory> filter_factory,
const rule_loader::context& cond_ctx,
const rule_loader::context& parent_ctx,
bool allow_unknown_fields,
indexed_vector<falco_macro>& macros_out,
std::shared_ptr<libsinsp::filter::ast::expr>& ast_out,
std::shared_ptr<sinsp_filter>& filter_out) const {
std::set<falco::load_result::load_result::warning_code> 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<falco_list>& lists,
indexed_vector<falco_macro>& macros,
indexed_vector<falco_rule>& out) const
{
void rule_loader::compiler::compile_rule_infos(configuration& cfg,
const collector& col,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& macros,
indexed_vector<falco_rule>& 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::compile_output> rule_loader::compiler::new_compile_output()
{
std::unique_ptr<rule_loader::compile_output> rule_loader::compiler::new_compile_output() {
return std::make_unique<compile_output>();
}
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);
}
}
}

View File

@@ -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<compile_output> new_compile_output();
virtual std::unique_ptr<compile_output> 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;
protected:
/*!
\brief Compile a single condition expression,
including expanding macro and list references.
virtual void compile(configuration& cfg, const collector& col, compile_output& 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<falco_list>& lists,
const indexed_vector<rule_loader::macro_info>& macros,
const std::string& condition,
std::shared_ptr<sinsp_filter_factory> filter_factory,
const rule_loader::context& cond_ctx,
const rule_loader::context& parent_ctx,
bool allow_unknown_fields,
indexed_vector<falco_macro>& macros_out,
std::shared_ptr<libsinsp::filter::ast::expr>& ast_out,
std::shared_ptr<sinsp_filter>& filter_out) const;
protected:
/*!
\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<falco_list>& lists,
const indexed_vector<rule_loader::macro_info>& macros,
const std::string& condition,
std::shared_ptr<sinsp_filter_factory> filter_factory,
const rule_loader::context& cond_ctx,
const rule_loader::context& parent_ctx,
bool allow_unknown_fields,
indexed_vector<falco_macro>& macros_out,
std::shared_ptr<libsinsp::filter::ast::expr>& ast_out,
std::shared_ptr<sinsp_filter>& filter_out) const;
private:
void compile_list_infos(
configuration& cfg,
const collector& col,
indexed_vector<falco_list>& out) const;
void compile_list_infos(configuration& cfg,
const collector& col,
indexed_vector<falco_list>& out) const;
void compile_macros_infos(
configuration& cfg,
const collector& col,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& out) const;
void compile_macros_infos(configuration& cfg,
const collector& col,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& out) const;
void compile_rule_infos(
configuration& cfg,
const collector& col,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& macros,
indexed_vector<falco_rule>& out) const;
void compile_rule_infos(configuration& cfg,
const collector& col,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& macros,
indexed_vector<falco_rule>& out) const;
};
}; // namespace rule_loader
}; // namespace rule_loader

File diff suppressed because it is too large Load Diff

View File

@@ -23,53 +23,55 @@ limitations under the License.
#include <libsinsp/version.h>
#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 <typename T>
static void decode_val(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx);
template<typename T>
static void decode_val(const YAML::Node& item,
const char* key,
T& out,
const rule_loader::context& ctx);
template <typename T>
static void decode_optional_val(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx);
template<typename T>
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

View File

@@ -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.<key>: append' but no rule by that name already exists"
#define ERROR_NO_PREVIOUS_RULE_APPEND \
"Rule uses 'append' or 'override.<key>: append' but no rule by that name already exists"
#define ERROR_NO_PREVIOUS_RULE_REPLACE "An 'override.<key>: replace' to a rule was requested but no rule by that name already exists"
#define ERROR_NO_PREVIOUS_RULE_REPLACE \
"An 'override.<key>: replace' to a rule was requested but no rule by that name already exists"

View File

@@ -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<falco_rule>& rules,
std::string& out) const
{
void stats_manager::format(const indexed_vector<falco_rule>& 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<std::atomic<uint64_t>>(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<std::atomic<uint64_t>>(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);
}

View File

@@ -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<falco_rule>& rules,
std::string& out) const;
virtual void format(const indexed_vector<falco_rule>& rules, std::string& out) const;
// Getter functions
inline const std::atomic<uint64_t>& get_total() const
{
return m_total;
}
inline const std::atomic<uint64_t>& get_total() const { return m_total; }
inline const std::vector<std::unique_ptr<std::atomic<uint64_t>>>& get_by_priority() const
{
inline const std::vector<std::unique_ptr<std::atomic<uint64_t>>>& get_by_priority() const {
return m_by_priority;
}
inline const std::vector<std::unique_ptr<std::atomic<uint64_t>>>& get_by_rule_id() const
{
inline const std::vector<std::unique_ptr<std::atomic<uint64_t>>>& get_by_rule_id() const {
return m_by_rule_id;
}
private:
std::atomic<uint64_t> m_total;
std::vector<std::unique_ptr<std::atomic<uint64_t>>> m_by_priority;

View File

@@ -48,23 +48,23 @@ private:
using Callback = std::function<void(YAML::Node&)>;
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 @@ private:
/**
* @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 @@ public:
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<YAML::Node> loadall_from_string(const std::string& input, const nlohmann::json& schema={}, std::vector<std::string> *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<YAML::Node> loadall_from_string(
const std::string& input,
const nlohmann::json& schema = {},
std::vector<std::string>* 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 @@ public:
}
/**
* Load the YAML document represented by the input string.
*/
void load_from_string(const std::string& input, const nlohmann::json& schema={}, std::vector<std::string> *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<std::string>* 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<std::string> *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<std::string>* 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<std::string> *schema_warnings=nullptr)
{
void include_config_file(const std::string& include_file_path,
const nlohmann::json& schema = {},
std::vector<std::string>* 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 @@ public:
/**
* 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<typename T>
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<T>(default_value);
}
return default_value;
@@ -192,8 +181,7 @@ public:
* Set the node identified by key to value.
*/
template<typename T>
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 @@ public:
/**
* 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<typename T>
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<T>(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<std::string> *schema_warnings)
{
YAML::Node load_from_file_int(const std::string& path,
const nlohmann::json& schema,
std::vector<std::string>* 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<std::string> *schema_warnings)
{
void validate_node(const YAML::Node& node,
const nlohmann::json& schema,
std::vector<std::string>* schema_warnings) {
// Validate the yaml against our json schema
valijson::Schema schemaDef;
valijson::SchemaParser schemaParser;
@@ -271,20 +253,17 @@ private:
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 @@ private:
* 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<std::string>();
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;
void pre_process_env_vars(YAML::Node& root) {
yaml_visitor([](YAML::Node& scalar) {
auto value = scalar.as<std::string>();
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;
}
start_pos++; // consume the second '$' token
}
else
{
start_pos += substr.length();
}
start_pos = value.find("$", start_pos);
}
scalar = value;
})(root);
// 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++; // consume the second '$' token
} else {
start_pos += substr.length();
}
start_pos = value.find("$", start_pos);
}
scalar = value;
})(root);
}
/**
@@ -365,101 +332,79 @@ private:
*
* 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<typename T>
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<typename T::value_type>());
}
}
else if(node.IsScalar())
{
} else if(node.IsScalar()) {
ret.insert(ret.end(), node.as<typename T::value_type>());
}
}
@@ -468,55 +413,45 @@ private:
// define a yaml-cpp conversion function for nlohmann json objects
namespace YAML {
template<>
struct convert<nlohmann::json> {
static bool decode(const Node& node, nlohmann::json& res)
{
int int_val;
double double_val;
bool bool_val;
std::string str_val;
template<>
struct convert<nlohmann::json> {
static bool decode(const Node& node, nlohmann::json& res) {
int int_val;
double double_val;
bool bool_val;
std::string str_val;
switch (node.Type()) {
case YAML::NodeType::Map:
for (auto &&it: node)
{
nlohmann::json sub{};
YAML::convert<nlohmann::json>::decode(it.second, sub);
res[it.first.as<std::string>()] = sub;
}
break;
case YAML::NodeType::Sequence:
for (auto &&it : node)
{
nlohmann::json sub{};
YAML::convert<nlohmann::json>::decode(it, sub);
res.emplace_back(sub);
}
break;
case YAML::NodeType::Scalar:
if (YAML::convert<int>::decode(node, int_val))
{
res = int_val;
}
else if (YAML::convert<double>::decode(node, double_val))
{
res = double_val;
}
else if (YAML::convert<bool>::decode(node, bool_val))
{
res = bool_val;
}
else if (YAML::convert<std::string>::decode(node, str_val))
{
res = str_val;
}
default:
break;
switch(node.Type()) {
case YAML::NodeType::Map:
for(auto&& it : node) {
nlohmann::json sub{};
YAML::convert<nlohmann::json>::decode(it.second, sub);
res[it.first.as<std::string>()] = sub;
}
return true;
break;
case YAML::NodeType::Sequence:
for(auto&& it : node) {
nlohmann::json sub{};
YAML::convert<nlohmann::json>::decode(it, sub);
res.emplace_back(sub);
}
break;
case YAML::NodeType::Scalar:
if(YAML::convert<int>::decode(node, int_val)) {
res = int_val;
} else if(YAML::convert<double>::decode(node, double_val)) {
res = double_val;
} else if(YAML::convert<bool>::decode(node, bool_val)) {
res = bool_val;
} else if(YAML::convert<std::string>::decode(node, str_val)) {
res = str_val;
}
default:
break;
}
// 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

View File

@@ -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
)
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}"
)
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()
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}"
)
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
"$<TARGET_FILE_DIR:falco>/falco.js"
"$<TARGET_FILE_DIR:falco>/falco.wasm"
if(EMSCRIPTEN)
install(
FILES "$<TARGET_FILE_DIR:falco>/falco.js" "$<TARGET_FILE_DIR:falco>/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()

View File

@@ -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

View File

@@ -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();
}
}

Some files were not shown because too many files have changed in this diff Show More