Compare commits

..

1 Commits

Author SHA1 Message Date
Luca Guerra
74a0882244 test update
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-26 13:09:05 +01:00
116 changed files with 1249 additions and 3681 deletions

View File

@@ -16,22 +16,12 @@ jobs:
fetch-version:
uses: ./.github/workflows/reusable_fetch_version.yaml
build-dev-packages-sanitizers-x86_64:
build-dev-packages:
needs: [fetch-version]
uses: ./.github/workflows/reusable_build_packages.yaml
with:
arch: x86_64
version: ${{ needs.fetch-version.outputs.version }}
build_type: Debug
sanitizers: true
build-dev-packages-x86_64:
needs: [fetch-version]
uses: ./.github/workflows/reusable_build_packages.yaml
with:
arch: x86_64
version: ${{ needs.fetch-version.outputs.version }}
build_type: Release
build-dev-packages-arm64:
needs: [fetch-version]
@@ -39,11 +29,9 @@ jobs:
with:
arch: aarch64
version: ${{ needs.fetch-version.outputs.version }}
build_type: Debug
sanitizers: false
test-dev-packages:
needs: [fetch-version, build-dev-packages-sanitizers-x86_64]
needs: [fetch-version, build-dev-packages]
uses: ./.github/workflows/reusable_test_packages.yaml
# The musl build job is currently disabled because we link libelf dynamically and it is
# not possible to dynamically link with musl
@@ -53,7 +41,6 @@ jobs:
# static: ["static", ""]
with:
arch: x86_64
sanitizers: true
# static: ${{ matrix.static != '' && true || false }}
version: ${{ needs.fetch-version.outputs.version }}
@@ -95,7 +82,6 @@ jobs:
arch: x86_64
git_ref: ${{ github.event.pull_request.head.sha }}
minimal: false
sanitizers: true
build_type: Debug
cmd: "echo $(build/userspace/falco/falco -c ./falco.yaml --version | grep 'Engine:' | awk '{print $2}') $(echo $(build/userspace/falco/falco -c ./falco.yaml --version | grep 'Schema version:' | awk '{print $3}') $(build/userspace/falco/falco -c ./falco.yaml --list --markdown | grep '^`' | sort) $(build/userspace/falco/falco -c ./falco.yaml --list-events | sort) | sha256sum)"

View File

@@ -21,7 +21,7 @@ on:
jobs:
analyze:
name: Analyze
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
permissions:
actions: read
contents: read
@@ -42,7 +42,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -60,11 +60,16 @@ jobs:
- name: Prepare project
run: |
cmake -B build -S . -DBUILD_BPF=On -DBUILD_FALCO_MODERN_BPF=Off -DUSE_BUNDLED_DEPS=Off -DUSE_BUNDLED_NLOHMANN_JSON=On -DUSE_BUNDLED_CXXOPTS=On -DUSE_BUNDLED_CPPHTTPLIB=On
mkdir build
pushd build
cmake -DBUILD_BPF=On ..
popd
- name: Build
run: |
KERNELDIR=/lib/modules/$(uname -r)/build cmake --build build -j4
pushd build
KERNELDIR=/lib/modules/$(uname -r)/build make -j4 all
popd
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9

View File

@@ -14,11 +14,6 @@ on:
description: Minimal build
required: true
type: boolean
sanitizers:
description: Enable sanitizer support
required: false
default: false
type: boolean
build_type:
description: One of 'Debug' or 'Release'
required: true
@@ -58,23 +53,22 @@ jobs:
- name: Prepare project
run: |
cmake -B build -S .\
mkdir build
pushd build
cmake \
-DBUILD_FALCO_UNIT_TESTS=On \
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \
-DBUILD_FALCO_MODERN_BPF=Off \
-DBUILD_BPF=${{ inputs.minimal == true && 'OFF' || 'ON' }} \
-DBUILD_DRIVER=${{ inputs.minimal == true && 'OFF' || 'ON' }} \
-DMINIMAL_BUILD=${{ inputs.minimal == true && 'ON' || 'OFF' }} \
-DUSE_ASAN=${{ inputs.sanitizers == true && 'ON' || 'OFF' }} \
-DUSE_UBSAN=${{ inputs.sanitizers == true && 'ON' || 'OFF' }} \
-DUSE_BUNDLED_DEPS=Off \
-DUSE_BUNDLED_NLOHMANN_JSON=On \
-DUSE_BUNDLED_CXXOPTS=On \
-DUSE_BUNDLED_CPPHTTPLIB=On \
..
popd
- name: Build
run: |
KERNELDIR=/lib/modules/$(uname -r)/build cmake --build build -j4
pushd build
KERNELDIR=/lib/modules/$(uname -r)/build make -j4 all
popd
- name: Run unit tests
run: |

View File

@@ -10,16 +10,6 @@ on:
description: The Falco version to use when building packages
required: true
type: string
build_type:
description: The build type
required: false
type: string
default: 'Release'
sanitizers:
description: enable sanitizer support
required: false
type: boolean
default: false
jobs:
build-modern-bpf-skeleton:
@@ -31,23 +21,23 @@ jobs:
- name: Install build dependencies
run: |
dnf install -y bpftool ca-certificates cmake make automake gcc gcc-c++ kernel-devel clang git pkg-config autoconf automake libbpf-devel elfutils-libelf-devel
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Build modern BPF skeleton
run: |
cmake -B skeleton-build -S . \
-DUSE_BUNDLED_DEPS=ON -DCREATE_TEST_TARGETS=Off -DFALCO_VERSION=${{ inputs.version }}
cmake --build skeleton-build --target ProbeSkeleton -j6
mkdir skeleton-build && cd skeleton-build
cmake -DUSE_BUNDLED_DEPS=ON -DBUILD_FALCO_MODERN_BPF=ON -DCREATE_TEST_TARGETS=Off -DFALCO_VERSION=${{ inputs.version }} ..
make ProbeSkeleton -j6
- name: Upload skeleton
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: bpf_probe_${{ inputs.arch }}.skel.h
path: skeleton-build/skel_dir/bpf_probe.skel.h
retention-days: 1
build-packages:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-latest' }}
@@ -60,73 +50,80 @@ jobs:
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++
source /opt/rh/devtoolset-9/enable
yum install -y wget git make m4 rpm-build elfutils-libelf-devel perl-IPC-Cmd devtoolset-9-libasan-devel devtoolset-9-libubsan-devel
yum install -y wget git make m4 rpm-build elfutils-libelf-devel perl-IPC-Cmd
- name: Checkout
# It is not possible to upgrade the checkout action to versions >= v4.0.0 because of incompatibilities with centos 7's libc.
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Download skeleton
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: bpf_probe_${{ inputs.arch }}.skel.h
path: /tmp
- name: Install updated cmake
run: |
curl -L https://github.com/Kitware/CMake/releases/download/v3.22.5/cmake-3.22.5-linux-$(uname -m).tar.gz \
| tar --directory=/usr --strip-components=1 -xzp
curl -L -o /tmp/cmake.tar.gz https://github.com/Kitware/CMake/releases/download/v3.22.5/cmake-3.22.5-linux-$(uname -m).tar.gz
gzip -d /tmp/cmake.tar.gz
tar -xpf /tmp/cmake.tar --directory=/tmp
cp -R /tmp/cmake-3.22.5-linux-$(uname -m)/* /usr
rm -rf /tmp/cmake-3.22.5-linux-$(uname -m)
- name: Prepare project
run: |
mkdir build && cd build
source /opt/rh/devtoolset-9/enable
cmake -B build -S . \
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_BUNDLED_DEPS=On \
-DFALCO_ETC_DIR=/etc/falco \
-DBUILD_FALCO_MODERN_BPF=ON \
-DMODERN_BPF_SKEL_DIR=/tmp \
-DBUILD_DRIVER=Off \
-DBUILD_BPF=Off \
-DUSE_ASAN=${{ (inputs.sanitizers == true && inputs.arch == 'x86_64' && 'ON') || 'OFF' }} \
-DFALCO_VERSION=${{ inputs.version }}
-DFALCO_VERSION=${{ inputs.version }} \
..
- name: Build project
run: |
cd build
source /opt/rh/devtoolset-9/enable
cmake --build build --target falco -j6
make falco -j6
- name: Build packages
run: |
cd build
source /opt/rh/devtoolset-9/enable
cmake --build build --target package
make package
- name: Upload Falco tar.gz package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}${{ inputs.sanitizers == true && '-sanitizers' || '' }}.tar.gz
name: falco-${{ inputs.version }}-${{ inputs.arch }}.tar.gz
path: |
${{ github.workspace }}/build/falco-*.tar.gz
- name: Upload Falco deb package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}${{ inputs.sanitizers == true && '-sanitizers' || '' }}.deb
name: falco-${{ inputs.version }}-${{ inputs.arch }}.deb
path: |
${{ github.workspace }}/build/falco-*.deb
- name: Upload Falco rpm package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}${{ inputs.sanitizers == true && '-sanitizers' || '' }}.rpm
name: falco-${{ inputs.version }}-${{ inputs.arch }}.rpm
path: |
${{ github.workspace }}/build/falco-*.rpm
# The musl build job is currently disabled because we link libelf dynamically and it is
# not possible to dynamically link with musl
build-musl-package:
# x86_64 only for now
# if: ${{ inputs.arch == 'x86_64' }}
if: false
if: false
runs-on: ubuntu-latest
container: alpine:3.17
steps:
@@ -134,33 +131,32 @@ jobs:
- name: Install build dependencies
run: |
apk add g++ gcc cmake make git bash perl linux-headers autoconf automake m4 libtool elfutils-dev libelf-static patch binutils bpftool clang
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Prepare project
run: |
cmake -B build -S . \
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \
-DCPACK_GENERATOR=TGZ \
-DBUILD_BPF=Off -DBUILD_DRIVER=Off \
-DUSE_BUNDLED_DEPS=On -DUSE_BUNDLED_LIBELF=Off -DBUILD_LIBSCAP_MODERN_BPF=ON -DMUSL_OPTIMIZED_BUILD=On -DFALCO_ETC_DIR=/etc/falco -DFALCO_VERSION=${{ inputs.version }}
mkdir build && cd build
cmake -DCPACK_GENERATOR=TGZ -DBUILD_BPF=Off -DBUILD_DRIVER=Off -DCMAKE_BUILD_TYPE=Release -DUSE_BUNDLED_DEPS=On -DUSE_BUNDLED_LIBELF=Off -DBUILD_LIBSCAP_MODERN_BPF=ON -DMUSL_OPTIMIZED_BUILD=On -DFALCO_ETC_DIR=/etc/falco ../ -DFALCO_VERSION=${{ inputs.version }}
- name: Build project
run: |
cmake --build build -j6
cd build
make -j6 all
- name: Build packages
run: |
cmake --build build -j6 --target package
cd build
make -j6 package
- name: Rename static package
run: |
cd build
mv falco-${{ inputs.version }}-x86_64.tar.gz falco-${{ inputs.version }}-static-x86_64.tar.gz
mv falco-${{ inputs.version }}-x86_64.tar.gz falco-${{ inputs.version }}-static-x86_64.tar.gz
- name: Upload Falco static package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
@@ -182,39 +178,41 @@ jobs:
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Prepare project
run: |
emcmake cmake -B build -S . \
mkdir build && cd build
emcmake cmake \
-DBUILD_BPF=Off \
-DBUILD_DRIVER=Off \
-DBUILD_FALCO_MODERN_BPF=Off \
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \
-DBUILD_LIBSCAP_MODERN_BPF=OFF \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_BUNDLED_DEPS=On \
-DFALCO_ETC_DIR=/etc/falco \
-DBUILD_FALCO_UNIT_TESTS=On \
-DFALCO_VERSION=${{ inputs.version }}
-DFALCO_VERSION=${{ inputs.version }} \
..
- name: Build project
run: |
cd build
emmake make -j6 all
- name: Run unit Tests
run: |
cd build
node ./unit_tests/falco_unit_tests.js
- name: Build packages
run: |
cd build
emmake make -j6 package
- name: Upload Falco WASM package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
@@ -231,18 +229,19 @@ jobs:
with:
fetch-depth: 0
# NOTE: Backslash doesn't work as line continuation on Windows.
- name: Prepare project
run: |
cmake -B build -S . -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DMINIMAL_BUILD=On -DUSE_BUNDLED_DEPS=On -DBUILD_FALCO_UNIT_TESTS=On -DFALCO_VERSION=${{ inputs.version }}
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DMINIMAL_BUILD=On -DUSE_BUNDLED_DEPS=On -DBUILD_FALCO_UNIT_TESTS=On -DFALCO_VERSION=${{ inputs.version }} ..
- name: Build project
run: |
cmake --build build --target package --config ${{ inputs.build_type }}
cmake --build build --target package --config Release
- name: Run unit Tests
run: |
build/unit_tests/${{ inputs.build_type }}/falco_unit_tests.exe
build/unit_tests/Release/falco_unit_tests.exe
- name: Upload Falco win32 installer
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
@@ -255,7 +254,7 @@ jobs:
with:
name: falco-${{ inputs.version }}-win32.exe
path: |
${{ github.workspace }}/build/userspace/falco/${{ inputs.build_type }}/falco.exe
${{ github.workspace }}/build/userspace/falco/Release/falco.exe
build-macos-package:
if: ${{ inputs.arch == 'x86_64' }}
@@ -268,8 +267,9 @@ jobs:
- name: Prepare project
run: |
cmake -B build -S . \
-DMINIMAL_BUILD=On -DUSE_BUNDLED_DEPS=On -DBUILD_FALCO_UNIT_TESTS=On -DFALCO_VERSION=${{ inputs.version }}
mkdir build
cd build
cmake -DMINIMAL_BUILD=On -DUSE_BUNDLED_DEPS=On -DBUILD_FALCO_UNIT_TESTS=On -DFALCO_VERSION=${{ inputs.version }} ..
- name: Build project
run: |

View File

@@ -5,33 +5,34 @@ on:
version:
description: "Falco version"
value: ${{ jobs.fetch-version.outputs.version }}
jobs:
# We need to use an ubuntu-latest to fetch Falco version because
# Falco version is computed by some cmake scripts that do git sorceries
# to get the current version.
# But centos7 jobs have a git version too old and actions/checkout does not
# But centos7 jobs have a git version too old and actions/checkout does not
# fully clone the repo, but uses http rest api instead.
fetch-version:
runs-on: ubuntu-latest
# Map the job outputs to step outputs
outputs:
version: ${{ steps.store_version.outputs.version }}
version: ${{ steps.store_version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Install build dependencies
run: |
sudo apt update
sudo apt update
sudo apt install -y cmake build-essential
- name: Configure project
run: |
cmake -B build -S . -DUSE_BUNDLED_DEPS=On -DUSE_DYNAMIC_LIBELF=Off
mkdir build && cd build
cmake -DUSE_BUNDLED_DEPS=On -DUSE_DYNAMIC_LIBELF=Off ..
- name: Load and store Falco version output
id: store_version
run: |

View File

@@ -152,7 +152,9 @@ jobs:
- name: Setup Cosign
if: inputs.sign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2
with:
cosign-release: v2.0.2
- name: Sign images with cosign
if: inputs.sign

View File

@@ -15,11 +15,6 @@ on:
description: The Falco version to use when testing packages
required: true
type: string
sanitizers:
description: Use sanitizer enabled build
required: false
default: false
type: boolean
jobs:
test-packages:
@@ -29,7 +24,7 @@ jobs:
- name: Download binary
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}${{ inputs.static && '-static' || '' }}-${{ inputs.arch }}${{ inputs.sanitizers == true && '-sanitizers' || '' }}.tar.gz
name: falco-${{ inputs.version }}${{ inputs.static && '-static' || '' }}-${{ inputs.arch }}.tar.gz
- name: Install Falco package
run: |
@@ -44,16 +39,8 @@ jobs:
run: |
sudo apt update -y
sudo apt install -y --no-install-recommends linux-headers-$(uname -r)
# Some builds use sanitizers, we always install support for them so they can run
- name: Install sanitizer support
run: |
sudo apt update -y
sudo apt install -y libasan5 libubsan1
- name: Run tests
env:
LSAN_OPTIONS: "intercept_tls_get_addr=0"
uses: falcosecurity/testing@main
with:
test-falco: 'true'

View File

@@ -43,7 +43,7 @@ jobs:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2
with:
results_file: results.sarif
results_format: sarif

View File

@@ -19,11 +19,10 @@ jobs:
- name: Build and run cppcheck 🏎️
run: |
cmake -B build -S . \
-DCMAKE_BUILD_TYPE="release" \
-DUSE_BUNDLED_DEPS=On -DUSE_DYNAMIC_LIBELF=Off -DBUILD_WARNINGS_AS_ERRORS=ON -DCREATE_TEST_TARGETS=Off -DBUILD_BPF=Off -DBUILD_DRIVER=Off
cmake --build build -j4 --target cppcheck
cmake --build build -j4 --target cppcheck_htmlreport
mkdir build
cd build && cmake -DUSE_BUNDLED_DEPS=On -DUSE_DYNAMIC_LIBELF=Off -DBUILD_WARNINGS_AS_ERRORS=ON -DCREATE_TEST_TARGETS=Off -DCMAKE_BUILD_TYPE="release" -DBUILD_BPF=Off -DBUILD_DRIVER=Off ..
make -j4 cppcheck
make -j4 cppcheck_htmlreport
- name: Upload reports ⬆️
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3

View File

@@ -1,141 +1,5 @@
# Change Log
## v0.38.0
Released on 2024-05-30
### Breaking Changes :warning:
* new(scripts,docker)!: enable automatic driver selection logic in packages and docker images. Modern eBPF is now also the default driver and the highest priority one in the new driver selection logic. [[#3154](https://github.com/falcosecurity/falco/pull/3154)] - [@FedeDP](https://github.com/FedeDP)
* cleanup(falco.yaml)!: remove some deprecated configs [[#3087](https://github.com/falcosecurity/falco/pull/3087)] - [@Andreagit97](https://github.com/Andreagit97)
* cleanup(docker)!: remove unused builder dockerfile [[#3088](https://github.com/falcosecurity/falco/pull/3088)] - [@Andreagit97](https://github.com/Andreagit97)
More details: https://falco.org/blog/falco-0-38-0/#breaking-changes-and-deprecations
### Major Changes
* new(webserver): a metrics endpoint has been added providing prometheus metrics. It can be optionally enabled using the new `metrics.prometheus_enabled` configuration option. It will only be activated if the `metrics.enabled` is true as well. [[#3140](https://github.com/falcosecurity/falco/pull/3140)] - [@sgaist](https://github.com/sgaist)
* new(metrics): add `rules_counters_enabled` option [[#3192](https://github.com/falcosecurity/falco/pull/3192)] - [@incertum](https://github.com/incertum)
* new(build): provide signatures for .tar.gz packages [[#3201](https://github.com/falcosecurity/falco/pull/3201)] - [@LucaGuerra](https://github.com/LucaGuerra)
* new(engine): add print_enabled_rules_falco_logger when log_level debug [[#3189](https://github.com/falcosecurity/falco/pull/3189)] - [@incertum](https://github.com/incertum)
* new(falco): allow selecting which rules to load from the configuration file or command line [[#3178](https://github.com/falcosecurity/falco/pull/3178)] - [@LucaGuerra](https://github.com/LucaGuerra)
* new(metrics): add file sha256sum metrics for loaded config and rules files [[#3187](https://github.com/falcosecurity/falco/pull/3187)] - [@incertum](https://github.com/incertum)
* new(engine): throw an error when an invalid macro/list name is used [[#3116](https://github.com/falcosecurity/falco/pull/3116)] - [@mrgian](https://github.com/mrgian)
* new(engine): raise warning instead of error on invalid macro/list name [[#3167](https://github.com/falcosecurity/falco/pull/3167)] - [@mrgian](https://github.com/mrgian)
* new(userspace): support split config files [[#3024](https://github.com/falcosecurity/falco/pull/3024)] - [@FedeDP](https://github.com/FedeDP)
* new(engine): enforce unique exceptions names [[#3134](https://github.com/falcosecurity/falco/pull/3134)] - [@mrgian](https://github.com/mrgian)
* new(engine): add warning when appending an exception with no values [[#3133](https://github.com/falcosecurity/falco/pull/3133)] - [@mrgian](https://github.com/mrgian)
* feat(metrics): coherent metrics stats model including few metrics naming changes [[#3129](https://github.com/falcosecurity/falco/pull/3129)] - [@incertum](https://github.com/incertum)
* new(config): add `falco_libs.thread_table_size` [[#3071](https://github.com/falcosecurity/falco/pull/3071)] - [@incertum](https://github.com/incertum)
* new(proposals): introduce on host anomaly detection framework [[#2655](https://github.com/falcosecurity/falco/pull/2655)] - [@incertum](https://github.com/incertum)
### Minor Changes
* update(cmake): bump falcoctl to v0.8.0. [[#3219](https://github.com/falcosecurity/falco/pull/3219)] - [@FedeDP](https://github.com/FedeDP)
* update(rules): update falco-rules to 3.1.0 [[#3217](https://github.com/falcosecurity/falco/pull/3217)] - [@LucaGuerra](https://github.com/LucaGuerra)
* refactor(userspace): move falco logger under falco engine [[#3208](https://github.com/falcosecurity/falco/pull/3208)] - [@jasondellaluce](https://github.com/jasondellaluce)
* chore(docs): apply features adoption and deprecation proposal to config file keys [[#3206](https://github.com/falcosecurity/falco/pull/3206)] - [@FedeDP](https://github.com/FedeDP)
* cleanup(metrics): add original rule name as label [[#3205](https://github.com/falcosecurity/falco/pull/3205)] - [@incertum](https://github.com/incertum)
* update(falco): deprecate options -T, -t and -D [[#3193](https://github.com/falcosecurity/falco/pull/3193)] - [@LucaGuerra](https://github.com/LucaGuerra)
* refactor: bump libs and driver, support field modifiers [[#3186](https://github.com/falcosecurity/falco/pull/3186)] - [@jasondellaluce](https://github.com/jasondellaluce)
* chore(userspace/falco): deprecated old 'rules_file' config key [[#3162](https://github.com/falcosecurity/falco/pull/3162)] - [@FedeDP](https://github.com/FedeDP)
* chore(falco): update falco libs and driver to master (Apr 8th 2024) [[#3158](https://github.com/falcosecurity/falco/pull/3158)] - [@LucaGuerra](https://github.com/LucaGuerra)
* update(build): update libs to 026ffe1d8f1b25c6ccdc09afa2c02afdd3e3f672 [[#3151](https://github.com/falcosecurity/falco/pull/3151)] - [@LucaGuerra](https://github.com/LucaGuerra)
* cleanup: minor adjustments to readme, add new testing section [[#3072](https://github.com/falcosecurity/falco/pull/3072)] - [@incertum](https://github.com/incertum)
* refactor(userspace/engine): reduce allocations during rules loading [[#3065](https://github.com/falcosecurity/falco/pull/3065)] - [@jasondellaluce](https://github.com/jasondellaluce)
* update(CI): publish wasm package as dev-wasm [[#3017](https://github.com/falcosecurity/falco/pull/3017)] - [@Rohith-Raju](https://github.com/Rohith-Raju)
### Bug Fixes
* fix(userspace/falco): fix state initialization avoid a crash during hot reload [[#3190](https://github.com/falcosecurity/falco/pull/3190)] - [@FedeDP](https://github.com/FedeDP)
* fix(userspace/engine): make sure exception fields are not optional in replace mode [[#3108](https://github.com/falcosecurity/falco/pull/3108)] - [@jasondellaluce](https://github.com/jasondellaluce)
* fix(docker): added zstd to driver loader images [[#3203](https://github.com/falcosecurity/falco/pull/3203)] - [@FedeDP](https://github.com/FedeDP)
* fix(engine): raise warning instead of error on not-unique exceptions names [[#3159](https://github.com/falcosecurity/falco/pull/3159)] - [@mrgian](https://github.com/mrgian)
* fix(engine): apply output substitutions for all sources [[#3135](https://github.com/falcosecurity/falco/pull/3135)] - [@mrgian](https://github.com/mrgian)
* fix(userspace/configuration): make sure that folders that would trigger permission denied are not traversed [[#3127](https://github.com/falcosecurity/falco/pull/3127)] - [@sgaist](https://github.com/sgaist)
* fix(engine): logical issue in exceptions condition [[#3115](https://github.com/falcosecurity/falco/pull/3115)] - [@mrgian](https://github.com/mrgian)
* fix(cmake): properly let falcoctl cmake module create /usr/share/falco/plugins/ folder. [[#3105](https://github.com/falcosecurity/falco/pull/3105)] - [@FedeDP](https://github.com/FedeDP)
### Non user-facing changes
* update(scripts/falcoctl): bump falco-rules version to 3 [[#3128](https://github.com/falcosecurity/falco/pull/3128)] - [@alacuku](https://github.com/alacuku)
* build(deps): Bump submodules/falcosecurity-rules from `59bf03b` to `9e56293` [[#3212](https://github.com/falcosecurity/falco/pull/3212)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* chore(gha): update cosign to v3.5.0 [[#3209](https://github.com/falcosecurity/falco/pull/3209)] - [@LucaGuerra](https://github.com/LucaGuerra)
* build(deps): Bump submodules/falcosecurity-rules from `29c41c4` to `59bf03b` [[#3207](https://github.com/falcosecurity/falco/pull/3207)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* update(cmake): bumped libs to 0.17.0-rc1 and falcoctl to v0.8.0-rc6. [[#3204](https://github.com/falcosecurity/falco/pull/3204)] - [@FedeDP](https://github.com/FedeDP)
* build(deps): Bump submodules/falcosecurity-rules from `3f668d0` to `3cac61c` [[#3044](https://github.com/falcosecurity/falco/pull/3044)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* build(deps): Bump submodules/falcosecurity-testing from `ae3950a` to `7abf76f` [[#3094](https://github.com/falcosecurity/falco/pull/3094)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* fix(ci): enforce bundled deps OFF in build-dev CI [[#3118](https://github.com/falcosecurity/falco/pull/3118)] - [@FedeDP](https://github.com/FedeDP)
* build(deps): Bump submodules/falcosecurity-rules from `88a40c8` to `869c9a7` [[#3156](https://github.com/falcosecurity/falco/pull/3156)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* update(cmake): bumped falcoctl to v0.8.0-rc5. [[#3199](https://github.com/falcosecurity/falco/pull/3199)] - [@FedeDP](https://github.com/FedeDP)
* build(deps): Bump submodules/falcosecurity-rules from `4f153f5` to `29c41c4` [[#3198](https://github.com/falcosecurity/falco/pull/3198)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* update(cmake): bump falcoctl to v0.8.0-rc4 [[#3191](https://github.com/falcosecurity/falco/pull/3191)] - [@FedeDP](https://github.com/FedeDP)
* refactor: smart pointer usage [[#3184](https://github.com/falcosecurity/falco/pull/3184)] - [@federico-sysdig](https://github.com/federico-sysdig)
* build(deps): Bump submodules/falcosecurity-rules from `ec255e6` to `4f153f5` [[#3182](https://github.com/falcosecurity/falco/pull/3182)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* update(cmake): bumped libs and driver to latest master. [[#3177](https://github.com/falcosecurity/falco/pull/3177)] - [@FedeDP](https://github.com/FedeDP)
* chore(cmake): enable modern bpf build by default. [[#3180](https://github.com/falcosecurity/falco/pull/3180)] - [@FedeDP](https://github.com/FedeDP)
* cleanup(docs): fix typo in license blocks [[#3175](https://github.com/falcosecurity/falco/pull/3175)] - [@LucaGuerra](https://github.com/LucaGuerra)
* chore(docker,scripts): set old eBPF probe as lowest priority driver. [[#3173](https://github.com/falcosecurity/falco/pull/3173)] - [@FedeDP](https://github.com/FedeDP)
* build(deps): Bump submodules/falcosecurity-rules from `869c9a7` to `ec255e6` [[#3170](https://github.com/falcosecurity/falco/pull/3170)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* update(app): close inspectors at teardown time [[#3169](https://github.com/falcosecurity/falco/pull/3169)] - [@LucaGuerra](https://github.com/LucaGuerra)
* fix(docker): fixed docker entrypoints for driver loading. [[#3168](https://github.com/falcosecurity/falco/pull/3168)] - [@FedeDP](https://github.com/FedeDP)
* fix(docker,scripts): do not load falcoctl driver loader when installing Falco deb package in docker images [[#3166](https://github.com/falcosecurity/falco/pull/3166)] - [@FedeDP](https://github.com/FedeDP)
* update(ci): build both release and debug versions [[#3161](https://github.com/falcosecurity/falco/pull/3161)] - [@LucaGuerra](https://github.com/LucaGuerra)
* chore(userspace/falco): watch all configs files. [[#3160](https://github.com/falcosecurity/falco/pull/3160)] - [@FedeDP](https://github.com/FedeDP)
* fix(ci): update scorecard-action to v2.3.1 [[#3153](https://github.com/falcosecurity/falco/pull/3153)] - [@LucaGuerra](https://github.com/LucaGuerra)
* cleanup(falco): consolidate falco::grpc::server in one class [[#3150](https://github.com/falcosecurity/falco/pull/3150)] - [@LucaGuerra](https://github.com/LucaGuerra)
* new(build): enable ASan and UBSan builds with options and in CI [[#3147](https://github.com/falcosecurity/falco/pull/3147)] - [@LucaGuerra](https://github.com/LucaGuerra)
* fix(userspace): variable / function shadowing [[#3123](https://github.com/falcosecurity/falco/pull/3123)] - [@sgaist](https://github.com/sgaist)
* build(deps): Bump submodules/falcosecurity-rules from `fbf0a4e` to `88a40c8` [[#3145](https://github.com/falcosecurity/falco/pull/3145)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* fix(cmake): fix USE_BUNDLED_DEPS=ON and BUILD_FALCO_UNIT_TESTS=ON [[#3146](https://github.com/falcosecurity/falco/pull/3146)] - [@LucaGuerra](https://github.com/LucaGuerra)
* Add --kernelversion and --kernelrelease options to falco driver loader entrypoint [[#3143](https://github.com/falcosecurity/falco/pull/3143)] - [@Sryther](https://github.com/Sryther)
* build(deps): Bump submodules/falcosecurity-rules from `44addef` to `fbf0a4e` [[#3139](https://github.com/falcosecurity/falco/pull/3139)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* chore: bump to latest libs commit [[#3137](https://github.com/falcosecurity/falco/pull/3137)] - [@Andreagit97](https://github.com/Andreagit97)
* refactor: Use FetchContent for integrating three bundled libs [[#3107](https://github.com/falcosecurity/falco/pull/3107)] - [@federico-sysdig](https://github.com/federico-sysdig)
* build(deps): Bump submodules/falcosecurity-rules from `dc7970d` to `44addef` [[#3136](https://github.com/falcosecurity/falco/pull/3136)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* build(deps): Bump submodules/falcosecurity-rules from `f88b991` to `dc7970d` [[#3126](https://github.com/falcosecurity/falco/pull/3126)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* refactor(ci): Avoid using command make directly [[#3101](https://github.com/falcosecurity/falco/pull/3101)] - [@federico-sysdig](https://github.com/federico-sysdig)
* docs(proposal): 20231220-features-adoption-and-deprecation.md [[#2986](https://github.com/falcosecurity/falco/pull/2986)] - [@leogr](https://github.com/leogr)
* build(deps): Bump submodules/falcosecurity-rules from `b499a1d` to `f88b991` [[#3125](https://github.com/falcosecurity/falco/pull/3125)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* docs(README.md): Falco Graduates within the CNCF [[#3124](https://github.com/falcosecurity/falco/pull/3124)] - [@leogr](https://github.com/leogr)
* build(deps): Bump submodules/falcosecurity-rules from `497e011` to `b499a1d` [[#3111](https://github.com/falcosecurity/falco/pull/3111)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* chore(ci): bumped codeql actions. [[#3114](https://github.com/falcosecurity/falco/pull/3114)] - [@FedeDP](https://github.com/FedeDP)
* Cleanup warnings and smart ptrs [[#3112](https://github.com/falcosecurity/falco/pull/3112)] - [@federico-sysdig](https://github.com/federico-sysdig)
* new(build): add options to use bundled dependencies [[#3092](https://github.com/falcosecurity/falco/pull/3092)] - [@mrgian](https://github.com/mrgian)
* fix(ci): test-dev-packages-arm64 needs build-dev-packages-arm64. [[#3110](https://github.com/falcosecurity/falco/pull/3110)] - [@FedeDP](https://github.com/FedeDP)
* refactor: bump libs and driver, and adopt unique pointers wherever possible [[#3109](https://github.com/falcosecurity/falco/pull/3109)] - [@jasondellaluce](https://github.com/jasondellaluce)
* cleanup: falco_engine test fixture [[#3099](https://github.com/falcosecurity/falco/pull/3099)] - [@federico-sysdig](https://github.com/federico-sysdig)
* refactor: test AtomicSignalHandler.handle_once_wait_consistency [[#3100](https://github.com/falcosecurity/falco/pull/3100)] - [@federico-sysdig](https://github.com/federico-sysdig)
* Cleanup variable use [[#3097](https://github.com/falcosecurity/falco/pull/3097)] - [@sgaist](https://github.com/sgaist)
* cleanup(submodules): dropped testing submodule. [[#3098](https://github.com/falcosecurity/falco/pull/3098)] - [@FedeDP](https://github.com/FedeDP)
* cleanup(ci): make use of falcosecurity/testing provided composite action [[#3093](https://github.com/falcosecurity/falco/pull/3093)] - [@FedeDP](https://github.com/FedeDP)
* Improve const correctness [[#3083](https://github.com/falcosecurity/falco/pull/3083)] - [@sgaist](https://github.com/sgaist)
* Improve exception throwing [[#3085](https://github.com/falcosecurity/falco/pull/3085)] - [@sgaist](https://github.com/sgaist)
* fix(ci): update sync in deb and rpm scripts with acl [[#3062](https://github.com/falcosecurity/falco/pull/3062)] - [@LucaGuerra](https://github.com/LucaGuerra)
* cleanup(tests): consolidate Falco engine and rule loader tests [[#3066](https://github.com/falcosecurity/falco/pull/3066)] - [@LucaGuerra](https://github.com/LucaGuerra)
* cleanup: falco_engine deps and include paths [[#3090](https://github.com/falcosecurity/falco/pull/3090)] - [@federico-sysdig](https://github.com/federico-sysdig)
* fix: Some compiler warnings [[#3089](https://github.com/falcosecurity/falco/pull/3089)] - [@federico-sysdig](https://github.com/federico-sysdig)
* build(deps): Bump submodules/falcosecurity-rules from `0f60976` to `497e011` [[#3081](https://github.com/falcosecurity/falco/pull/3081)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* fix(c++): add missing explicit to single argument constructors [[#3069](https://github.com/falcosecurity/falco/pull/3069)] - [@sgaist](https://github.com/sgaist)
* Improve class initialization [[#3074](https://github.com/falcosecurity/falco/pull/3074)] - [@sgaist](https://github.com/sgaist)
* build(deps): Bump submodules/falcosecurity-rules from `6ed2036` to `0f60976` [[#3078](https://github.com/falcosecurity/falco/pull/3078)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* build(deps): Bump submodules/falcosecurity-rules from `1053b2d` to `6ed2036` [[#3067](https://github.com/falcosecurity/falco/pull/3067)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* fix(c++): add missing overrides [[#3064](https://github.com/falcosecurity/falco/pull/3064)] - [@sgaist](https://github.com/sgaist)
* new(build): prune deb-dev and rpm-dev directories [[#3056](https://github.com/falcosecurity/falco/pull/3056)] - [@LucaGuerra](https://github.com/LucaGuerra)
* refactor(userspace): align falco to gen-event class family deprecation [[#3051](https://github.com/falcosecurity/falco/pull/3051)] - [@jasondellaluce](https://github.com/jasondellaluce)
* build(deps): Bump submodules/falcosecurity-rules from `3cac61c` to `1053b2d` [[#3047](https://github.com/falcosecurity/falco/pull/3047)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* fix: adopt new libsinsp logger [[#3026](https://github.com/falcosecurity/falco/pull/3026)] - [@therealbobo](https://github.com/therealbobo)
* refactor: cleanup libs relative include paths [[#2936](https://github.com/falcosecurity/falco/pull/2936)] - [@therealbobo](https://github.com/therealbobo)
* chore(ci): bumped rn2md to latest master. [[#3046](https://github.com/falcosecurity/falco/pull/3046)] - [@FedeDP](https://github.com/FedeDP)
* Support alternate rules loader [[#3008](https://github.com/falcosecurity/falco/pull/3008)] - [@mstemm](https://github.com/mstemm)
* fix(ci): fixed release body driver version. [[#3042](https://github.com/falcosecurity/falco/pull/3042)] - [@FedeDP](https://github.com/FedeDP)
* build(deps): Bump submodules/falcosecurity-rules from `c39d31a` to `3f668d0` [[#3039](https://github.com/falcosecurity/falco/pull/3039)] - [@dependabot[bot]](https://github.com/apps/dependabot)
## v0.37.1
Released on 2024-02-13

View File

@@ -21,9 +21,6 @@ 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(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)
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)
@@ -52,7 +49,7 @@ 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)
option(BUILD_FALCO_MODERN_BPF "Build modern BPF support for Falco" OFF)
if(BUILD_FALCO_MODERN_BPF)
add_definitions(-DHAS_MODERN_BPF)
endif()
@@ -164,15 +161,12 @@ endif()
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}")
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}")
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}")
endif()
if(NOT MINIMAL_BUILD)

View File

@@ -10,7 +10,7 @@
At its core, Falco is a kernel monitoring and detection agent that observes events, such as syscalls, based on custom rules. Falco can enhance these events by integrating metadata from the container runtime and Kubernetes. The collected events can be analyzed off-host in SIEM or data lake systems.
Falco, originally created by [Sysdig](https://sysdig.com), is a **graduated project** under the [Cloud Native Computing Foundation](https://cncf.io) (CNCF) used in production by various [organisations](https://github.com/falcosecurity/falco/blob/master/ADOPTERS.md).
Falco, originally created by [Sysdig](https://sysdig.com), is an incubating project under the [Cloud Native Computing Foundation](https://cncf.io) (CNCF) used in production by various [organisations](https://github.com/falcosecurity/falco/blob/master/ADOPTERS.md).
For detailed technical information and insights into the cyber threats that Falco can detect, visit the official [Falco](https://falco.org/) website.

View File

@@ -53,17 +53,6 @@ if(NOT MSVC)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -D_FORTIFY_SOURCE=2")
endif()
if(USE_ASAN)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -fsanitize=address")
endif()
if(USE_UBSAN)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -fsanitize=undefined")
if(UBSAN_HALT_ON_ERROR)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -fno-sanitize-recover=undefined")
endif()
endif()
set(CMAKE_COMMON_FLAGS "${FALCO_SECURITY_FLAGS} -Wall -ggdb ${FALCO_EXTRA_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}")
if(BUILD_WARNINGS_AS_ERRORS)

View File

@@ -12,15 +12,32 @@
# specific language governing permissions and limitations under the License.
#
#
# cpp-httplib (https://github.com/yhirose/cpp-httplib)
#
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)
else()
if(CPPHTTPLIB_INCLUDE)
# we already have cpp-httplib
elseif(NOT USE_BUNDLED_CPPHTTPLIB)
find_package(httplib CONFIG REQUIRED)
get_target_property(CPPHTTPLIB_INCLUDE httplib::httplib INTERFACE_INCLUDE_DIRECTORIES)
else()
set(CPPHTTPLIB_SRC "${PROJECT_BINARY_DIR}/cpp-httplib-prefix/src/cpp-httplib")
set(CPPHTTPLIB_INCLUDE "${CPPHTTPLIB_SRC}")
message(STATUS "Using bundled cpp-httplib in ${CPPHTTPLIB_SRC}")
ExternalProject_Add(cpp-httplib
PREFIX "${PROJECT_BINARY_DIR}/cpp-httplib-prefix"
URL "https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.13.1.tar.gz"
URL_HASH "SHA256=9b837d290b61e3f0c4239da0b23bbf14c382922e2bf2a9bac21c1e3feabe1ff9"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
endif()
if(NOT TARGET cpp-httplib)
add_custom_target(cpp-httplib)
endif()

View File

@@ -34,8 +34,8 @@ else()
# 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.2.0+driver")
set(DRIVER_CHECKSUM "SHA256=82424189620010092d0eaabbfa59d904510771e293fd03f67a01b099691b4c4b")
set(DRIVER_VERSION "f2eabad40d2b3bd74c63743ed7f7a020c85f3aaa")
set(DRIVER_CHECKSUM "SHA256=5e1d0d6ff736b49b8b49e9cf5881be8db622cea5586d71d1974b6f8152e0b978")
endif()
# cd /path/to/build && cmake /path/to/source

View File

@@ -16,14 +16,14 @@ include(ExternalProject)
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} FALCOCTL_SYSTEM_NAME)
set(FALCOCTL_VERSION "0.8.0")
set(FALCOCTL_VERSION "0.7.2")
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(FALCOCTL_SYSTEM_PROC_GO "amd64")
set(FALCOCTL_HASH "7b763bfaf38faf582840af22750dca7150d03958a5dc47f6118748713d661589")
set(FALCOCTL_HASH "abbbef2beefceb3d518a638fbad220ca6002840d33a20a7f1de9b358c4dbef45")
else() # aarch64
set(FALCOCTL_SYSTEM_PROC_GO "arm64")
set(FALCOCTL_HASH "7f826de7a8a84e65c46a160e7e59d1deca874f39b79a8251721a2669905baf14")
set(FALCOCTL_HASH "8dafef99948355febfa311bb940f8c714af631a249f4ae05ffd7d4c5f181e2c4")
endif()
ExternalProject_Add(

View File

@@ -35,8 +35,8 @@ else()
# 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.17.2")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=5c4f0c987272b7d5236f6ab2bbe3906ffdaf76b59817b63cf90cc8c387ab5b15")
set(FALCOSECURITY_LIBS_VERSION "f2eabad40d2b3bd74c63743ed7f7a020c85f3aaa")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=5e1d0d6ff736b49b8b49e9cf5881be8db622cea5586d71d1974b6f8152e0b978")
endif()
# cd /path/to/build && cmake /path/to/source

View File

@@ -12,15 +12,29 @@
# specific language governing permissions and limitations under the License.
#
#
# njson (https://github.com/nlohmann/json)
#
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)
else()
if(nlohmann_json_INCLUDE_DIRS)
# we already have nlohmnann-json
elseif(NOT USE_BUNDLED_NLOHMANN_JSON)
find_package(nlohmann_json CONFIG REQUIRED)
get_target_property(nlohmann_json_INCLUDE_DIRS nlohmann_json::nlohmann_json INTERFACE_INCLUDE_DIRECTORIES)
else()
set(nlohmann_json_INCLUDE_DIRS "${PROJECT_BINARY_DIR}/njson-prefix/include")
message(STATUS "Using bundled nlohmann-json in ${nlohmann_json_INCLUDE_DIRS}")
ExternalProject_Add(njson
URL "https://github.com/nlohmann/json/archive/v3.3.0.tar.gz"
URL_HASH "SHA256=2fd1d207b4669a7843296c41d3b6ac5b23d00dec48dba507ba051d14564aa801"
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/njson-prefix -DJSON_BuildTests=OFF -DBUILD_TESTING=OFF
)
endif()
if(NOT TARGET njson)
add_custom_target(njson)
endif()

View File

@@ -16,8 +16,8 @@ include(GNUInstallDirs)
include(ExternalProject)
# falco_rules.yaml
set(FALCOSECURITY_RULES_FALCO_VERSION "falco-rules-3.1.0")
set(FALCOSECURITY_RULES_FALCO_CHECKSUM "SHA256=3b617920c0b66128627613e591a954eb9572747a4c287bc13b53b38786250162")
set(FALCOSECURITY_RULES_FALCO_VERSION "falco-rules-3.0.0")
set(FALCOSECURITY_RULES_FALCO_CHECKSUM "SHA256=2e91799fee49c2daf58fb482e47410a21433eb116e02cde18206f7af87449ddb")
set(FALCOSECURITY_RULES_FALCO_PATH "${PROJECT_BINARY_DIR}/falcosecurity-rules-falco-prefix/src/falcosecurity-rules-falco/falco_rules.yaml")
ExternalProject_Add(
falcosecurity-rules-falco

View File

@@ -12,15 +12,45 @@
# specific language governing permissions and limitations under the License.
#
#
# yamlcpp (https://github.com/jbeder/yaml-cpp)
#
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)
if(YAMLCPP_INCLUDE_DIR)
# we already have yamlcpp
elseif(NOT USE_BUNDLED_YAMLCPP)
find_path(YAMLCPP_INCLUDE_DIR NAMES yaml-cpp/yaml.h)
find_library(YAMLCPP_LIB NAMES yaml-cpp)
if(YAMLCPP_INCLUDE_DIR)
message(STATUS "Found yamlcpp: include: ${YAMLCPP_INCLUDE_DIR}")
else()
message(FATAL_ERROR "Couldn't find system yamlcpp")
endif()
else()
find_package(yaml-cpp CONFIG REQUIRED)
set(YAMLCPP_SRC "${PROJECT_BINARY_DIR}/yamlcpp-prefix/src/yamlcpp")
set(YAMLCPP_INCLUDE_DIR "${YAMLCPP_SRC}/include")
message(STATUS "Using bundled yaml-cpp in '${YAMLCPP_SRC}'")
if(NOT WIN32)
set(YAMLCPP_LIB "${YAMLCPP_SRC}/libyaml-cpp.a")
else()
set(YAMLCPP_LIB "${YAMLCPP_SRC}/${CMAKE_BUILD_TYPE}/yaml-cpp.lib")
endif()
ExternalProject_Add(
yamlcpp
URL "https://github.com/jbeder/yaml-cpp/archive/yaml-cpp-0.7.0.tar.gz"
URL_HASH "SHA256=43e6a9fcb146ad871515f0d0873947e5d497a1c9c60c58cb102a97b47208b7c3"
BUILD_BYPRODUCTS ${YAMLCPP_LIB}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DYAML_MSVC_SHARED_RT=Off -DYAML_BUILD_SHARED_LIBS=Off -DYAML_CPP_BUILD_TESTS=Off -DYAML_CPP_BUILD_TOOLS=OFF -DYAML_CPP_BUILD_CONTRIB=OFF -DCMAKE_DEBUG_POSTFIX=''
BUILD_IN_SOURCE 1
INSTALL_COMMAND "")
endif()
if(NOT TARGET yamlcpp)
add_custom_target(yamlcpp)
endif()

View File

@@ -37,7 +37,6 @@ RUN apt-get update \
netcat \
patchelf \
xz-utils \
zstd \
&& rm -rf /var/lib/apt/lists/*
RUN if [ "$TARGETARCH" = "amd64" ]; \
@@ -93,7 +92,7 @@ RUN rm -rf /usr/bin/clang \
RUN curl -s https://falco.org/repo/falcosecurity-packages.asc | apt-key add - \
&& echo "deb https://download.falco.org/packages/${VERSION_BUCKET} stable main" | tee -a /etc/apt/sources.list.d/falcosecurity.list \
&& apt-get update -y \
&& if [ "$FALCO_VERSION" = "latest" ]; then FALCO_DRIVER_CHOICE=none apt-get install -y --no-install-recommends falco; else FALCO_DRIVER_CHOICE=none apt-get install -y --no-install-recommends falco=${FALCO_VERSION}; fi \
&& if [ "$FALCO_VERSION" = "latest" ]; then apt-get install -y --no-install-recommends falco; else apt-get install -y --no-install-recommends falco=${FALCO_VERSION}; fi \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -24,9 +24,7 @@ print_usage() {
echo " docker run -i -t --privileged -v /root/.falco:/root/.falco -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc:ro falcosecurity/falco-driver-loader-legacy:latest [driver] [options]"
echo ""
echo "Available drivers:"
echo " auto leverage automatic driver selection logic (default)"
echo " modern_ebpf modern eBPF CORE probe"
echo " kmod kernel module"
echo " kmod kernel module (default)"
echo " ebpf eBPF probe"
echo ""
echo "Options:"
@@ -55,17 +53,18 @@ done
ENABLE_COMPILE="false"
ENABLE_DOWNLOAD="false"
HTTP_INSECURE="false"
driver=
has_driver=
has_opts=
while test $# -gt 0; do
case "$1" in
auto|kmod|ebpf|modern_ebpf)
if [ -n "$driver" ]; then
kmod|ebpf)
if [ -n "$has_driver" ]; then
>&2 echo "Only one driver per invocation"
print_usage
exit 1
else
driver=$1
/usr/bin/falcoctl driver config --type $1
has_driver="true"
fi
;;
-h|--help)
@@ -86,6 +85,11 @@ while test $# -gt 0; do
;;
--http-insecure)
HTTP_INSECURE="true"
;;
--source-only)
>&2 echo "Support dropped in Falco 0.37.0."
print_usage
exit 1
;;
--print-env)
/usr/bin/falcoctl driver printenv
@@ -105,22 +109,9 @@ while test $# -gt 0; do
shift
done
# No opts passed, enable both compile and download
if [ -z "$has_opts" ]; then
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
fi
# Default value: auto
if [ -z "$driver" ]; then
driver="auto"
fi
if [ "$driver" != "auto" ]; then
/usr/bin/falcoctl driver config --type $driver
else
# Needed because we need to configure Falco to start with correct driver
/usr/bin/falcoctl driver config --type modern_ebpf --type kmod --type ebpf
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
fi
/usr/bin/falcoctl driver install --compile=$ENABLE_COMPILE --download=$ENABLE_DOWNLOAD --http-insecure=$HTTP_INSECURE --http-headers="$FALCOCTL_DRIVER_HTTP_HEADERS"

View File

@@ -24,20 +24,16 @@ print_usage() {
echo " docker run -i -t --privileged -v /root/.falco:/root/.falco -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc:ro falcosecurity/falco-driver-loader:latest [driver] [options]"
echo ""
echo "Available drivers:"
echo " auto leverage automatic driver selection logic (default)"
echo " modern_ebpf modern eBPF CORE probe"
echo " kmod kernel module"
echo " kmod kernel module (default)"
echo " ebpf eBPF probe"
echo ""
echo "Options:"
echo " --help show this help message"
echo " --clean try to remove an already present driver installation"
echo " --compile try to compile the driver locally (default true)"
echo " --download try to download a prebuilt driver (default true)"
echo " --kernel-release <value> set the kernel release"
echo " --kernel-version <value> set the kernel version"
echo " --http-insecure enable insecure downloads"
echo " --print-env skip execution and print env variables for other tools to consume"
echo " --help show this help message"
echo " --clean try to remove an already present driver installation"
echo " --compile try to compile the driver locally (default true)"
echo " --download try to download a prebuilt driver (default true)"
echo " --http-insecure enable insecure downloads"
echo " --print-env skip execution and print env variables for other tools to consume"
echo ""
echo "Environment variables:"
echo " FALCOCTL_DRIVER_REPOS specify different URL(s) where to look for prebuilt Falco drivers (comma separated)"
@@ -57,19 +53,18 @@ done
ENABLE_COMPILE="false"
ENABLE_DOWNLOAD="false"
HTTP_INSECURE="false"
driver=
has_driver=
has_opts=
extra_args=
while test $# -gt 0; do
case "$1" in
auto|kmod|ebpf|modern_ebpf)
if [ -n "$driver" ]; then
kmod|ebpf)
if [ -n "$has_driver" ]; then
>&2 echo "Only one driver per invocation"
print_usage
exit 1
else
driver=$1
/usr/bin/falcoctl driver config --type $1
has_driver="true"
fi
;;
-h|--help)
@@ -90,14 +85,11 @@ while test $# -gt 0; do
;;
--http-insecure)
HTTP_INSECURE="true"
;;
--kernel-release)
extra_args+="--kernelrelease=$2 "
shift
;;
--kernel-version)
extra_args+="--kernelversion=$2 "
shift
;;
--source-only)
>&2 echo "Support dropped in Falco 0.37.0."
print_usage
exit 1
;;
--print-env)
/usr/bin/falcoctl driver printenv
@@ -117,22 +109,9 @@ while test $# -gt 0; do
shift
done
# No opts passed, enable both compile and download
if [ -z "$has_opts" ]; then
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
fi
# Default value: auto
if [ -z "$driver" ]; then
driver="auto"
fi
if [ "$driver" != "auto" ]; then
/usr/bin/falcoctl driver config --type $driver
else
# Needed because we need to configure Falco to start with correct driver
/usr/bin/falcoctl driver config --type modern_ebpf --type kmod --type ebpf
fi
/usr/bin/falcoctl driver install --compile=$ENABLE_COMPILE --download=$ENABLE_DOWNLOAD --http-insecure=$HTTP_INSECURE --http-headers="$FALCOCTL_DRIVER_HTTP_HEADERS" $extra_args
/usr/bin/falcoctl driver install --compile=$ENABLE_COMPILE --download=$ENABLE_DOWNLOAD --http-insecure=$HTTP_INSECURE --http-headers="$FALCOCTL_DRIVER_HTTP_HEADERS"

View File

@@ -39,13 +39,12 @@ RUN apt-get update \
netcat-openbsd \
patchelf \
xz-utils \
zstd \
&& rm -rf /var/lib/apt/lists/*
RUN curl -s https://falco.org/repo/falcosecurity-packages.asc | apt-key add - \
&& echo "deb https://download.falco.org/packages/${VERSION_BUCKET} stable main" | tee -a /etc/apt/sources.list.d/falcosecurity.list \
&& apt-get update -y \
&& if [ "$FALCO_VERSION" = "latest" ]; then FALCO_DRIVER_CHOICE=none apt-get install -y --no-install-recommends falco; else FALCO_DRIVER_CHOICE=none apt-get install -y --no-install-recommends falco=${FALCO_VERSION}; fi \
&& if [ "$FALCO_VERSION" = "latest" ]; then apt-get install -y --no-install-recommends falco; else apt-get install -y --no-install-recommends falco=${FALCO_VERSION}; fi \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -24,9 +24,7 @@ print_usage() {
echo " docker run -i -t --privileged -v /root/.falco:/root/.falco -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc:ro -e 'FALCO_DRIVER_LOADER_OPTIONS=[driver] [options]' falcosecurity/falco:latest"
echo ""
echo "Available FALCO_DRIVER_LOADER_OPTIONS drivers:"
echo " auto leverage automatic driver selection logic (default)"
echo " modern_ebpf modern eBPF CORE probe"
echo " kmod kernel module"
echo " kmod kernel module (default)"
echo " ebpf eBPF probe"
echo ""
echo "FALCO_DRIVER_LOADER_OPTIONS options:"
@@ -62,18 +60,19 @@ if [[ -z "${SKIP_DRIVER_LOADER}" ]]; then
ENABLE_COMPILE="false"
ENABLE_DOWNLOAD="false"
HTTP_INSECURE="false"
driver=
has_driver=
has_opts=
for opt in "${falco_driver_loader_option_arr[@]}"
do
case "$opt" in
auto|kmod|ebpf|modern_ebpf)
if [ -n "$driver" ]; then
kmod|ebpf)
if [ -n "$has_driver" ]; then
>&2 echo "Only one driver per invocation"
print_usage
exit 1
else
driver=$opt
/usr/bin/falcoctl driver config --type $opt
has_driver="true"
fi
;;
-h|--help)
@@ -92,43 +91,34 @@ if [[ -z "${SKIP_DRIVER_LOADER}" ]]; then
ENABLE_DOWNLOAD="true"
has_opts="true"
;;
--http-insecure)
HTTP_INSECURE="true"
;;
--http-insecure)
HTTP_INSECURE="true"
;;
--source-only)
>&2 echo "Support dropped in Falco 0.37.0."
print_usage
exit 1
;;
--print-env)
/usr/bin/falcoctl driver printenv
exit 0
;;
--*)
>&2 echo "Unknown option: $opt"
>&2 echo "Unknown option: $1"
print_usage
exit 1
;;
*)
>&2 echo "Unknown driver: $opt"
>&2 echo "Unknown driver: $1"
print_usage
exit 1
;;
esac
done
# No opts passed, enable both compile and download
if [ -z "$has_opts" ]; then
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
fi
# Default value: auto
if [ -z "$driver" ]; then
driver="auto"
fi
if [ "$driver" != "auto" ]; then
/usr/bin/falcoctl driver config --type $driver
else
# Needed because we need to configure Falco to start with correct driver
/usr/bin/falcoctl driver config --type modern_ebpf --type kmod --type ebpf
fi
/usr/bin/falcoctl driver install --compile=$ENABLE_COMPILE --download=$ENABLE_DOWNLOAD --http-insecure=$HTTP_INSECURE --http-headers="$FALCOCTL_DRIVER_HTTP_HEADERS"
fi

View File

@@ -25,64 +25,46 @@
#
# (Falco command-line arguments)
# (Falco environment variables)
# Falco config files settings
# config_files [Stable]
# watch_config_files [Stable]
# Falco rules files
# rules_files [Stable]
# Falco rules
# rules [Incubating]
# rules_file
# Falco engine
# engine [Stable]
# engine
# Falco plugins
# load_plugins [Stable]
# plugins [Stable]
# load_plugins
# plugins
# Falco config files
# watch_config_files
# Falco outputs settings
# time_format_iso_8601 [Stable]
# priority [Stable]
# json_output [Stable]
# json_include_output_property [Stable]
# json_include_tags_property [Stable]
# buffered_outputs [Stable]
# rule_matching [Incubating]
# outputs_queue [Stable]
# time_format_iso_8601
# priority
# json_output
# json_include_output_property
# json_include_tags_property
# buffered_outputs
# rule_matching
# outputs_queue
# Falco outputs channels
# stdout_output [Stable]
# syslog_output [Stable]
# file_output [Stable]
# http_output [Stable]
# program_output [Stable]
# grpc_output [Stable]
# stdout_output
# syslog_output
# file_output
# http_output
# program_output
# grpc_output
# Falco exposed services
# grpc [Stable]
# webserver [Stable]
# grpc
# webserver
# Falco logging / alerting / metrics related to software functioning (basic)
# log_stderr [Stable]
# log_syslog [Stable]
# log_level [Stable]
# libs_logger [Stable]
# log_stderr
# log_syslog
# log_level
# libs_logger
# Falco logging / alerting / metrics related to software functioning (advanced)
# output_timeout [Stable]
# syscall_event_timeouts [Stable]
# syscall_event_drops [Stable] -> [CHANGE NOTICE] Automatic notifications will be simplified in Falco 0.38! If you depend on the detailed drop counters payload, use 'metrics.output_rule' along with 'metrics.kernel_event_counters_enabled' instead
# metrics [Stable]
# output_timeout
# syscall_event_timeouts
# syscall_event_drops -> [CHANGE NOTICE] Automatic notifications will be simplified in Falco 0.38! If you depend on the detailed drop counters payload, use 'metrics.output_rule' along with 'metrics.kernel_event_counters_enabled' instead
# metrics
# Falco performance tuning (advanced)
# base_syscalls [Stable]
# Falco libs
# falco_libs [Incubating]
########################
# Config maturity tags #
########################
# As per features adoption and deprecation proposal we support 4 levels of configuration keys maturity:
# * Sandbox -> Experimental/alpha features, not recommended for production use, can be removed at any time without further notice.
# * Incubating -> Beta features, long-term support is not guaranteed.
# * Stable -> General Availability (GA) features for which long-term support is expected.
# * Deprecated -> Deprecated keys, soon to be removed.
#
# For more info, please take a look at the proposal: https://github.com/falcosecurity/falco/blob/master/proposals/20231220-features-adoption-and-deprecation.md.
# base_syscalls
################################
# Falco command-line arguments #
@@ -130,44 +112,15 @@
# disabling the automatic artifacts followed by falcoctl.
###############################
# Falco config files settings #
###############################
# [Stable] `config_files`
#
# Falco will load additional configs files specified here.
# Their loading is assumed to be made *after* main config file has been processed,
# exactly in the order they are specified.
# Therefore, loaded config files *can* override values from main config file.
# Also, nested include is not allowed, ie: included config files won't be able to include other config files.
#
# Like for 'rules_files', specifying a folder will load all the configs files present in it in a lexicographical order.
config_files:
- /etc/falco/config.d
# [Stable] `watch_config_files`
#
# Falco monitors configuration and rules files for changes and automatically
# reloads itself to apply the updated configuration when any modifications are
# detected. This feature is particularly useful when you want to make real-time
# changes to the configuration or rules of Falco without interrupting its
# operation or losing its state. For more information about Falco's state
# engine, please refer to the `base_syscalls` section.
watch_config_files: true
#####################
# Falco rules files #
#####################
# [Stable] `rules_files`
# NOTICE: Before Falco 0.38, this config key was `rules_file` (singular form), which is now deprecated in favor of `rules_files` (plural form).
# [Stable] `rules_file`
#
# Falco rules can be specified using files or directories, which are loaded at
# startup.
#
# If the entry is a file, it will be read directly. If the entry is a directory,
# startup. The name "rules_file" is maintained for backwards compatibility. If
# the entry is a file, it will be read directly. If the entry is a directory,
# all files within that directory will be read in alphabetical order.
#
# The falco_rules.yaml file ships with the Falco package and is overridden with
@@ -196,44 +149,11 @@ watch_config_files: true
# "first match wins" principle. However, enabling the `all` matching option may result
# in a performance penalty. We recommend carefully testing this alternative setting
# before deploying it in production. Read more under the `rule_matching` configuration.
rules_files:
rules_file:
- /etc/falco/falco_rules.yaml
- /etc/falco/falco_rules.local.yaml
- /etc/falco/rules.d
# [Incubating] `rules`
#
# --- [Description]
#
# Falco rules can be enabled or disabled by name (with wildcards *) and/or by tag.
#
# This configuration is applied after all rules files have been loaded, including
# their overrides, and will take precedence over the enabled/disabled configuration
# specified or overridden in the rules files.
#
# The ordering matters and selections are evaluated in order. For instance, if you
# need to only enable a rule you would first disable all of them and then only
# enable what you need, regardless of the enabled status in the files.
#
# --- [Examples]
#
# Only enable two rules:
#
# rules:
# - disable:
# rule: "*"
# - enable:
# rule: Netcat Remote Code Execution in Container
# - enable:
# rule: Delete or rename shell history
#
# Disable all rules with a specific tag:
#
# rules:
# - disable:
# tag: network
#
################
# Falco engine #
################
@@ -400,7 +320,7 @@ rules_files:
# buffers (higher `cpus_for_each_buffer`) can lower the memory footprint.
#
engine:
kind: modern_ebpf
kind: kmod
kmod:
buf_size_preset: 4
drop_failed_exit: false
@@ -481,6 +401,21 @@ plugins:
library_path: libjson.so
######################
# Falco config files #
######################
# [Stable] `watch_config_files`
#
# Falco monitors configuration and rule files for changes and automatically
# reloads itself to apply the updated configuration when any modifications are
# detected. This feature is particularly useful when you want to make real-time
# changes to the configuration or rules of Falco without interrupting its
# operation or losing its state. For more information about Falco's state
# engine, please refer to the `base_syscalls` section.
watch_config_files: true
##########################
# Falco outputs settings #
##########################
@@ -534,7 +469,7 @@ json_include_tags_property: true
# output mechanism. By default, buffering is disabled (false).
buffered_outputs: false
# [Incubating] `rule_matching`
# [Experimental] `rule_matching`
#
# The `rule_matching` configuration key's values are:
# - `first`: Falco stops checking conditions of rules against upcoming event
@@ -758,11 +693,6 @@ webserver:
# Can be an IPV4 or IPV6 address, defaults to IPV4
listen_address: 0.0.0.0
k8s_healthz_endpoint: /healthz
# [Incubating] `prometheus_metrics_enabled`
#
# Enable the metrics endpoint providing Prometheus values
# It will only have an effect if metrics.enabled is set to true as well.
prometheus_metrics_enabled: false
ssl_enabled: false
ssl_certificate: /etc/falco/falco.pem
@@ -992,8 +922,6 @@ syscall_event_drops:
# as Falco does not automatically rotate the file. It can be used in combination
# with `output_rule`.
#
# `rules_counters_enabled`: Emit counts for each rule.
#
# `resource_utilization_enabled`: Emit CPU and memory usage metrics. CPU usage
# is reported as a percentage of one CPU and can be normalized to the total
# number of CPUs to determine overall usage. Memory metrics are provided in raw
@@ -1037,30 +965,19 @@ syscall_event_drops:
# beneficial for exploring the data schema and ensuring that fields with empty
# values are included in the output.
#
# `plugins_metrics_enabled`: Falco can now expose your custom plugins'
# metrics. Please note that if the respective plugin has no metrics implemented,
# there will be no metrics available. In other words, there are no default or
# generic plugin metrics at this time. This may be subject to change.
#
# If metrics are enabled, the web server can be configured to activate the
# corresponding Prometheus endpoint using `webserver.prometheus_metrics_enabled`.
# Prometheus output can be used in combination with the other output options.
#
# todo: prometheus export option
# todo: syscall_counters_enabled option
metrics:
enabled: false
interval: 1h
# Typically, in production, you only use `output_rule` or `output_file`, but not both.
# However, if you have a very unique use case, you can use both together.
# Set `webserver.prometheus_metrics_enabled` for Prometheus output.
output_rule: true
# output_file: /tmp/falco_stats.jsonl
rules_counters_enabled: true
resource_utilization_enabled: true
state_counters_enabled: true
kernel_event_counters_enabled: true
libbpf_stats_enabled: true
plugins_metrics_enabled: true
convert_memory_to_mb: true
include_empty_values: false
@@ -1183,29 +1100,6 @@ base_syscalls:
custom_set: []
repair: false
##############
# Falco libs #
##############
# [Incubating] `falco_libs`
#
# `thread_table_size`
#
# Set the maximum number of entries (the absolute maximum value can only be MAX UINT32)
# for Falco's internal threadtable (process cache). Please note that Falco operates at a
# granular level, focusing on individual threads. Falco rules reference the thread leader
# as the process. The size of the threadtable should typically be much higher than the
# number of currently alive processes. The default value should work well on modern
# infrastructures and be sufficient to absorb bursts.
#
# Reducing its size can help in better memory management, but as a consequence, your
# process tree may be more frequently disrupted due to missing threads. You can explore
# `metrics.state_counters_enabled` to measure how the internal state handling is performing,
# and the fields called `n_drops_full_threadtable` or `n_store_evts_drops` will inform you
# if you should increase this value for optimal performance.
falco_libs:
thread_table_size: 262144
# [Stable] Guidance for Kubernetes container engine command-line args settings
#
# Modern cloud environments, particularly Kubernetes, heavily rely on

View File

@@ -335,7 +335,7 @@ typedef struct
// the type of the value they return (string, integer...).
// Required: no
// Arguments:
// - evtnum: the number of the event that is being processed
// - evtnum: the number of the event that is bein processed
// - id: the numeric identifier of the field to extract. It corresponds to the
// position of the field in the array returned by get_fields().
// - arg: the field argument, if an argument has been specified for the field,

View File

@@ -1,219 +0,0 @@
# Features Adoption and Deprecation Policies Proposal
This proposal aims to introduce a balance between maintaining adopter trust and the need for The Falco Project to evolve. Historically, Falco has favored rapid evolution over providing long-term support for features and interfaces. However, some project subsystems have been implicitly assumed not to allow backward-incompatible changes (e.g., we have almost never removed a condition syntax field). These implicit conventions have never been formalized, and decisions in this regard have been left unspecified.
## Goals
- Establish adopter expectations on the operational cost of using Falco.
- Provide a clear path for features to be adopted and dismissed.
- Allow quick evolution and experimentation without disrupting our adopters' deployments.
- Detail the process for introducing new features, following a "sandbox" to "incubating" to "stable" progression.
- Define the scope of the policy, including which aspects of Falco are covered (e.g., command line flags, configuration files, rules syntax).
- Establish stages for deprecating features, aligning with the project's current status (pre- and post-1.0 stages).
- Adopt a semantic versioning (semver) approach.
## Non-Goals
- Define the number of previous releases that will receive patches or security updates and the duration of this support.
- Define the criteria for Falco 1.0.
## Scope
The proposed policies apply to Falco, its subsystems (e.g., rules, the plugin system), and all [core projects](https://github.com/falcosecurity/evolution#core) which are deemed [stable](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable), thus officially supported by The Falco Project.
## Definitions
### Feature Changes
A feature is a distinct and specific functionality or characteristic of Falco and its core components that provides value to the user by enabling them to perform particular tasks. Features encompass aspects such as functionality, user value, usability, integrability, scalability, configurability, and discoverability. Features can range from essential user interface elements to complex, multifunctional operations.
A feature change refers to any modification or update to an existing feature or the addition of a new feature. This does not include documentation, Falco compatibility across different environments, platforms, systems, or other software or hardware, bug fixing (stated it does not require a feature change to overcome the problem), and performance (unless a change produces a measurable effect on usability).
### Behavior Changes
A behavior change refers to alterations in how Falco, or a specific feature within it, operates or responds under certain conditions. Unlike feature changes, behavior changes are more about tweaking the underlying logic or the way existing features interact or perform, particularly the expected behavior of Falco when run with the default configuration.
Behaviors are generally documented. Any modification that does not meet the conditions and expectations of an already documented feature is assumed to be a behavior change.
Undocumented behaviors may be included in this definition if there's strong evidence or suspicion that users rely on those undocumented behaviors.
### User-Facing Changes
User-facing changes refer to any feature changes, behavior changes, modifications, or additions that are directly noticeable and interactable by the end users. These changes affect how Falco operates from the user's perspective (notably any change that can lead to user disruption). Unlike internal changes (i.e., code refactoring, CI, maintenance-related changes), which are under-the-hood improvements not directly visible to the user, user-facing changes are evident in the Falco and its core components interface and functionality.
### CLI/Config Area
Falco is comprised of the Falco binary and other programs and tools cooperating (notably [falcoctl](https://github.com/falcosecurity/falcoctl)). These programs are the primary user interface for Falco. Any feature or behavior changes to the following elements of these programs are assumed to be user-facing changes to the CLI/Config area:
- Program name.
- Distribution mechanism and packaging (e.g., a container image).
- Command line flags and options.
- Environment variables.
- Configurations.
- Elements that affect the program's lifecycle (e.g., the effect of sending a SIGINT to the program).
- Elements that allow scripting, automation, or interaction with other programs (e.g., piping and redirection).
- Program inputs, excluding elements explicitly governed by other areas (e.g., [Falco rules](#rules-area)).
- Program outputs excluding elements explicitly governed by other areas (e.g., [Falco outputs/alerts](#outputs-alerts-area)).
### Rules System Area
Rules are the primary input for Falco. Any feature or behavior changes to the following aspects or elements are assumed to be user-facing changes to the rules system area:
- Syntax.
- File format.
- Schema (i.e., supported fields).
- Elements that affect the way users can implement rules.
- Elements that affect the way rules are triggered.
However, any change related to the rule's output when triggered (i.e., the alert) is out of scope for this area (see next section).
Note that this area does not include changes related to the ruleset files. Ruleset distributions follow their own [Rules Maturity Framework](https://github.com/falcosecurity/rules/blob/main/CONTRIBUTING.md#rules-maturity-framework) policies.
### Outputs/Alerts Area
Alerts, delivered through Falco output channels, are Falco's primary output. The way and the format in which alerts are produced can have a significant impact on adopters. For example, removing a supported rule field also impacts this area, as adopters may have relied on that field when consuming Falco output.
Any feature or behavior changes to the following aspects or elements are assumed to be user-facing changes to the Outputs/Alerts area:
- Output and logging formats.
- Schema of outputted data (i.e., supported fields).
- Falco output channels.
- Any element that might be consumed from the output.
### Subsystem APIs (Plugins, gRPC Output, Metrics, etc.) Area
Falco is also comprised of several subsystems providing specific APIs. These subsystems notably include plugin system API, gRPC output API, and metrics API.
In the context of this proposal, only changes to **public APIs** are assumed to be user-facing changes to this area.
Public APIs are defined as those supporting Falco functioning and explicitly intended for user usage. Internal APIs consumed by Falco or other tools are out of scope for this area. For instance, the driver APIs or libs APIs are intended to be mainly consumed by Falco and not by users.
### Platform Support Area
Platform support for Falco encompasses the range of platforms, systems, and environments it is designed to operate in. Platform support may significantly vary by Falco's data sources and use cases. For example, its compatibility differs when utilized for Kubernetes audit events versus system call events. Additionally, platform support can be influenced by deployment methods (e.g., directly on a host versus within Kubernetes) or configurations (e.g., running in privileged versus least privileged mode).
Given the diversity of potential platforms and setups, only those explicitly listed in Falco's documentation are considered officially supported. While Falco may function on other platforms, official support is guaranteed solely for documented ones.
Therefore, changes in platform compatibility or behavior that are documented explicitly assumed to be user-facing changes to the Platform Support area.
### Release Cycle
In the context of this proposal, a release cycle is the period between two consecutive major or minor releases of Falco. Hotfix/Patch releases must not be counted.
The actual duration of a release cycle can vary. Still, it's assumed to be about 16 weeks (as per our current defined [Release Cycles and Development Iterations](https://github.com/falcosecurity/falco/blob/master/proposals/20230511-roadmap-management.md#release-cycles-and-development-iterations)). In case of future modification to the Falco release schedule, a period of minimum 3 months must be assumed.
## Proposal
### Maturation Levels
Maturation levels (inspired by those we already have in place for [repositories](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#status)) are used to characterize the maturity of a feature. Each feature will have an assigned level at any specific time (i.e., a Falco release). Levels are shown in the table below.
| Maturity Level | Intended for |
| --- | --- |
| Sandbox | Experimental/alpha features, not recommended for production use, can be removed at any time without further notice. |
| Incubating | Beta features, long-term support is not guaranteed. |
| Stable | General Availability (GA) features for which long-term support is expected. |
| Deprecated | See the [deprecation policy](#Deprecation-policy) section below. |
### Adoption Policy
The adoption policy applies to any backward compatible user-facing changes which add functionalities. For non-backward compatible changes see the [deprecation policy](#Deprecation-policy) below.
**Adoption rules**:
1. A feature can be introduced at only one of the following levels:
- Sandbox: The feature must be opt-in (e.g., not enabled by default), labeled as *Sandbox* and the user must be proactively informed by the experimental nature of the feature (i.e. emitting a notice when the feature is being enabled).
- Incubating: The feature must be labeled as *Incubating*.
2. Any functionality additions to an existing feature are inherently introduced at the same level as the feature itself unless logically separable (for instance, a sub-feature that may be enabled separately).
3. A feature can be promoted *from Sandbox to Incubating* or *from Incubating to Stable* only after at least one release cycle has passed without user-facing changes to the feature.
4. A feature cannot be demoted to a previous level.
_Note about behaviors_:
This policy indirectly applies to behaviors, too. Behavior changes are assumed to be a consequence of a feature change. The adoption level of a documented behavior is considered to be the same as the related feature. Furthermore, behavior changes are particularly relevant in the context of deprecation (see the next section).
### Deprecation Policy
The deprecation policy applies to any non-backward compatible user-facing changes. Any other changes introduced in a backward-compatible manner does not fall under the scope of this deprecation policy.
**Deprecation rules**:
1. Sandbox features can be removed or changed at any time without notice. No deprecation period is required.
2. Incubating or Stable features and documented behaviors must enter a deprecation period and function for no less than the indicated release cycles (see tables below) after their announced deprecation.
- If the change affects the feature partially, the deprecation applies only to that feature part.
- If the change removes the feature entirely, the deprecation applies to the entire feature.
3. At least for the entire deprecation period, the feature must be labeled as *Deprecated* in all relevant documentation, and:
- for deprecated configurations or CLI elements, a warning must be emitted warnings when the feature is being enabled or used;
- for deprecated APIs, when technically feasible, the API should be signal the deprecation status (this may vary depending on the specific subsystem);
- for deprecated behaviors the documentation must highlight the _before_ and _after_ behavior, alongside with a prominent deprecation notice.
4. Any Pull Request introducing a deprecation notice must be labeled and include a note in the format `DEPRECATION NOTICE: ...`.
5. Any Pull Request introducing a breaking change due to the end of the deprecation notice period must be labeled and include a note in the format `BREAKING CHANGE: ...`.
- It is also recommended for code commits that introduce a breaking change to follow the related [conventional commit spec](https://www.conventionalcommits.org/en/v1.0.0/#specification).
The minimum deprecation period length depends on the affected area. If a single change spans multiple areas, the area with the most extended deprecation period is assumed. Longer deprecation periods are allowed if the feature is deemed to be particularly critical or widely used.
#### Deprecation Period Lengths
_The units represent the number of releases._
##### Before Falco 1.0
| Area | Stable | Incubating |
| -------------- | ------ | ---------- |
| *all areas* | 1 | 0 |
##### Since Falco 1.0 onward
| Area | Stable | Incubating |
| -------------- | ------ | ---------- |
| Behaviors | 2 | 1 |
| Rules System | 2 | 1 |
| Output/Alerts | 2 | 1 |
| Platform | 2 | 1 |
| CLI/Config | 1 | 1 |
| Subsystem APIs | 1 | 0 |
### Examples
**Example 1** Let's consider a feature _foo_ in the Output/Alerts Area introduced in Falco 1.0.0 and labeled as *Incubating*. The feature is promoted to *Stable* in Falco 1.1.0 (because the feature did not get any user-facing change).
Subsequently, maintainers decide that backward-compatible changes must be introduced in _foo_ to improve its functionality. The part of the feature to be changed is labeled as *Deprecated* in Falco 1.2.0, and the deprecation period starts. The non-backward compatible change is then introduced in Falco 1.4.0.
**Example 2** The `--bar` flag in the CLI/Config Area has been introduced since Falco 1.1.0 and is labeled as *Stable*. Before releasing Falco 1.5.0, maintainers realize `--bar` is redundant and should be removed. The flag is labeled as *Deprecated* in Falco 1.5.0, and the deprecation period starts. The flag is removed in Falco 1.6.0.
### Exceptions
- Ruleset in the official distributions follow the [Rules Maturity Framework](https://github.com/falcosecurity/rules/blob/main/CONTRIBUTING.md#rules-maturity-framework) policies.
- Subsystems or subcomponents may have additional criteria and exceptions. Stated other criteria and exceptions must not directly affect the main Falco distribution (e.g., *falcoctl* can have a different release cycle and different policies; however, if Falco relies on a specific *falcoctl* feature, that *falcoctl* feature adoption and deprecation must be strictly compatible with the rules described in this proposal).
- Internal APIs are out of scope for this policy. Their adoption models and deprecation policies might be regulated separately.
- Different parties may provide plugins, and each plugin may have a different maturity level. Only those plugins officially maintained by The Falco Project and identified as "core" for Falco are in scope for this policy; all others are excluded.
- Any other exceptions to the rules provided by this policy require a formal core maintainer majority vote.
### Versioning
Regarding the above policies, component versioning must adhere to [Semantic Versioning 2.0.0](https://semver.org/). However, in the context of Falco core components, the scope extends beyond the strict API definition and includes any user-facing changes.
Thus, given a version number `MAJOR.MINOR.PATCH` increment the:
- *MAJOR* version when the deprecation period of one or more _stable_ features ends, thus introducing incompatible user-facing or API changes.
- *MINOR* version when adding functionality in a backward-compatible manner.
- *PATCH* version when making backward-compatible bug fixes.
Moreover, *MAJOR* version zero (0.y.z) is for versioning stabilization (i.e., before defining the public set of user-facing features and APIs). At this stage, the *MINOR* version is allowed to be incremented instead of the *MAJOR* version.
### Documentation
Documentation must be tied to a specific release and reflect the adoption level status of a feature at that specific release. In particular:
- Deprecated items must be labeled `DEPRECATED` in all relevant documentation.
- Stable items must be sufficiently documented. Explicitly labeling the Stable status is not required or recommended.
- Incubating items must be sufficiently documented and labeled `INCUBATING` in all relevant documentation.
- Sandbox items may be partially documented and labeled `SANDBOX` in all relevant documentation, if any. The relevant documentation must also explicitly state the experimental nature of the item.
## Transition Phases
Since software components may need to adapt to implement the requirements this proposal mandates, we assume the following stages are required to transition from the current state to the desired state fully:
- Within Falco 0.38, at least stable features must be identified, and the adoption policy and relevant documentation should be implemented in Falco. Exceptions may be made temporarily for the deprecation policy.
- Within subsequent releases and no later than Falco 1.0.0 (still not scheduled to date), all the policies must be strictly implemented in Falco and documented in [falco.org](falco.org). The [Rules Maturity Framework](https://github.com/falcosecurity/rules/blob/main/CONTRIBUTING.md#rules-maturity-framework) must be adapted to ensure it aligns with the spirit of this proposal. Exceptions may be made temporarily for other [core projects](https://github.com/falcosecurity/evolution#core) with [stable](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable) status, assuming exceptions don't severely affect the main Falco distribution.
- Within Falco 1.1.0, all the policies must be strictly implemented in Falco and in all [core projects](https://github.com/falcosecurity/evolution#core) with [stable](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable) status.
During the transition phases, maintainers can fine-tune these policies and add further exceptions, eventually. After this initial transition phases, the policy is assumed to be established. From then on, any policy modifications, updates, and exceptions must be subject to a core maintainer majority vote to ensure the policy remains relevant and practical.

View File

@@ -47,18 +47,7 @@ endif()
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)
list(APPEND FALCOCTL_DRIVER_TYPES_LIST "modern_ebpf")
endif()
if (BUILD_DRIVER)
list(APPEND FALCOCTL_DRIVER_TYPES_LIST "kmod")
endif()
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}")
endif()

View File

@@ -17,8 +17,7 @@
# limitations under the License.
#
# By default, we use the automatic selection for drivers
chosen_driver="auto"
chosen_driver=
chosen_unit=
CHOICE=
@@ -39,56 +38,43 @@ systemctl --system disable 'falcoctl-artifact-follow.service' || true
systemctl --system unmask falcoctl-artifact-follow.service || true
if [ "$1" = "configure" ]; then
# "auto" case is not managed here since it is already the default, so no CHOICE=2
case $FALCO_DRIVER_CHOICE in
none)
CHOICE=1
;;
kmod)
CHOICE=3
CHOICE=2
;;
ebpf)
CHOICE=4
CHOICE=3
;;
modern_ebpf)
CHOICE=5
CHOICE=4
;;
esac
if [ -z $CHOICE ] && [ -x /usr/bin/dialog ] && [ "${FALCO_FRONTEND}" != "noninteractive" ]; then
# If dialog is installed, create a dialog to let users choose the correct driver for them
CHOICE=$(dialog --clear --title "Falco drivers" --menu "Choose your preferred driver:" 12 55 4 \
1 "Manual configuration (no unit is started)" \
2 "Automatic selection" \
3 "Kmod" \
4 "eBPF" \
5 "Modern eBPF" \
2 "Kmod" \
3 "eBPF" \
4 "Modern eBPF" \
2>&1 >/dev/tty)
fi
# "auto" case is not managed here since it is already the default, so no CHOICE=2
fi
case $CHOICE in
1)
chosen_driver=""
2)
chosen_driver="kmod"
chosen_unit="kmod"
;;
3)
chosen_driver="kmod"
chosen_driver="ebpf"
chosen_unit="bpf"
;;
4)
chosen_driver="ebpf"
;;
5)
chosen_driver="modern_ebpf"
chosen_unit="modern-bpf"
;;
esac
if [ -n "$chosen_driver" ]; then
echo "[POST-INSTALL] Configure falcoctl '$chosen_driver' driver type:"
if [ "$chosen_driver" = "auto" ]; then
# Configure falcoctl to enable all drivers
falcoctl driver config --type "modern_ebpf" --type "kmod" --type "ebpf"
# Load the actually automatic chosen driver
chosen_driver=$(falcoctl driver printenv | grep DRIVER= | cut -d'"' -f2)
else
falcoctl driver config --type "$chosen_driver"
fi
if [ -n "$CHOICE" ]; then
echo "[POST-INSTALL] Configure falcoctl driver type:"
falcoctl driver config --type $chosen_driver
CHOICE=
case $FALCOCTL_ENABLED in
no)
@@ -122,15 +108,10 @@ case "$chosen_driver" in
# Only compile for kmod, in this way we use dkms
echo "[POST-INSTALL] Call 'falcoctl driver install for kmod:"
falcoctl driver install --download=false
chosen_unit="kmod"
;;
"ebpf")
echo "[POST-INSTALL] Call 'falcoctl driver install for ebpf':"
falcoctl driver install
chosen_unit="bpf"
;;
"modern_ebpf")
chosen_unit="modern-bpf"
;;
esac

View File

@@ -1,5 +1,5 @@
driver:
type: [@FALCOCTL_DRIVER_TYPES@]
type: "kmod"
name: "@DRIVER_NAME@"
repos:
- "@DRIVERS_REPO@"
@@ -10,7 +10,7 @@ artifact:
every: 6h0m0s
falcoVersions: http://localhost:8765/versions
refs:
- falco-rules:3
- falco-rules:0
indexes:
- name: falcosecurity
url: https://falcosecurity.github.io/falcoctl/index.yaml

View File

@@ -39,15 +39,9 @@ fi
s3_bucket_repo="s3://falco-distribution/packages/${repo}/${arch}"
cloudfront_path="/packages/${repo}/${arch}"
# sign
gpg --detach-sign --digest-algo SHA256 --armor ${file}
# publish
package=$(basename -- ${file})
echo "Publishing ${package} to ${s3_bucket_repo}..."
aws s3 cp ${file} ${s3_bucket_repo}/${package} --acl public-read
aws s3 cp ${file}.asc ${s3_bucket_repo}/${package}.asc --acl public-read
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${package}
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${package}.asc
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${package}

View File

@@ -16,8 +16,7 @@
# limitations under the License.
#
# By default, we use the automatic selection for drivers
chosen_driver="auto"
chosen_driver=
chosen_unit=
CHOICE=
@@ -38,56 +37,43 @@ systemctl --system disable 'falcoctl-artifact-follow.service' || true
systemctl --system unmask falcoctl-artifact-follow.service || true
if [ $1 -ge 1 ]; then
# "auto" case is not managed here since it is already the default, so no CHOICE=2
case $FALCO_DRIVER_CHOICE in
none)
CHOICE=1
;;
kmod)
CHOICE=3
CHOICE=2
;;
ebpf)
CHOICE=4
CHOICE=3
;;
modern_ebpf)
CHOICE=5
CHOICE=4
;;
esac
if [ -z $CHOICE ] && [ -x /usr/bin/dialog ] && [ "${FALCO_FRONTEND}" != "noninteractive" ]; then
# If dialog is installed, create a dialog to let users choose the correct driver for them
CHOICE=$(dialog --clear --title "Falco drivers" --menu "Choose your preferred driver:" 12 55 4 \
1 "Manual configuration (no unit is started)" \
2 "Automatic selection" \
3 "Kmod" \
4 "eBPF" \
5 "Modern eBPF" \
2 "Kmod" \
3 "eBPF" \
4 "Modern eBPF" \
2>&1 >/dev/tty)
fi
# "auto" case is not managed here since it is already the default, so no CHOICE=2
fi
case $CHOICE in
1)
chosen_driver=""
2)
chosen_driver="kmod"
chosen_unit="kmod"
;;
3)
chosen_driver="kmod"
chosen_driver="ebpf"
chosen_unit="bpf"
;;
4)
chosen_driver="ebpf"
;;
5)
chosen_driver="modern_ebpf"
chosen_unit="modern-bpf"
;;
esac
if [ -n "$chosen_driver" ]; then
echo "[POST-INSTALL] Configure falcoctl '$chosen_driver' driver type:"
if [ "$chosen_driver" = "auto" ]; then
# Configure falcoctl to enable all drivers
falcoctl driver config --type "modern_ebpf" --type "kmod" --type "ebpf"
# Load the actually automatic chosen driver
chosen_driver=$(falcoctl driver printenv | grep DRIVER= | cut -d'"' -f2)
else
falcoctl driver config --type "$chosen_driver"
fi
if [ -n "$CHOICE" ]; then
echo "[POST-INSTALL] Configure falcoctl driver type:"
falcoctl driver config --type $chosen_driver
CHOICE=
case $FALCOCTL_ENABLED in
no)
@@ -119,17 +105,12 @@ systemctl --system daemon-reload || true
case "$chosen_driver" in
"kmod")
# Only compile for kmod, in this way we use dkms
echo "[POST-INSTALL] Call 'falcoctl driver install for kmod:"
falcoctl driver install --download=false
chosen_unit="kmod"
echo "[POST-INSTALL] Call 'falcoctl driver install for kmod:"
falcoctl driver install --download=false
;;
"ebpf")
echo "[POST-INSTALL] Call 'falcoctl driver install for ebpf':"
falcoctl driver install
chosen_unit="bpf"
;;
"modern_ebpf")
chosen_unit="modern-bpf"
;;
esac

View File

@@ -44,7 +44,6 @@ add_executable(falco_unit_tests
engine/test_rule_loader.cpp
engine/test_rulesets.cpp
falco/test_configuration.cpp
falco/test_configuration_rule_selection.cpp
falco/app/actions/test_select_event_sources.cpp
falco/app/actions/test_load_config.cpp
)
@@ -66,13 +65,10 @@ PRIVATE
${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}
)
if (EMSCRIPTEN)

View File

@@ -263,11 +263,11 @@ static void load_rules(sinsp& inspector,
rule_loader::collector collector;
rule_loader::compiler compiler;
EXPECT_TRUE(reader.read(*cfg, collector));
EXPECT_TRUE(reader.read(*(cfg.get()), collector));
compile_output = compiler.new_compile_output();
compiler.compile(*cfg, collector, *compile_output);
compiler.compile(*(cfg.get()), collector, *(compile_output.get()));
}
TEST(engine_loader_alt_loader, load_rules)
@@ -303,15 +303,16 @@ 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,
ruleset->add_compile_output(*(compile_output.get()),
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
// should be enabled.
bool match_exact = true;
uint16_t ruleset_id = 0;
ruleset->enable("", filter_ruleset::match_type::substring, ruleset_id);
ruleset->enable("", match_exact, ruleset_id);
EXPECT_EQ(ruleset->enabled_count(ruleset_id), 1);
}

View File

@@ -44,36 +44,6 @@ static std::string single_rule = R"END(
tags: [exec process]
)END";
static std::string multi_rule = R"END(
- rule: first actual rule
desc: A test rule
condition: evt.type=execve
output: A test rule matched (evt.type=%evt.type)
priority: INFO
source: syscall
tags: [process]
- rule: second disabled rule
desc: A disabled rule
condition: evt.type=execve
output: A disabled 2 rule matched (evt.type=%evt.type)
priority: INFO
source: syscall
enabled: false
tags: [exec process]
- rule: third disabled rule
desc: A disabled rule
condition: evt.type=execve
output: A disabled 3 rule matched (evt.type=%evt.type)
priority: INFO
source: syscall
enabled: false
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";
@@ -246,41 +216,3 @@ TEST_F(test_falco_engine, enable_rule_name_exact)
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(2, m_engine->num_rules_for_ruleset(ruleset_4));
}
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));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
// As long as there are no *, exact matches work
m_engine->enable_rule_wildcard("first actual rule", true, ruleset_1);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
m_engine->enable_rule_wildcard("*rule", true, ruleset_2);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(3, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
// This should enable the second rule
m_engine->enable_rule_wildcard("*second*r*", true, ruleset_3);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(3, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
m_engine->enable_rule_wildcard("*", true, ruleset_4);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(3, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(3, m_engine->num_rules_for_ruleset(ruleset_4));
}

View File

@@ -72,32 +72,3 @@ TEST(FalcoUtils, parse_prometheus_interval)
*/
ASSERT_EQ(falco::utils::parse_prometheus_interval("200"), 0UL);
}
TEST(FalcoUtils, sanitize_metric_name)
{
ASSERT_EQ(falco::utils::sanitize_metric_name("Testing rule 2 (CVE-2244)"), "Testing_rule_2_CVE_2244");
ASSERT_EQ(falco::utils::sanitize_metric_name("Testing rule__:2)"), "Testing_rule_:2");
ASSERT_EQ(falco::utils::sanitize_metric_name("This@is_a$test rule123"), "This_is_a_test_rule123");
ASSERT_EQ(falco::utils::sanitize_metric_name("RULEwith:special#characters"), "RULEwith:special_characters");
}
TEST(FalcoUtils, matches_wildcard)
{
ASSERT_TRUE(falco::utils::matches_wildcard("*", "anything"));
ASSERT_TRUE(falco::utils::matches_wildcard("**", "anything"));
ASSERT_TRUE(falco::utils::matches_wildcard("*", ""));
ASSERT_TRUE(falco::utils::matches_wildcard("no star", "no star"));
ASSERT_TRUE(falco::utils::matches_wildcard("", ""));
ASSERT_TRUE(falco::utils::matches_wildcard("hello*world", "hello new world"));
ASSERT_TRUE(falco::utils::matches_wildcard("hello*world*", "hello new world yes"));
ASSERT_TRUE(falco::utils::matches_wildcard("*hello*world", "come on hello this world"));
ASSERT_TRUE(falco::utils::matches_wildcard("*hello*****world", "come on hello this world"));
ASSERT_FALSE(falco::utils::matches_wildcard("no star", ""));
ASSERT_FALSE(falco::utils::matches_wildcard("", "no star"));
ASSERT_FALSE(falco::utils::matches_wildcard("star", "no star"));
ASSERT_FALSE(falco::utils::matches_wildcard("hello*world", "hello new thing"));
ASSERT_FALSE(falco::utils::matches_wildcard("hello*world", "hello new world yes"));
ASSERT_FALSE(falco::utils::matches_wildcard("*hello*world", "come on hello this world yes"));
ASSERT_FALSE(falco::utils::matches_wildcard("*hello*world*", "come on hello this yes"));
}

View File

@@ -8,7 +8,7 @@ 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
Unless ASSERT_EQd 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
@@ -18,8 +18,6 @@ limitations under the License.
#include <gtest/gtest.h>
#include <engine/filter_macro_resolver.h>
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)
@@ -37,19 +35,19 @@ static std::vector<filter_macro_resolver::value_info>::const_iterator find_value
TEST(MacroResolver, should_resolve_macros_on_a_filter_AST)
{
filter_ast::pos_info macro_pos(12, 85, 27);
libsinsp::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<libsinsp::filter::ast::expr> macro = libsinsp::filter::ast::unary_check_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)));
std::shared_ptr<filter_ast::expr> filter = filter_ast::and_expr::create(filter_and);
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> filter_and;
filter_and.push_back(libsinsp::filter::ast::unary_check_expr::create("evt.name", "", "exists"));
filter_and.push_back(libsinsp::filter::ast::not_expr::create(libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos)));
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::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::not_expr::create(clone(macro.get())));
std::shared_ptr<filter_ast::expr> expected = filter_ast::and_expr::create(expected_and);
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> expected_and;
expected_and.push_back(libsinsp::filter::ast::unary_check_expr::create("evt.name", "", "exists"));
expected_and.push_back(libsinsp::filter::ast::not_expr::create(clone(macro.get())));
std::shared_ptr<libsinsp::filter::ast::expr> expected = libsinsp::filter::ast::and_expr::create(expected_and);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
@@ -71,17 +69,17 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST)
TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_single_node)
{
filter_ast::pos_info macro_pos(12, 85, 27);
libsinsp::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<libsinsp::filter::ast::expr> macro = libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists");
std::shared_ptr<filter_ast::expr> filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos);
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
// first run
filter_ast::expr* old_filter_ptr = filter.get();
libsinsp::filter::ast::expr* old_filter_ptr = filter.get();
ASSERT_TRUE(resolver.run(filter));
ASSERT_NE(filter.get(), old_filter_ptr);
ASSERT_EQ(resolver.get_resolved_macros().size(), 1);
@@ -101,21 +99,21 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_single_node)
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);
libsinsp::filter::ast::pos_info a_macro_pos(11, 75, 43);
libsinsp::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<libsinsp::filter::ast::expr> a_macro = libsinsp::filter::ast::unary_check_expr::create("one.field", "", "exists");
std::shared_ptr<libsinsp::filter::ast::expr> b_macro = libsinsp::filter::ast::unary_check_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));
filter_or.push_back(filter_ast::identifier_expr::create(MACRO_B_NAME, b_macro_pos));
std::shared_ptr<filter_ast::expr> filter = filter_ast::or_expr::create(filter_or);
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> filter_or;
filter_or.push_back(libsinsp::filter::ast::value_expr::create(MACRO_A_NAME, a_macro_pos));
filter_or.push_back(libsinsp::filter::ast::value_expr::create(MACRO_B_NAME, b_macro_pos));
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::or_expr::create(filter_or);
std::vector<std::unique_ptr<filter_ast::expr>> expected_or;
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> expected_or;
expected_or.push_back(clone(a_macro.get()));
expected_or.push_back(clone(b_macro.get()));
std::shared_ptr<filter_ast::expr> expected_filter = filter_ast::or_expr::create(expected_or);
std::shared_ptr<libsinsp::filter::ast::expr> expected_filter = libsinsp::filter::ast::or_expr::create(expected_or);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_A_NAME, a_macro);
@@ -145,23 +143,23 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_multiple_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);
libsinsp::filter::ast::pos_info a_macro_pos(47, 1, 76);
libsinsp::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::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::vector<std::unique_ptr<libsinsp::filter::ast::expr>> a_macro_and;
a_macro_and.push_back(libsinsp::filter::ast::unary_check_expr::create("one.field", "", "exists"));
a_macro_and.push_back(libsinsp::filter::ast::value_expr::create(MACRO_B_NAME, b_macro_pos));
std::shared_ptr<libsinsp::filter::ast::expr> a_macro = libsinsp::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<libsinsp::filter::ast::expr> b_macro =
libsinsp::filter::ast::unary_check_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<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::value_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"));
std::shared_ptr<filter_ast::expr> expected_filter = filter_ast::and_expr::create(expected_and);
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> expected_and;
expected_and.push_back(libsinsp::filter::ast::unary_check_expr::create("one.field", "", "exists"));
expected_and.push_back(libsinsp::filter::ast::unary_check_expr::create("another.field", "", "exists"));
std::shared_ptr<libsinsp::filter::ast::expr> expected_filter = libsinsp::filter::ast::and_expr::create(expected_and);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_A_NAME, a_macro);
@@ -193,12 +191,12 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_nested_macros)
TEST(MacroResolver, should_find_unknown_macros)
{
filter_ast::pos_info macro_pos(9, 4, 2);
libsinsp::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)));
std::shared_ptr<filter_ast::expr> filter = filter_ast::and_expr::create(filter_and);
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> filter_and;
filter_and.push_back(libsinsp::filter::ast::unary_check_expr::create("evt.name", "", "exists"));
filter_and.push_back(libsinsp::filter::ast::not_expr::create(libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos)));
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::and_expr::create(filter_and);
filter_macro_resolver resolver;
ASSERT_FALSE(resolver.run(filter));
@@ -210,15 +208,15 @@ TEST(MacroResolver, should_find_unknown_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);
libsinsp::filter::ast::pos_info a_macro_pos(32, 84, 9);
libsinsp::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::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::vector<std::unique_ptr<libsinsp::filter::ast::expr>> a_macro_and;
a_macro_and.push_back(libsinsp::filter::ast::unary_check_expr::create("one.field", "", "exists"));
a_macro_and.push_back(libsinsp::filter::ast::value_expr::create(MACRO_B_NAME, b_macro_pos));
std::shared_ptr<libsinsp::filter::ast::expr> a_macro = libsinsp::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<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::value_expr::create(MACRO_A_NAME, a_macro_pos);
auto expected_filter = clone(a_macro.get());
filter_macro_resolver resolver;
@@ -236,12 +234,12 @@ TEST(MacroResolver, should_find_unknown_nested_macros)
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);
libsinsp::filter::ast::pos_info macro_pos_1(12, 9, 3);
libsinsp::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<libsinsp::filter::ast::expr> macro = libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists");
std::shared_ptr<libsinsp::filter::ast::expr> a_filter = libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos_1);
std::shared_ptr<libsinsp::filter::ast::expr> b_filter = libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos_2);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
@@ -263,9 +261,9 @@ TEST(MacroResolver, should_undefine_macro)
/* checks that the macro AST is cloned and not shared across resolved filters */
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);
libsinsp::filter::ast::pos_info macro_pos(5, 2, 8888);
std::shared_ptr<libsinsp::filter::ast::unary_check_expr> macro = libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists");
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
@@ -276,6 +274,6 @@ TEST(MacroResolver, should_clone_macro_AST)
ASSERT_TRUE(resolver.get_unknown_macros().empty());
ASSERT_TRUE(filter->is_equal(macro.get()));
macro->left = filter_ast::field_expr::create("another.field", "");
macro->field = "another.field";
ASSERT_FALSE(filter->is_equal(macro.get()));
}

View File

@@ -8,7 +8,7 @@ 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
Unless ASSERTd 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

View File

@@ -680,42 +680,6 @@ 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(
- rule: test_rule
desc: test rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
exceptions:
- name: test_exception
fields: proc.name
comps: in
values: ["cat"]
# when appending, it's fine to provide partial exception definitions
- rule: test_rule
exceptions:
- name: test_exception
values: [echo]
override:
exceptions: append
# when replacing, we don't allow partial exception definitions
- rule: test_rule
exceptions:
- name: test_exception
values: [id]
override:
exceptions: replace
)END";
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_FALSE(has_warnings());
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(
@@ -881,300 +845,4 @@ TEST_F(test_falco_engine, list_value_with_escaping)
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");
}
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
output: command=%proc.cmdline
priority: INFO
exceptions:
- name: test_exception
fields: [proc.cmdline]
comps: [contains]
values:
- [curl 127.0.0.1]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
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(
- macro: test-macro
condition: evt.type = close
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
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(
- list: test list
items: [open, openat, openat2]
- rule: test_rule
desc: test rule description
condition: evt.type in (test list)
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
enabled: false
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
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(
- rule: test_rule
desc: test rule
condition: proc.cmdline contains curl
output: command=%proc.cmdline
priority: INFO
exceptions:
- name: test_exception
fields: [proc.cmdline]
comps: [contains]
values:
- [curl 127.0.0.1]
- rule: test_rule
exceptions:
- name: test_exception
value: curl 1.1.1.1
append: true
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
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(
- rule: test_rule
desc: test rule
condition: proc.cmdline contains curl
output: command=%proc.cmdline
priority: INFO
exceptions:
- name: test_exception
fields: [proc.cmdline]
comps: [contains]
values:
- [curl 127.0.0.1]
- rule: test_rule
exceptions:
- name: test_exception
value: curl 1.1.1.1
override:
exceptions: append
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
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(
- rule: test_rule
desc: test rule
condition: proc.cmdline contains curl
output: command=%proc.cmdline
priority: INFO
exceptions:
- name: test_exception
fields: [proc.cmdline]
comps: [contains]
values:
- [curl 127.0.0.1]
- name: test_exception
fields: [proc.cmdline]
comps: [endswith]
values:
- [curl 127.0.0.1]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_warning_message("Multiple definitions of exception"));
}
static std::string s_exception_values_rule_base = R"END(
- rule: test_rule
desc: test rule
condition: evt.type = open
output: command=%proc.cmdline
priority: INFO
)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]
comps: [=]
values:
- [proc.pname]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = proc.pname)");
EXPECT_TRUE(check_warning_message("string 'proc.pname' may be a valid field wrongly interpreted as a string value"));
}
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]
comps: [=]
values:
- ["proc.pname"]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = proc.pname)");
EXPECT_TRUE(check_warning_message("string 'proc.pname' may be a valid field wrongly interpreted as a string value"));
}
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]
comps: [=]
values:
- ["proc.pname "]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = \"proc.pname \")");
EXPECT_TRUE(check_warning_message("string 'proc.pname ' may be a valid field wrongly interpreted as a string value"));
}
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]
comps: [=]
values:
- [toupper(proc.pname)]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
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(
exceptions:
- name: test_exception
fields: [proc.name]
comps: [=]
values:
- ["toupper(proc.pname)"]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
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(
exceptions:
- name: test_exception
fields: [proc.name]
comps: [=]
values:
- [toupper( proc.pname)]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = \"toupper( proc.pname)\")");
EXPECT_TRUE(check_warning_message("string 'toupper( proc.pname)' may be a valid field transformer wrongly interpreted as a string value"));
}
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]
comps: [=]
values:
- ["toupper( proc.pname)"]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not proc.name = \"toupper( proc.pname)\")");
EXPECT_TRUE(check_warning_message("string 'toupper( proc.pname)' may be a valid field transformer wrongly interpreted as a string value"));
}
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)]
comps: [=]
values:
- [test]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
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(
exceptions:
- name: test_exception
fields: ["tolower(proc.name)"]
comps: [=]
values:
- [test]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
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(
exceptions:
- name: test_exception
fields: ["tolower( proc.name)"]
comps: [=]
values:
- [test]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_FALSE(has_warnings());
EXPECT_EQ(get_compiled_rule_condition("test_rule"), "(evt.type = open and not tolower(proc.name) = test)");
}
}

View File

@@ -74,70 +74,46 @@ TEST(Ruleset, enable_disable_rules_using_names)
r->add(rule_C, filter, ast);
/* Enable `rule_A` for RULESET_0 */
r->enable(rule_A.name, filter_ruleset::match_type::exact, RULESET_0);
r->enable(rule_A.name, true, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 1);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Disable `rule_A` for RULESET_1, this should have no effect */
r->disable(rule_A.name, filter_ruleset::match_type::exact, RULESET_1);
r->disable(rule_A.name, true, RULESET_1);
ASSERT_EQ(r->enabled_count(RULESET_0), 1);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Enable a not existing rule for RULESET_2, this should have no effect */
r->disable("<NA>", filter_ruleset::match_type::exact, RULESET_2);
r->disable("<NA>", true, RULESET_2);
ASSERT_EQ(r->enabled_count(RULESET_0), 1);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Enable all rules for RULESET_0 */
r->enable("rule_", filter_ruleset::match_type::substring, RULESET_0);
r->enable("rule_", false, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 3);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Try to disable all rules with exact match for RULESET_0, this should have no effect */
r->disable("rule_", filter_ruleset::match_type::exact, RULESET_0);
r->disable("rule_", true, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 3);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Disable all rules for RULESET_0 */
r->disable("rule_", filter_ruleset::match_type::substring, RULESET_0);
r->disable("rule_", false, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 0);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Enable rule_C for RULESET_2 without exact_match */
r->enable("_C", filter_ruleset::match_type::substring, RULESET_2);
r->enable("_C", false, RULESET_2);
ASSERT_EQ(r->enabled_count(RULESET_0), 0);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 1);
/* Disable rule_C for RULESET_2 without exact_match */
r->disable("_C", filter_ruleset::match_type::substring, RULESET_2);
ASSERT_EQ(r->enabled_count(RULESET_0), 0);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Enable all rules for RULESET_0 with wildcard */
r->enable("*", filter_ruleset::match_type::wildcard, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 3);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Disable rule C for RULESET_0 with wildcard */
r->disable("*C*", filter_ruleset::match_type::wildcard, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 2);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Disable all rules for RULESET_0 with wildcard */
r->disable("*_*", filter_ruleset::match_type::wildcard, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 0);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
}
TEST(Ruleset, enable_disable_rules_using_tags)

View File

@@ -108,7 +108,6 @@ TEST_F(test_falco_engine, preconditions_postconditions)
s1.engine = nullptr;
s1.config = std::make_shared<falco_configuration>();
s1.options.all_events = false;
auto result = falco::app::actions::configure_interesting_sets(s1);
ASSERT_FALSE(result.success);
ASSERT_NE(result.errstr, "");

View File

@@ -8,7 +8,7 @@ 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
Unless ASSERTd 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

View File

@@ -8,7 +8,7 @@ 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
Unless ASSERTd 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

View File

@@ -8,7 +8,7 @@ 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
Unless ASSERTd 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

View File

@@ -8,7 +8,7 @@ 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
Unless ASSERTd 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
@@ -16,7 +16,7 @@ limitations under the License.
*/
#include <falco/atomic_signal_handler.h>
#include <engine/logger.h>
#include <falco/logger.h>
#include <gtest/gtest.h>

View File

@@ -8,7 +8,7 @@ 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
Unless ASSERTd 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
@@ -109,484 +109,6 @@ TEST(Configuration, modify_yaml_fields)
ASSERT_EQ(conf.get_scalar<bool>(key, false), true);
}
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;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_ANY_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
std::filesystem::remove("main.yaml");
std::filesystem::remove("conf_2.yaml");
}
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 conf_yaml_2 =
"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";
const std::string conf_yaml_4 =
"base_value_4:\n"
" id: 4\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
outfile.open("conf_3.yaml");
outfile << conf_yaml_3;
outfile.close();
outfile.open("conf_4.yaml");
outfile << conf_yaml_4;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main + conf_2 + conf_3
ASSERT_EQ(loaded_conf_files.size(), 3);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
ASSERT_TRUE(falco_config.config.is_defined("foo3"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo3", ""), "bar3");
ASSERT_TRUE(falco_config.config.is_defined("base_value_3.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_3.id", 0), 3);
ASSERT_TRUE(falco_config.config.is_defined("base_value_3.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value_3.name", ""), "foo3");
ASSERT_FALSE(falco_config.config.is_defined("base_value_4.id")); // conf_4 is not included
std::filesystem::remove("main.yaml");
std::filesystem::remove("conf_2.yaml");
std::filesystem::remove("conf_3.yaml");
std::filesystem::remove("conf_4.yaml");
}
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.
*/
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 conf_yaml_2 =
"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";
std::ofstream outfile(temp_main.string());
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
outfile.open("conf_3.yaml");
outfile << conf_yaml_3;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file(temp_main.string(), loaded_conf_files, cmdline_config_options));
// main + conf_2 + conf_3
ASSERT_EQ(loaded_conf_files.size(), 3);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
ASSERT_TRUE(falco_config.config.is_defined("base_value_3.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_3.id", 0), 3);
std::filesystem::remove(temp_main.string());
std::filesystem::remove("conf_2.yaml");
std::filesystem::remove("conf_3.yaml");
}
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 conf_yaml_2 =
"foo2: bar2\n"
"base_value_2:\n"
" id: 2\n";
const std::string conf_yaml_3 =
"base_value:\n"
" id: 3\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
outfile.open("conf_3.yaml");
outfile << conf_yaml_3;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main + conf_2 + conf_3
ASSERT_EQ(loaded_conf_files.size(), 3);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 3); // overridden!
ASSERT_FALSE(falco_config.config.is_defined("base_value.name")); // no more present since entire `base_value` block was overridden
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
ASSERT_FALSE(falco_config.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 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";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main
ASSERT_EQ(loaded_conf_files.size(), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
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";
const std::string conf_yaml_2 =
"foo2: bar2\n"
"base_value_2:\n"
" id: 2\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main + conf_2
ASSERT_EQ(loaded_conf_files.size(), 2);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
std::filesystem::remove("main.yaml");
std::filesystem::remove("conf_2.yaml");
}
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";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main
ASSERT_EQ(loaded_conf_files.size(), 1);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
std::filesystem::remove("main.yaml");
}
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";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_ANY_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
std::filesystem::remove("main.yaml");
}
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 conf_yaml_2 =
"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";
std::filesystem::create_directory(std::filesystem::temp_directory_path() / "test");
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
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 << 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 << conf_yaml_4;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main + conf_2 + conf_3.
// test/foo is not parsed.
ASSERT_EQ(loaded_conf_files.size(), 3);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
ASSERT_TRUE(falco_config.config.is_defined("base_value_3.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_3.id", 0), 3);
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar3");
ASSERT_FALSE(falco_config.config.is_defined("foo4"));
std::filesystem::remove("main");
std::filesystem::remove_all(std::filesystem::temp_directory_path()/"test");
}
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";
const std::string conf_yaml_2 =
"foo2: bar2\n"
"base_value_2:\n"
" id: 2\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
// Pass "config_files=..." cmdline option
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back((yaml_helper::configs_key+"=conf_2.yaml"));
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main + conf_2
ASSERT_EQ(loaded_conf_files.size(), 2);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
std::filesystem::remove("main.yaml");
std::filesystem::remove("conf_2.yaml");
}
TEST(Configuration, configuration_environment_variables)
{
// Set an environment variable for testing purposes
@@ -799,9 +321,9 @@ TEST(Configuration, configuration_webserver_ip)
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(cmdline_config_options));
ASSERT_EQ(falco_config.m_webserver_config.m_listen_address, address);
ASSERT_EQ(falco_config.m_webserver_listen_address, address);
}
std::vector<std::string> invalid_addresses = {"327.0.0.1",
@@ -836,6 +358,6 @@ TEST(Configuration, configuration_webserver_ip)
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(cmdline_config_options));
}
}

View File

@@ -1,60 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <gtest/gtest.h>
#include <falco/configuration.h>
TEST(ConfigurationRuleSelection, parse_yaml)
{
falco_configuration falco_config;
EXPECT_NO_THROW(falco_config.init_from_content(R"(
rules:
- enable:
rule: 'Terminal Shell in Container'
- disable:
tag: experimental
- enable:
rule: 'hello*'
)", {}));
ASSERT_EQ(falco_config.m_rules_selection.size(), 3);
ASSERT_EQ(falco_config.m_rules_selection[0].m_op, falco_configuration::rule_selection_operation::enable);
ASSERT_EQ(falco_config.m_rules_selection[0].m_rule, "Terminal Shell in Container");
ASSERT_EQ(falco_config.m_rules_selection[1].m_op, falco_configuration::rule_selection_operation::disable);
ASSERT_EQ(falco_config.m_rules_selection[1].m_tag, "experimental");
ASSERT_EQ(falco_config.m_rules_selection[2].m_op, falco_configuration::rule_selection_operation::enable);
ASSERT_EQ(falco_config.m_rules_selection[2].m_rule, "hello*");
}
TEST(ConfigurationRuleSelection, cli_options)
{
falco_configuration falco_config;
EXPECT_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_EQ(falco_config.m_rules_selection.size(), 2);
ASSERT_EQ(falco_config.m_rules_selection[0].m_op, falco_configuration::rule_selection_operation::disable);
ASSERT_EQ(falco_config.m_rules_selection[0].m_tag, "maturity_incubating");
ASSERT_EQ(falco_config.m_rules_selection[1].m_op, falco_configuration::rule_selection_operation::enable);
ASSERT_EQ(falco_config.m_rules_selection[1].m_rule, "Adding ssh keys to authorized_keys");
}

View File

@@ -22,7 +22,6 @@ add_library(falco_engine STATIC
filter_details_resolver.cpp
filter_macro_resolver.cpp
filter_warning_resolver.cpp
logger.cpp
stats_manager.cpp
rule_loader.cpp
rule_loader_reader.cpp
@@ -34,15 +33,18 @@ if (EMSCRIPTEN)
target_compile_options(falco_engine PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
endif()
add_dependencies(falco_engine yamlcpp njson)
target_include_directories(falco_engine
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${nlohmann_json_INCLUDE_DIRS}
${TBB_INCLUDE_DIR}
${YAMLCPP_INCLUDE_DIR}
)
target_link_libraries(falco_engine
PUBLIC
sinsp
nlohmann_json::nlohmann_json
yaml-cpp
${YAMLCPP_LIB}
)

View File

@@ -17,10 +17,6 @@ limitations under the License.
#include "evttype_index_ruleset.h"
#include "falco_utils.h"
#include "logger.h"
#include <algorithm>
evttype_index_ruleset::evttype_index_ruleset(
@@ -227,75 +223,50 @@ void evttype_index_ruleset::add(
void evttype_index_ruleset::on_loading_complete()
{
print_enabled_rules_falco_logger();
}
void evttype_index_ruleset::print_enabled_rules_falco_logger()
{
falco_logger::log(falco_logger::level::DEBUG, "Enabled rules:\n");
int n = 0;
for (const auto& ruleset_ptr : m_rulesets)
{
if (ruleset_ptr)
{
for (const auto& wrap : ruleset_ptr->get_filters())
{
n++;
falco_logger::log(falco_logger::level::DEBUG, std::string(" ") + wrap->rule.name + "\n");
}
}
}
falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(n) + ") enabled rules in total\n");
// nothing to do for now
}
void evttype_index_ruleset::clear()
{
for (size_t i = 0; i < m_rulesets.size(); i++)
{
m_rulesets[i] = std::make_shared<ruleset_filters>();
std::shared_ptr<ruleset_filters> r(new ruleset_filters());
m_rulesets[i] = r;
}
m_filters.clear();
}
void evttype_index_ruleset::enable(const std::string &pattern, match_type match, uint16_t ruleset_id)
void evttype_index_ruleset::enable(const std::string &substring, bool match_exact, uint16_t ruleset_id)
{
enable_disable(pattern, match, true, ruleset_id);
enable_disable(substring, match_exact, true, ruleset_id);
}
void evttype_index_ruleset::disable(const std::string &pattern, match_type match, uint16_t ruleset_id)
void evttype_index_ruleset::disable(const std::string &substring, bool match_exact, uint16_t ruleset_id)
{
enable_disable(pattern, match, false, ruleset_id);
enable_disable(substring, match_exact, false, ruleset_id);
}
void evttype_index_ruleset::enable_disable(const std::string &pattern, match_type match, bool enabled, uint16_t ruleset_id)
void evttype_index_ruleset::enable_disable(const std::string &substring, bool match_exact, 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.emplace_back(new ruleset_filters());
}
for(const auto &wrap : m_filters)
{
bool matches;
std::string::size_type pos;
switch(match)
if(match_exact)
{
case match_type::exact:
pos = wrap->rule.name.find(pattern);
size_t pos = wrap->rule.name.find(substring);
matches = (pattern == "" || (pos == 0 &&
pattern.size() == wrap->rule.name.size()));
break;
case match_type::substring:
matches = (pattern == "" || (wrap->rule.name.find(pattern) != std::string::npos));
break;
case match_type::wildcard:
matches = falco::utils::matches_wildcard(pattern, wrap->rule.name);
break;
default:
// should never happen
matches = false;
matches = (substring == "" || (pos == 0 &&
substring.size() == wrap->rule.name.size()));
}
else
{
matches = (substring == "" || (wrap->rule.name.find(substring) != std::string::npos));
}
if(matches)
@@ -326,7 +297,7 @@ void evttype_index_ruleset::enable_disable_tags(const std::set<std::string> &tag
{
while(m_rulesets.size() < (size_t)ruleset_id + 1)
{
m_rulesets.emplace_back(std::make_shared<ruleset_filters>());
m_rulesets.emplace_back(new ruleset_filters());
}
for(const auto &wrap : m_filters)
@@ -355,7 +326,7 @@ uint64_t evttype_index_ruleset::enabled_count(uint16_t ruleset_id)
{
while(m_rulesets.size() < (size_t)ruleset_id + 1)
{
m_rulesets.emplace_back(std::make_shared<ruleset_filters>());
m_rulesets.emplace_back(new ruleset_filters());
}
return m_rulesets[ruleset_id]->num_filters();

View File

@@ -52,18 +52,14 @@ public:
void on_loading_complete() override;
// Print each enabled rule when running Falco with falco logger
// log_level=debug; invoked within on_loading_complete()
void print_enabled_rules_falco_logger();
void enable(
const std::string &pattern,
match_type match,
const std::string &substring,
bool match_exact,
uint16_t rulset_id) override;
void disable(
const std::string &pattern,
match_type match,
const std::string &substring,
bool match_exact,
uint16_t rulset_id) override;
void enable_tags(
@@ -89,8 +85,8 @@ private:
// Helper used by enable()/disable()
void enable_disable(
const std::string &pattern,
match_type match,
const std::string &substring,
bool match_exact,
bool enabled,
uint16_t rulset_id);
@@ -122,17 +118,12 @@ private:
uint64_t num_filters();
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(sinsp_evt *evt, falco_rule& match);
// Evaluate an event against the ruleset and return all the
// matching rules.
// Evaluate an event against the ruleset and return all the
// matching rules.
bool run(sinsp_evt *evt, std::vector<falco_rule>& matches);
libsinsp::events::set<ppm_sc_code> sc_codes();
@@ -173,7 +164,9 @@ public:
inline std::shared_ptr<filter_ruleset> new_ruleset() override
{
return std::make_shared<evttype_index_ruleset>(m_filter_factory);
std::shared_ptr<filter_ruleset> ret(
new evttype_index_ruleset(m_filter_factory));
return ret;
}
private:

View File

@@ -28,8 +28,6 @@ limitations under the License.
//
#define DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE std::ptrdiff_t(~size_t(0) / 2)
#define DEFAULT_FALCO_LIBS_THREAD_TABLE_SIZE 262144
//
// Most falco_* classes can throw exceptions. Unless directly related
// to low-level failures like inability to open file, etc, they will

View File

@@ -198,11 +198,11 @@ std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_c
cfg.replace_output_container_info = m_replace_container_info;
// read rules YAML file and collect its definitions
if(m_rule_reader->read(cfg, *m_rule_collector))
if(m_rule_reader->read(cfg, *(m_rule_collector.get())))
{
// compile the definitions (resolve macro/list refs, exceptions, ...)
m_last_compile_output = m_rule_compiler->new_compile_output();
m_rule_compiler->compile(cfg, *m_rule_collector, *m_last_compile_output);
m_rule_compiler->compile(cfg, *(m_rule_collector.get()), *m_last_compile_output.get());
// clear the rules known by the engine and each ruleset
m_rules.clear();
@@ -210,7 +210,7 @@ std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_c
// add rules to each ruleset
{
src.ruleset = create_ruleset(src.ruleset_factory);
src.ruleset->add_compile_output(*m_last_compile_output,
src.ruleset->add_compile_output(*(m_last_compile_output.get()),
m_min_priority,
src.name);
}
@@ -242,11 +242,11 @@ std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_c
}
if(info->enabled)
{
source->ruleset->enable(rule.name, filter_ruleset::match_type::exact, m_default_ruleset_id);
source->ruleset->enable(rule.name, true, m_default_ruleset_id);
}
else
{
source->ruleset->disable(rule.name, filter_ruleset::match_type::exact, m_default_ruleset_id);
source->ruleset->disable(rule.name, true, m_default_ruleset_id);
}
}
}
@@ -272,15 +272,17 @@ void falco_engine::enable_rule(const std::string &substring, bool enabled, const
void falco_engine::enable_rule(const std::string &substring, bool enabled, const uint16_t ruleset_id)
{
bool match_exact = false;
for(const auto &it : m_sources)
{
if(enabled)
{
it.ruleset->enable(substring, filter_ruleset::match_type::substring, ruleset_id);
it.ruleset->enable(substring, match_exact, ruleset_id);
}
else
{
it.ruleset->disable(substring, filter_ruleset::match_type::substring, ruleset_id);
it.ruleset->disable(substring, match_exact, ruleset_id);
}
}
}
@@ -294,37 +296,17 @@ void falco_engine::enable_rule_exact(const std::string &rule_name, bool enabled,
void falco_engine::enable_rule_exact(const std::string &rule_name, bool enabled, const uint16_t ruleset_id)
{
bool match_exact = true;
for(const auto &it : m_sources)
{
if(enabled)
{
it.ruleset->enable(rule_name, filter_ruleset::match_type::exact, ruleset_id);
it.ruleset->enable(rule_name, match_exact, ruleset_id);
}
else
{
it.ruleset->disable(rule_name, filter_ruleset::match_type::exact, ruleset_id);
}
}
}
void falco_engine::enable_rule_wildcard(const std::string &rule_name, bool enabled, const std::string &ruleset)
{
uint16_t ruleset_id = find_ruleset_id(ruleset);
enable_rule_wildcard(rule_name, enabled, ruleset_id);
}
void falco_engine::enable_rule_wildcard(const std::string &rule_name, bool enabled, const uint16_t ruleset_id)
{
for(const auto &it : m_sources)
{
if(enabled)
{
it.ruleset->enable(rule_name, filter_ruleset::match_type::wildcard, ruleset_id);
}
else
{
it.ruleset->disable(rule_name, filter_ruleset::match_type::wildcard, ruleset_id);
it.ruleset->disable(rule_name, match_exact, ruleset_id);
}
}
}
@@ -468,8 +450,9 @@ std::size_t falco_engine::add_source(const std::string &source,
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory)
{
// evttype_index_ruleset is the default ruleset implementation
size_t idx = add_source(source, filter_factory, formatter_factory,
std::make_shared<evttype_index_ruleset_factory>(filter_factory));
std::shared_ptr<filter_ruleset_factory> ruleset_factory(
new evttype_index_ruleset_factory(filter_factory));
size_t idx = add_source(source, filter_factory, formatter_factory, ruleset_factory);
if(source == falco_common::syscall_source)
{
@@ -503,7 +486,7 @@ template <typename T> inline nlohmann::json sequence_to_json_array(const T& seq)
return ret;
}
nlohmann::json falco_engine::describe_rule(std::string *rule_name, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
nlohmann::json falco_engine::describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{
// use previously-loaded collector definitions and the compiled
// output of rules, macros, and lists.
@@ -514,7 +497,7 @@ nlohmann::json falco_engine::describe_rule(std::string *rule_name, const std::ve
// use collected and compiled info to print a json output
nlohmann::json output;
if(!rule_name)
if(!rule)
{
// Store required engine version
auto required_engine_version = m_rule_collector->required_engine_version();
@@ -545,51 +528,51 @@ nlohmann::json falco_engine::describe_rule(std::string *rule_name, const std::ve
// Store information about rules
nlohmann::json rules_array = nlohmann::json::array();
for(const auto& rule : m_last_compile_output->rules)
for(const auto& r : m_last_compile_output->rules)
{
auto info = m_rule_collector->rules().at(rule.name);
nlohmann::json details;
get_json_details(details, rule, *info, plugins);
rules_array.push_back(std::move(details));
auto info = m_rule_collector->rules().at(r.name);
nlohmann::json rule;
get_json_details(rule, r, *info, plugins);
rules_array.push_back(std::move(rule));
}
output["rules"] = std::move(rules_array);
// Store information about macros
nlohmann::json macros_array = nlohmann::json::array();
for(const auto &macro : m_last_compile_output->macros)
for(const auto &m : m_last_compile_output->macros)
{
auto info = m_rule_collector->macros().at(macro.name);
nlohmann::json details;
get_json_details(details, macro, *info, plugins);
macros_array.push_back(std::move(details));
auto info = m_rule_collector->macros().at(m.name);
nlohmann::json macro;
get_json_details(macro, m, *info, plugins);
macros_array.push_back(std::move(macro));
}
output["macros"] = std::move(macros_array);
// Store information about lists
nlohmann::json lists_array = nlohmann::json::array();
for(const auto &list : m_last_compile_output->lists)
for(const auto &l : m_last_compile_output->lists)
{
auto info = m_rule_collector->lists().at(list.name);
nlohmann::json details;
get_json_details(details, list, *info, plugins);
lists_array.push_back(std::move(details));
auto info = m_rule_collector->lists().at(l.name);
nlohmann::json list;
get_json_details(list, l, *info, plugins);
lists_array.push_back(std::move(list));
}
output["lists"] = std::move(lists_array);
}
else
{
// build json information for just the specified rule
auto ri = m_rule_collector->rules().at(*rule_name);
auto ri = m_rule_collector->rules().at(*rule);
if(ri == nullptr || ri->unknown_source)
{
throw falco_exception("Rule \"" + *rule_name + "\" is not loaded");
throw falco_exception("Rule \"" + *rule + "\" is not loaded");
}
auto rule = m_rules.at(ri->name);
auto r = m_rules.at(ri->name);
nlohmann::json details;
get_json_details(details, *rule, *ri, plugins);
nlohmann::json rule;
get_json_details(rule, *r, *ri, plugins);
nlohmann::json rules_array = nlohmann::json::array();
rules_array.push_back(std::move(details));
rules_array.push_back(std::move(rule));
output["rules"] = std::move(rules_array);
}
@@ -706,13 +689,13 @@ void falco_engine::get_json_details(
void falco_engine::get_json_details(
nlohmann::json& out,
const falco_macro& macro,
const falco_macro& m,
const rule_loader::macro_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{
nlohmann::json macro_info;
macro_info["name"] = macro.name;
macro_info["name"] = m.name;
macro_info["condition"] = info.cond;
out["info"] = std::move(macro_info);
@@ -735,9 +718,9 @@ void falco_engine::get_json_details(
compiled_details.known_lists.insert(l.name);
}
filter_details_resolver().run(ast.get(), details);
filter_details_resolver().run(macro.condition.get(), compiled_details);
filter_details_resolver().run(m.condition.get(), compiled_details);
out["details"]["used"] = macro.used;
out["details"]["used"] = m.used;
out["details"]["macros"] = sequence_to_json_array(details.macros);
out["details"]["lists"] = sequence_to_json_array(details.lists);
out["details"]["condition_operators"] = sequence_to_json_array(compiled_details.operators);
@@ -745,11 +728,11 @@ void falco_engine::get_json_details(
// Store event types
nlohmann::json events;
get_json_evt_types(events, "", macro.condition.get());
get_json_evt_types(events, "", m.condition.get());
out["details"]["events"] = std::move(events);
// Store compiled condition
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(macro.condition.get());
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(m.condition.get());
// Compute the plugins that are actually used by this macro.
// Note: macros have no specific source, we need to set an empty list of used
@@ -907,11 +890,6 @@ void falco_engine::print_stats() const
fprintf(stdout, "%s", out.c_str());
}
const stats_manager& falco_engine::get_rule_stats_manager() const
{
return m_rule_stats_manager;
}
bool falco_engine::is_source_valid(const std::string &source) const
{
return m_sources.at(source) != nullptr;

View File

@@ -102,12 +102,6 @@ public:
// 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);
// 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);
//
// Enable/Disable any rules with any of the provided tags (set, exact matches only)
//
@@ -147,23 +141,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;
//
// Return const /ref to rules stored in the Falco engine.
//
inline const indexed_vector<falco_rule>& get_rules() const { return m_rules; }
nlohmann::json describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
//
// Print statistics on how many events matched each rule.
//
void print_stats() const;
//
// 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;
//
// Set the sampling ratio, which can affect which events are
// matched against the set of rules.

View File

@@ -20,7 +20,7 @@ limitations under the License.
// The version of this Falco engine
#define FALCO_ENGINE_VERSION_MAJOR 0
#define FALCO_ENGINE_VERSION_MINOR 40
#define FALCO_ENGINE_VERSION_MINOR 35
#define FALCO_ENGINE_VERSION_PATCH 0
#define FALCO_ENGINE_VERSION \
@@ -34,4 +34,4 @@ limitations under the License.
// 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.
#define FALCO_ENGINE_CHECKSUM "bc9d0d94ae70ef26b7cf814f62273a48b2bb4133dff0baff5f194f6f1711875a"
#define FALCO_ENGINE_CHECKSUM "8b7007b6fdef6abc6661ccfb4424052e7c4838d59f7be3ae31ab1e7b10223c93"

View File

@@ -23,8 +23,7 @@ static const std::string error_codes[] = {
"LOAD_ERR_YAML_VALIDATE",
"LOAD_ERR_COMPILE_CONDITION",
"LOAD_ERR_COMPILE_OUTPUT",
"LOAD_ERR_VALIDATE",
"LOAD_ERR_EXTENSION"
"LOAD_ERR_VALIDATE"
};
const std::string& falco::load_result::error_code_str(error_code ec)
@@ -38,8 +37,7 @@ static const std::string error_strings[] = {
"Error validating internal structure of YAML file",
"Error compiling condition",
"Error compiling output",
"Error validating rule/macro/list/exception objects",
"Error in extension item"
"Error validating rule/macro/list/exception objects"
};
const std::string& falco::load_result::error_str(error_code ec)
@@ -53,8 +51,7 @@ static const std::string error_descs[] = {
"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 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."
};
const std::string& falco::load_result::error_desc(error_code ec)
@@ -70,13 +67,7 @@ static const std::string warning_codes[] = {
"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"
"LOAD_DEPRECATED_ITEM"
};
const std::string& falco::load_result::warning_code_str(warning_code wc)
@@ -92,13 +83,7 @@ static const std::string warning_strings[] = {
"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"
"Used deprecated item"
};
const std::string& falco::load_result::warning_str(warning_code wc)
@@ -114,13 +99,7 @@ static const std::string warning_descs[] = {
"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 deprecated item is employed by lists, macros, or rules."
};
const std::string& falco::load_result::warning_desc(warning_code wc)

View File

@@ -57,12 +57,7 @@ public:
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
LOAD_WARNING_EXTENSION
};
virtual ~load_result() = default;

View File

@@ -56,30 +56,12 @@ 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_field_defined(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)
if (filter_factory->new_filtercheck(field.c_str()) != nullptr)
{
try
{
auto filter = field;
filter.append(" exists");
sinsp_filter_compiler(filter_factory, filter).compile();
return true;
}
catch (...)
{
return false;
}
return true;
}
// otherwise, simply attempt creating a filtercheck with the given
// field name and see if we succeed
return filter_factory->new_filtercheck(field.c_str()) != nullptr;
return false;
}
};

View File

@@ -17,18 +17,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <cstring>
#include <iomanip>
#include "falco_utils.h"
#include <libsinsp/utils.h>
#include <re2/re2.h>
#if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__)
#include <openssl/sha.h>
#endif
#include <cstring>
#include <fstream>
#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)?$"
@@ -119,50 +114,6 @@ uint64_t parse_prometheus_interval(std::string interval_str)
return interval;
}
#if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__)
std::string calculate_file_sha256sum(const std::string& filename)
{
std::ifstream file(filename, std::ios::binary);
if (!file.is_open())
{
return "";
}
SHA256_CTX sha256_context;
SHA256_Init(&sha256_context);
constexpr size_t buffer_size = 4096;
char buffer[buffer_size];
while (file.read(buffer, buffer_size))
{
SHA256_Update(&sha256_context, buffer, buffer_size);
}
SHA256_Update(&sha256_context, buffer, file.gcount());
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256_Final(digest, &sha256_context);
std::stringstream ss;
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_metric_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() == '_')
{
sanitized_name.pop_back();
}
return sanitized_name;
}
std::string wrap_text(const std::string& in, uint32_t indent, uint32_t line_len)
{
std::istringstream is(in);
@@ -194,7 +145,7 @@ uint32_t hardware_concurrency()
void readfile(const std::string& filename, std::string& data)
{
std::ifstream file(filename, std::ios::in);
std::ifstream file(filename.c_str(), std::ios::in);
if(file.is_open())
{
@@ -209,48 +160,6 @@ void readfile(const std::string& filename, std::string& data)
return;
}
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)
{
// regular match (no wildcards)
return pattern == s;
}
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)
{
// pattern was just a sequence of stars *, **, ***, ... . This always matches.
return true;
}
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)
{
return false;
}
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))
{
return false;
}
return matches_wildcard(pattern.substr(star_pos), s.substr(star_pos));
}
}
namespace network
{
bool is_unix_scheme(const std::string& url)

View File

@@ -20,18 +20,31 @@ limitations under the License.
#pragma once
#include <cstdint>
#include <sstream>
#include <fstream>
#include <iostream>
#include <string>
#include <thread>
#include <unordered_set>
#include <set>
#include <vector>
#include <string>
namespace falco::utils
{
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);
#ifdef __GNUC__
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
std::string sanitize_metric_name(const std::string& name);
namespace falco
{
namespace utils
{
uint64_t parse_prometheus_interval(std::string interval_str);
std::string wrap_text(const std::string& in, uint32_t indent, uint32_t linelen);
@@ -39,11 +52,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);
namespace network
{
static const std::string UNIX_SCHEME("unix://");
bool is_unix_scheme(const std::string& url);
} // namespace network
} // namespace falco::utils
} // namespace utils
} // namespace falco

View File

@@ -17,11 +17,9 @@ limitations under the License.
#include "filter_details_resolver.h"
#include <stdexcept>
using namespace libsinsp::filter;
static inline std::string get_field_name(const std::string& name, const std::string& arg)
std::string get_field_name(const std::string& name, const std::string& arg)
{
std::string fld = name;
if (!arg.empty())
@@ -38,28 +36,35 @@ void filter_details::reset()
operators.clear();
lists.clear();
evtnames.clear();
transformers.clear();
}
void filter_details_resolver::run(ast::expr* filter, filter_details& details)
{
visitor v(details);
// note: we may have ASTs composed on only one macro ref
v.m_expect_macro = true;
filter->accept(&v);
}
void filter_details_resolver::visitor::visit(ast::and_expr* e)
{
m_expect_macro = false;
for(size_t i = 0; i < e->children.size(); i++)
{
m_expect_macro = true;
e->children[i]->accept(this);
m_expect_macro = false;
}
}
void filter_details_resolver::visitor::visit(ast::or_expr* e)
{
m_expect_macro = false;
for(size_t i = 0; i < e->children.size(); i++)
{
m_expect_macro = true;
e->children[i]->accept(this);
m_expect_macro = false;
}
}
@@ -94,61 +99,36 @@ void filter_details_resolver::visitor::visit(ast::list_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())
{
throw std::runtime_error("can't find field info in binary check expression");
}
m_expect_macro = false;
m_details.fields.insert(get_field_name(e->field, e->arg));
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";
e->right->accept(this);
m_expect_evtname = e->field == "evt.type" || e->field == "evt.asynctype";
e->value->accept(this);
m_expect_evtname = false;
m_expect_list = false;
}
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())
{
throw std::runtime_error("can't find field info in unary check expression");
}
m_details.fields.insert(m_last_node_field_name);
m_expect_macro = false;
m_details.fields.insert(get_field_name(e->field, e->arg));
m_details.operators.insert(e->op);
}
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())
{
m_details.macros.insert(e->identifier);
}
}
void filter_details_resolver::visitor::visit(ast::value_expr* e)
{
if (m_expect_evtname)
if (m_expect_macro)
{
if(m_details.known_macros.find(e->value) != m_details.known_macros.end())
{
m_details.macros.insert(e->value);
}
// todo(jasondellaluce): should we throw an error if we
// encounter an unknown macro?
}
else if (m_expect_evtname)
{
m_details.evtnames.insert(e->value);
}
}
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)
{
m_details.transformers.insert(e->transformer);
e->value->accept(this);
}

View File

@@ -34,7 +34,6 @@ struct filter_details
std::unordered_set<std::string> operators;
std::unordered_set<std::string> lists;
std::unordered_set<std::string> evtnames;
std::unordered_set<std::string> transformers;
void reset();
};
@@ -61,25 +60,22 @@ private:
explicit visitor(filter_details& details) :
m_details(details),
m_expect_list(false),
m_expect_evtname(false),
m_last_node_field_name() {}
m_expect_macro(false),
m_expect_evtname(false) {}
visitor(visitor&&) = default;
visitor(const visitor&) = delete;
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;
filter_details& m_details;
bool m_expect_list;
bool m_expect_macro;
bool m_expect_evtname;
std::string m_last_node_field_name;
};
};

View File

@@ -101,6 +101,8 @@ void filter_macro_resolver::visitor::visit(ast::list_expr* e)
void filter_macro_resolver::visitor::visit(ast::binary_check_expr* e)
{
// avoid exploring checks, so that we can be sure that each
// value_expr* node visited is a macro identifier
m_node_substitute = nullptr;
}
@@ -111,22 +113,10 @@ void filter_macro_resolver::visitor::visit(ast::unary_check_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)
{
m_node_substitute = nullptr;
}
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)
{
const auto& macro = m_macros.find(e->identifier);
// we are supposed to get here only in case
// of identier-only children from either a 'not',
// an 'and' or an 'or'.
const auto& macro = m_macros.find(e->value);
if (macro != m_macros.end() && macro->second) // skip null-ptr macros
{
// note: checks for loop detection
@@ -136,7 +126,7 @@ void filter_macro_resolver::visitor::visit(ast::identifier_expr* e)
auto msg = "reference loop in macro '" + macro->first + "'";
m_errors.push_back({msg, e->get_pos()});
m_node_substitute = nullptr;
m_unknown_macros.push_back({e->identifier, e->get_pos()});
m_unknown_macros.push_back({e->value, e->get_pos()});
return;
}
@@ -150,12 +140,12 @@ void filter_macro_resolver::visitor::visit(ast::identifier_expr* e)
{
m_node_substitute = std::move(new_node);
}
m_resolved_macros.push_back({e->identifier, e->get_pos()});
m_resolved_macros.push_back({e->value, e->get_pos()});
m_macros_path.pop_back();
}
else
{
m_node_substitute = nullptr;
m_unknown_macros.push_back({e->identifier, e->get_pos()});
m_unknown_macros.push_back({e->value, e->get_pos()});
}
}

View File

@@ -35,7 +35,7 @@ class filter_macro_resolver
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
is passed by reference and be modified 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
@@ -121,13 +121,10 @@ class filter_macro_resolver
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;

View File

@@ -41,10 +41,6 @@ public:
ruleset_retriever_func_t get_ruleset;
};
enum class match_type {
exact, substring, wildcard
};
virtual ~filter_ruleset() = default;
void set_engine_state(const engine_state_funcs &engine_state);
@@ -171,37 +167,31 @@ public:
/*!
\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 substring Substring used to match rule names.
If empty, all rules are matched.
\param match_exact If true, substring must be an exact match for a
given rule name. Otherwise, any rules having substring as a substring
in the rule name are enabled/disabled.
\param ruleset_id The id of the ruleset to be used
*/
virtual void enable(
const std::string &pattern,
match_type match,
const std::string &substring,
bool match_exact,
uint16_t ruleset_id) = 0;
/*!
\brief Find those rules matching the provided substring and disable
them in the provided ruleset.
\param pattern Pattern used to match rule names.
\param match How to match the pattern against rules:
- exact: rules that has the same exact name as the pattern are matched
- substring: rules having the pattern as a substring in the rule are matched.
An empty pattern matches all rules.
- wildcard: rules with names that satisfies a wildcard (*) pattern are matched.
A "*" pattern matches all rules.
Wildcards can appear anywhere in the pattern (e.g. "*hello*world*")
\param substring Substring used to match rule names.
If empty, all rules are matched.
\param match_exact If true, substring must be an exact match for a
given rule name. Otherwise, any rules having substring as a substring
in the rule name are enabled/disabled.
\param ruleset_id The id of the ruleset to be used
*/
virtual void disable(
const std::string &pattern,
match_type match,
const std::string &substring,
bool match_exact,
uint16_t ruleset_id) = 0;
/*!

View File

@@ -49,22 +49,14 @@ bool filter_warning_resolver::run(
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 (is_unsafe_field(e->field) && is_equality_operator(e->op))
{
m_is_equality_check = true;
e->right->accept(this);
e->value->accept(this);
m_is_equality_check = false;
}
}
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)
{

View File

@@ -49,22 +49,17 @@ public:
private:
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) {}
visitor(): m_is_equality_check(false), m_warnings(nullptr) {}
visitor(visitor&&) = default;
visitor& operator = (visitor&&) = default;
visitor(const visitor&) = delete;
visitor& operator = (const visitor&) = delete;
bool m_is_equality_check;
bool m_last_node_is_unsafe_field;
std::set<falco::load_result::warning_code>* m_warnings;
void visit(libsinsp::filter::ast::value_expr* e) override;
void visit(libsinsp::filter::ast::list_expr* e) override;
void visit(libsinsp::filter::ast::binary_check_expr* e) override;
void visit(libsinsp::filter::ast::field_expr* e) override;
};
};

View File

@@ -81,12 +81,12 @@ rule_loader::context::context(const libsinsp::filter::ast::pos_info& pos,
// 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 = "\"" + (
std::string 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', ' ');
std::replace(name.begin(), name.end(), '\n', ' ');
std::replace(name.begin(), name.end(), '\r', ' ');
std::string item_name = "";
@@ -100,7 +100,7 @@ rule_loader::context::context(const libsinsp::filter::ast::pos_info& pos,
condpos.line = pos.line + lastpos.pos.line;
condpos.column = pos.col + lastpos.pos.column;
init(condition_name, condpos, rule_loader::context::CONDITION_EXPRESSION, item_name, parent);
init(name, condpos, rule_loader::context::CONDITION_EXPRESSION, item_name, parent);
}
const std::string& rule_loader::context::name() const

View File

@@ -270,8 +270,10 @@ namespace rule_loader
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))
: content(cont), sources(srcs), name(name),
output_extra(), replace_output_container_info(false)
{
res.reset(new result(name));
}
// inputs
@@ -279,7 +281,7 @@ namespace rule_loader
const indexed_vector<falco_source>& sources;
std::string name;
std::string output_extra;
bool replace_output_container_info = false;
bool replace_output_container_info;
// outputs
std::unique_ptr<result> res;

View File

@@ -88,7 +88,7 @@ static void validate_exception_info(
{
for (const auto &v : ex.fields.items)
{
THROW(!source->is_valid_lhs_field(v.item),
THROW(!source->is_field_defined(v.item),
std::string("'") + v.item + "' is not a supported filter field",
ex.ctx);
}
@@ -109,7 +109,7 @@ static void validate_exception_info(
ex.ctx);
if (source)
{
THROW(!source->is_valid_lhs_field(ex.fields.item),
THROW(!source->is_field_defined(ex.fields.item),
std::string("'") + ex.fields.item + "' is not a supported filter field",
ex.ctx);
}

View File

@@ -76,7 +76,6 @@ static void build_rule_exception_infos(
std::string& condition)
{
std::string tmp;
condition = "(" + condition + ")";
for (const auto &ex : exceptions)
{
std::string icond;
@@ -343,35 +342,35 @@ void rule_loader::compiler::compile_list_infos(
const collector& col,
indexed_vector<falco_list>& out) const
{
std::list<std::string> used_names;
falco_list infos;
std::list<std::string> used;
falco_list v;
for (const auto &list : col.lists())
{
infos.name = list.name;
infos.items.clear();
v.name = list.name;
v.items.clear();
for (const auto &item : list.items)
{
const auto ref = col.lists().at(item);
if (ref && ref->index < list.visibility)
{
used_names.push_back(ref->name);
used.push_back(ref->name);
for (const auto &val : ref->items)
{
infos.items.push_back(val);
v.items.push_back(val);
}
}
else
{
infos.items.push_back(item);
v.items.push_back(item);
}
}
infos.used = false;
auto list_id = out.insert(infos, infos.name);
v.used = false;
auto list_id = out.insert(v, v.name);
out.at(list_id)->id = list_id;
}
for (const auto &name : used_names)
for (const auto &v : used)
{
out.at(name)->used = true;
out.at(v)->used = true;
}
}
@@ -440,35 +439,27 @@ bool rule_loader::compiler::compile_condition(
sinsp_filter_compiler compiler(filter_factory, ast_out.get());
try
{
filter_out = compiler.compile();
filter_out = std::move(compiler.compile());
}
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);
cond_ctx);
return false;
}
rule_loader::context ctx(compiler.get_pos(), condition, cond_ctx);
throw rule_loader::rule_load_exception(
falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION,
err,
ctx);
}
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);
}
return true;
}
@@ -509,12 +500,7 @@ void rule_loader::compiler::compile_rule_infos(
// build rule output message
rule.output = r.output;
// plugins sources do not have any container info and so we won't apply -pk, -pc, etc.
// on the other hand, when using plugins you might want to append custom output based on the plugin
// TODO: this is not flexible enough (esp. if you mix plugin with syscalls),
// it would be better to add configuration options to control the output.
if (!cfg.replace_output_container_info || r.source == falco_common::syscall_source)
if (r.source == falco_common::syscall_source)
{
apply_output_substitutions(cfg, rule.output);
}

View File

@@ -25,20 +25,8 @@ limitations under the License.
#include "rule_loading_messages.h"
#include <libsinsp/logger.h>
#include <re2/re2.h>
#define THROW(cond, err, ctx) { if ((cond)) { throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_YAML_VALIDATE, (err), (ctx)); } }
// Sinsp Filter grammar tokens taken from "libsinsp/filter/parser.h"
// These regular expressions are used here to check for invalid macro/list names
// todo(mrgian): to avoid code duplication we can move regex definitions in libsinsp/filter/parser.h
// and include it here instead of redefining them.
#define RGX_IDENTIFIER "([a-zA-Z]+[a-zA-Z0-9_]*)"
#define RGX_BARESTR "([^()\"'[:space:]=,]+)"
static re2::RE2 s_rgx_identifier(RGX_IDENTIFIER, re2::RE2::POSIX);
static re2::RE2 s_rgx_barestr(RGX_BARESTR, re2::RE2::POSIX);
// Don't call this directly, call decode_val/decode_optional_val instead.
template <typename T>
static void decode_val_generic(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx, bool optional)
@@ -282,7 +270,6 @@ static void decode_exception_values(
}
static void read_rule_exceptions(
rule_loader::configuration& cfg,
const YAML::Node& item,
std::vector<rule_loader::rule_exception_info>& exceptions,
const rule_loader::context& parent,
@@ -316,15 +303,6 @@ static void read_rule_exceptions(
rule_loader::rule_exception_info v_ex(ex_ctx);
v_ex.name = name;
// Check if an exception with the same name has already been defined
for (auto &exception : exceptions)
{
if(v_ex.name == exception.name)
{
cfg.res->add_warning(falco::load_result::LOAD_EXCEPTION_NAME_NOT_UNIQUE, "Multiple definitions of exception '" + v_ex.name + "' in the same rule", ex_ctx);
}
}
// note: the legacy lua loader used to throw a "xxx must strings" error
// fields are optional when append is true
@@ -344,24 +322,19 @@ static void read_rule_exceptions(
decode_exception_values(val, v_ex_val, vctx);
v_ex.values.push_back(v_ex_val);
}
}
else if (append)
{
cfg.res->add_warning(falco::load_result::LOAD_APPEND_NO_VALUES, "Overriding/appending exception with no values", ex_ctx);
}
exceptions.push_back(v_ex);
}
}
static void read_rule_exceptions(
rule_loader::configuration& cfg,
const YAML::Node& item,
std::optional<std::vector<rule_loader::rule_exception_info>>& exceptions,
const rule_loader::context& parent,
bool append)
{
std::vector<rule_loader::rule_exception_info> decoded;
read_rule_exceptions(cfg, item, decoded, parent, append);
read_rule_exceptions(item, decoded, parent, append);
exceptions = decoded;
}
@@ -386,11 +359,9 @@ void rule_loader::reader::read_item(
const YAML::Node& item,
const rule_loader::context& parent)
{
{
rule_loader::context tmp(item, rule_loader::context::RULES_CONTENT_ITEM, "", parent);
THROW(!item.IsMap(), "Unexpected element type. "
"Each element should be a yaml associative array.", tmp);
}
rule_loader::context tmp(item, rule_loader::context::RULES_CONTENT_ITEM, "", parent);
THROW(!item.IsMap(), "Unexpected element type. "
"Each element should be a yaml associative array.", tmp);
if (item["required_engine_version"].IsDefined())
{
@@ -469,13 +440,6 @@ void rule_loader::reader::read_item(
decode_val(item, "list", name, tmp);
rule_loader::context ctx(item, rule_loader::context::LIST, name, parent);
bool invalid_name = !re2::RE2::FullMatch(name, s_rgx_barestr);
if(invalid_name)
{
cfg.res->add_warning(falco::load_result::LOAD_INVALID_LIST_NAME, "List has an invalid name. List names should match a regular expression: " RGX_BARESTR, ctx);
}
rule_loader::list_info v(ctx);
bool append = false;
@@ -516,13 +480,6 @@ void rule_loader::reader::read_item(
decode_val(item, "macro", name, tmp);
rule_loader::context ctx(item, rule_loader::context::MACRO, name, parent);
bool invalid_name = !re2::RE2::FullMatch(name, s_rgx_identifier);
if(invalid_name)
{
cfg.res->add_warning(falco::load_result::LOAD_INVALID_MACRO_NAME, "Macro has an invalid name. Macro names should match a regular expression: " RGX_IDENTIFIER, ctx);
}
rule_loader::macro_info v(ctx);
v.name = name;
@@ -618,7 +575,7 @@ void rule_loader::reader::read_item(
if (check_update_expected(expected_keys, override_append, "append", "exceptions", ctx))
{
read_rule_exceptions(cfg, item, v.exceptions, ctx, true);
read_rule_exceptions(item, v.exceptions, ctx, true);
}
if (check_update_expected(expected_keys, override_append, "append", "output", ctx))
@@ -650,7 +607,7 @@ void rule_loader::reader::read_item(
if (check_update_expected(expected_keys, override_replace, "replace", "exceptions", ctx))
{
read_rule_exceptions(cfg, item, v.exceptions, ctx, false);
read_rule_exceptions(item, v.exceptions, ctx, true);
}
if (check_update_expected(expected_keys, override_replace, "replace", "output", ctx))
@@ -715,7 +672,7 @@ void rule_loader::reader::read_item(
if(item["exceptions"].IsDefined())
{
read_rule_exceptions(cfg, item, v.exceptions, ctx, true);
read_rule_exceptions(item, v.exceptions, ctx, true);
}
// TODO restore this error and update testing
@@ -771,7 +728,7 @@ void rule_loader::reader::read_item(
decode_optional_val(item, "warn_evttypes", v.warn_evttypes, ctx);
decode_optional_val(item, "skip-if-unknown-filter", v.skip_if_unknown_filter, ctx);
decode_tags(item, v.tags, ctx);
read_rule_exceptions(cfg, item, v.exceptions, ctx, false);
read_rule_exceptions(item, v.exceptions, ctx, has_append_flag);
collector.define(cfg, v);
}
}

View File

@@ -44,7 +44,7 @@ void stats_manager::format(
out += "Rule counts by severity:\n";
for (size_t i = 0; i < m_by_priority.size(); i++)
{
auto val = m_by_priority[i]->load();
auto val = m_by_priority[i].get()->load();
if (val > 0)
{
falco_common::format_priority(
@@ -56,7 +56,7 @@ void stats_manager::format(
out += "Triggered rules by rule name:\n";
for (size_t i = 0; i < m_by_rule_id.size(); i++)
{
auto val = m_by_rule_id[i]->load();
auto val = m_by_rule_id[i].get()->load();
if (val > 0)
{
out += " " + rules.at(i)->name + ": " + std::to_string(val) + "\n";
@@ -68,11 +68,13 @@ 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));
m_by_rule_id.emplace_back();
m_by_rule_id[m_by_rule_id.size() - 1].reset(new std::atomic<uint64_t>(0));
}
while (m_by_priority.size() <= (size_t) rule.priority)
{
m_by_priority.emplace_back(std::make_unique<std::atomic<uint64_t>>(0));
m_by_priority.emplace_back();
m_by_priority[m_by_priority.size() - 1].reset(new std::atomic<uint64_t>(0));
}
}

View File

@@ -63,23 +63,6 @@ public:
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::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
{
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

@@ -14,7 +14,8 @@
configure_file(config_falco.h.in config_falco.h)
add_library(falco_application STATIC
set(
FALCO_SOURCES
app/app.cpp
app/options.cpp
app/restart_handler.cpp
@@ -48,8 +49,8 @@ add_library(falco_application STATIC
app/actions/start_webserver.cpp
app/actions/validate_rules_files.cpp
app/actions/create_requested_paths.cpp
app/actions/close_inspectors.cpp
configuration.cpp
logger.cpp
falco_outputs.cpp
outputs_file.cpp
outputs_stdout.cpp
@@ -61,12 +62,16 @@ add_library(falco_application STATIC
set(
FALCO_INCLUDE_DIRECTORIES
"${PROJECT_SOURCE_DIR}/userspace/engine"
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}"
"${PROJECT_BINARY_DIR}/userspace/falco"
"${PROJECT_BINARY_DIR}/driver/src"
"${CXXOPTS_INCLUDE_DIR}"
"${YAMLCPP_INCLUDE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}"
)
list(APPEND FALCO_INCLUDE_DIRECTORIES "${FALCO_EXTRA_INCLUDE_DIRS}")
set(
FALCO_DEPENDENCIES
cxxopts
@@ -76,28 +81,31 @@ set(
FALCO_LIBRARIES
falco_engine
sinsp
yaml-cpp
"${YAMLCPP_LIB}"
)
list(APPEND FALCO_DEPENDENCIES yamlcpp)
if(NOT WIN32)
target_sources(falco_application
PRIVATE
outputs_program.cpp
outputs_syslog.cpp
)
list(
APPEND FALCO_SOURCES
outputs_program.cpp
outputs_syslog.cpp
)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
target_sources(falco_application
PRIVATE
list(
APPEND FALCO_SOURCES
outputs_grpc.cpp
outputs_http.cpp
falco_metrics.cpp
webserver.cpp
grpc_context.cpp
grpc_server_impl.cpp
grpc_request_context.cpp
grpc_server.cpp
grpc_context.cpp
grpc_server_impl.cpp
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
@@ -107,6 +115,7 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
list(
APPEND FALCO_INCLUDE_DIRECTORIES
"${CPPHTTPLIB_INCLUDE}"
"${OPENSSL_INCLUDE_DIR}"
"${GRPC_INCLUDE}"
"${GRPCPP_INCLUDE}"
@@ -119,24 +128,29 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
list(APPEND FALCO_LIBRARIES "${GRPC_LIBRARIES}")
endif()
list(APPEND FALCO_DEPENDENCIES cpp-httplib)
list(
APPEND FALCO_LIBRARIES
httplib::httplib
"${GRPCPP_LIB}"
"${GRPC_LIB}"
"${GPR_LIB}"
"${PROTOBUF_LIB}"
"${CARES_LIB}"
"${OPENSSL_LIBRARIES}"
"${YAMLCPP_LIB}"
)
endif()
add_library(
falco_application STATIC
${FALCO_SOURCES}
)
if (EMSCRIPTEN)
target_compile_options(falco_application PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
endif()
target_compile_definitions(falco_application PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)
add_dependencies(falco_application ${FALCO_DEPENDENCIES})
target_link_libraries(

View File

@@ -56,7 +56,6 @@ falco::app::run_result stop_grpc_server(falco::app::state& s);
falco::app::run_result stop_webserver(falco::app::state& s);
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

View File

@@ -1,44 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "actions.h"
#include "helpers.h"
using namespace falco::app;
using namespace falco::app::actions;
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)
{
s.offline_inspector->close();
}
for (const auto &src : s.loaded_sources)
{
auto src_info = s.source_infos.at(src);
if (src_info->inspector != nullptr)
{
src_info->inspector->close();
}
}
return run_result::ok();
}

View File

@@ -103,14 +103,7 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s
falco::app::restart_handler::watch_list_t dirs_to_watch;
if (s.config->m_watch_config_files)
{
files_to_watch.insert(
files_to_watch.end(),
s.config->m_loaded_configs_filenames.begin(),
s.config->m_loaded_configs_filenames.end());
dirs_to_watch.insert(
dirs_to_watch.end(),
s.config->m_loaded_configs_folders.begin(),
s.config->m_loaded_configs_folders.end());
files_to_watch.push_back(s.options.conf_filename);
files_to_watch.insert(
files_to_watch.end(),
s.config->m_loaded_rules_filenames.begin(),

View File

@@ -48,17 +48,11 @@ falco::app::run_result falco::app::actions::open_live_inspector(
{
try
{
if((s.config->m_metrics_flags & METRICS_V2_STATE_COUNTERS))
if((s.config->m_metrics_flags & PPM_SCAP_STATS_STATE_COUNTERS))
{
inspector->set_sinsp_stats_v2_enabled();
}
if(s.config->m_falco_libs_thread_table_size > 0)
{
// Default value is set in libs as part of the sinsp_thread_manager setup
inspector->m_thread_manager->set_max_thread_table_size(s.config->m_falco_libs_thread_table_size);
}
if (source != falco_common::syscall_source) /* Plugin engine */
{
for (const auto& p: inspector->get_plugin_manager()->plugins())

View File

@@ -66,11 +66,13 @@ void configure_output_format(falco::app::state& s)
void add_source_to_engine(falco::app::state& s, const std::string& src)
{
auto src_info = s.source_infos.at(src);
auto& filterchecks = *src_info->filterchecks;
auto& filterchecks = *src_info->filterchecks.get();
auto* inspector = src_info->inspector.get();
auto filter_factory = std::make_shared<sinsp_filter_factory>(inspector, filterchecks);
auto formatter_factory = std::make_shared<sinsp_evt_formatter_factory>(inspector, filterchecks);
auto filter_factory = std::shared_ptr<sinsp_filter_factory>(
new sinsp_filter_factory(inspector, filterchecks));
auto formatter_factory = std::shared_ptr<sinsp_evt_formatter_factory>(
new sinsp_evt_formatter_factory(inspector, filterchecks));
if(s.config->m_json_output)
{

View File

@@ -65,29 +65,29 @@ static bool populate_filterchecks(
std::unordered_set<std::string>& used_plugins,
std::string& err)
{
std::vector<const filter_check_info*> infos;
for(const auto& plugin : inspector->get_plugin_manager()->plugins())
std::vector<const filter_check_info*> info;
for(const auto& p : inspector->get_plugin_manager()->plugins())
{
if (!(plugin->caps() & CAP_EXTRACTION))
if (!(p->caps() & CAP_EXTRACTION))
{
continue;
}
// check if some fields are overlapping on this event sources
infos.clear();
filterchecks.get_all_fields(infos);
for (const auto &info : infos)
info.clear();
filterchecks.get_all_fields(info);
for (auto &info : info)
{
for (int32_t i = 0; i < info->m_nfields; i++)
{
// check if one of the fields extractable by the plugin
// is already provided by another filtercheck for this source
std::string fname = info->m_fields[i].m_name;
for (const auto &field : plugin->fields())
for (auto &f : p->fields())
{
if (field.m_name == fname)
if (std::string(f.m_name) == fname)
{
err = "Plugin '" + plugin->name()
err = "Plugin '" + p->name()
+ "' supports extraction of field '" + fname
+ "' that is overlapping for source '" + source + "'";
return false;
@@ -97,8 +97,8 @@ static bool populate_filterchecks(
}
// add plugin filterchecks to the event source
filterchecks.add_filter_check(sinsp_plugin::new_filtercheck(plugin));
used_plugins.insert(plugin->name());
filterchecks.add_filter_check(sinsp_plugin::new_filtercheck(p));
used_plugins.insert(p->name());
}
return true;
}
@@ -108,7 +108,7 @@ falco::app::run_result falco::app::actions::init_inspectors(falco::app::state& s
std::string err;
std::unordered_set<std::string> used_plugins;
const auto& all_plugins = s.offline_inspector->get_plugin_manager()->plugins();
for (const auto &src : s.loaded_sources)
{
auto src_info = s.source_infos.at(src);
@@ -182,7 +182,7 @@ falco::app::run_result falco::app::actions::init_inspectors(falco::app::state& s
if (!populate_filterchecks(
src_info->inspector,
src,
*src_info->filterchecks,
*src_info->filterchecks.get(),
used_plugins,
err))
{
@@ -197,10 +197,10 @@ falco::app::run_result falco::app::actions::init_inspectors(falco::app::state& s
const auto& sources = src_info->inspector->event_sources();
if (sources.size() == 0 || sources.size() > 2 || sources[0] != falco_common::syscall_source)
{
err.clear();
for (const auto &source : sources)
std::string err;
for (const auto &s : sources)
{
err += (err.empty() ? "" : ", ") + source;
err += (err.empty() ? "" : ", ") + s;
}
return run_result::fatal("Illegal sources setup in live inspector for source '" + src + "': " + err);
}

View File

@@ -60,7 +60,7 @@ falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s)
return run_result::ok();
}
s.outputs = std::make_shared<falco_outputs>(
s.outputs.reset(new falco_outputs(
s.engine,
s.config->m_outputs,
s.config->m_json_output,
@@ -70,7 +70,7 @@ falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s)
s.config->m_buffered_outputs,
s.config->m_outputs_queue_capacity,
s.config->m_time_format_iso_8601,
hostname);
hostname));
return run_result::ok();
}

View File

@@ -28,12 +28,12 @@ falco::app::run_result falco::app::actions::list_plugins(const falco::app::state
if(s.options.list_plugins)
{
std::ostringstream os;
sinsp inspector;
std::unique_ptr<sinsp> inspector(new sinsp());
const auto& configs = s.config->m_plugins;
for (auto &c : configs)
{
// load the plugin (no need to initialize it)
auto plugin = inspector.register_plugin(c.m_library_path);
auto plugin = inspector->register_plugin(c.m_library_path);
format_plugin_info(plugin, os);
os << std::endl;
}

View File

@@ -29,21 +29,18 @@ static falco::app::run_result apply_deprecated_options(const falco::app::state&
falco::app::run_result falco::app::actions::load_config(const falco::app::state& s)
{
// List of loaded conf files, ie: s.options.conf_filename
// plus all the `config_files` expanded list of configs.
std::vector<std::string> loaded_conf_files;
try
{
if (!s.options.conf_filename.empty())
{
s.config->init_from_file(s.options.conf_filename, loaded_conf_files, s.options.cmdline_config_options);
s.config->init(s.options.conf_filename, s.options.cmdline_config_options);
}
else
{
// Is possible to have an empty config file when we want to use some command line
// options like `--help`, `--version`, ...
// The configs used in `load_yaml` will be initialized to the default values.
s.config->init_from_content("", s.options.cmdline_config_options);
s.config->init(s.options.cmdline_config_options);
}
}
catch (std::exception& e)
@@ -60,11 +57,7 @@ falco::app::run_result falco::app::actions::load_config(const falco::app::state&
}
if (!s.options.conf_filename.empty())
{
falco_logger::log(falco_logger::level::INFO, "Falco initialized with configuration files:\n");
for (const auto& path : loaded_conf_files)
{
falco_logger::log(falco_logger::level::INFO, std::string(" ") + path + "\n");
}
falco_logger::log(falco_logger::level::INFO, "Falco initialized with configuration file: " + s.options.conf_filename + "\n");
}
s.config->m_buffered_outputs = !s.options.unbuffered_outputs;

View File

@@ -29,10 +29,10 @@ falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s)
return run_result::fatal("Loading plugins dynamic libraries is not supported by this Falco build");
}
#endif
// Initialize the set of loaded event sources.
// Initialize the set of loaded event sources.
// By default, the set includes the 'syscall' event source
state::source_info syscall_src_info;
syscall_src_info.filterchecks = std::make_shared<sinsp_filter_check_list>();
syscall_src_info.filterchecks.reset(new sinsp_filter_check_list());
s.source_infos.clear();
s.source_infos.insert(syscall_src_info, falco_common::syscall_source);
s.loaded_sources = { falco_common::syscall_source };
@@ -44,7 +44,7 @@ falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s)
// plugins in order to have them available every time we need to access
// their static info. If Falco is in capture mode, this inspector is also
// used to open and read the trace file
s.offline_inspector = std::make_shared<sinsp>();
s.offline_inspector.reset(new sinsp());
// Load all the configured plugins
for(auto &p : s.config->m_plugins)
@@ -55,7 +55,7 @@ falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s)
if(plugin->caps() & CAP_SOURCING && plugin->id() != 0)
{
state::source_info src_info;
src_info.filterchecks = std::make_shared<filter_check_list>();
src_info.filterchecks.reset(new filter_check_list());
auto sname = plugin->event_source();
s.source_infos.insert(src_info, sname);
// note: this avoids duplicate values

View File

@@ -17,7 +17,6 @@ limitations under the License.
#include "actions.h"
#include "helpers.h"
#include "falco_utils.h"
#include <libsinsp/plugin_manager.h>
@@ -84,9 +83,6 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
{
falco_logger::log(falco_logger::level::WARNING,res->as_string(true, rc) + "\n");
}
#if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__)
s.config->m_loaded_rules_filenames_sha256sum.insert({filename, falco::utils::calculate_file_sha256sum(filename)});
#endif
}
// note: we have an egg-and-chicken problem here. We would like to check
@@ -131,12 +127,6 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
return run_result::fatal(err);
}
if((!s.options.disabled_rule_substrings.empty() || !s.options.disabled_rule_tags.empty() || !s.options.enabled_rule_tags.empty()) &&
!s.config->m_rules_selection.empty())
{
return run_result::fatal("Specifying -D, -t, -T command line options together with \"rules:\" configuration or -o \"rules...\" is not supported.");
}
for (const auto& substring : s.options.disabled_rule_substrings)
{
falco_logger::log(falco_logger::level::INFO, "Disabling rules matching substring: " + substring + "\n");
@@ -164,27 +154,6 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
s.engine->enable_rule_by_tag(s.options.enabled_rule_tags, true);
}
for(const auto& sel : s.config->m_rules_selection)
{
bool enable = sel.m_op == falco_configuration::rule_selection_operation::enable;
if(sel.m_rule != "")
{
falco_logger::log(falco_logger::level::INFO,
(enable ? "Enabling" : "Disabling") + std::string(" rules with name: ") + sel.m_rule + "\n");
s.engine->enable_rule_wildcard(sel.m_rule, enable);
}
if(sel.m_tag != "")
{
falco_logger::log(falco_logger::level::INFO,
(enable ? "Enabling" : "Disabling") + std::string(" rules with tag: ") + sel.m_tag + "\n");
s.engine->enable_rule_by_tag(std::set<std::string>{sel.m_tag}, enable); // TODO wildcard support
}
}
// printout of `-L` option
if (s.options.describe_all_rules || !s.options.describe_rule.empty())
{

View File

@@ -24,28 +24,28 @@ limitations under the License.
using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::pidfile(const falco::app::state& state)
falco::app::run_result falco::app::actions::pidfile(const falco::app::state& s)
{
if (state.options.dry_run)
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping pidfile creation in dry-run\n");
return run_result::ok();
}
if (!state.options.pidfilename.empty())
if (!s.options.pidfilename.empty())
{
int64_t self_pid = getpid();
std::ofstream stream;
stream.open(state.options.pidfilename);
std::ofstream pidfile;
pidfile.open(s.options.pidfilename);
if (!stream.good())
if (!pidfile.good())
{
falco_logger::log(falco_logger::level::ERR, "Could not write pid to pidfile " + state.options.pidfilename + ". Exiting.\n");
falco_logger::log(falco_logger::level::ERR, "Could not write pid to pidfile : " + s.options.pidfilename + ". Exiting.\n");
exit(-1);
}
stream << self_pid;
stream.close();
pidfile << self_pid;
pidfile.close();
}

View File

@@ -25,8 +25,8 @@ falco::app::run_result falco::app::actions::print_generated_gvisor_config(falco:
{
if(!s.options.gvisor_generate_config_with_socket.empty())
{
sinsp i;
std::string gvisor_config = i.generate_gvisor_config(s.options.gvisor_generate_config_with_socket);
std::unique_ptr<sinsp> i(new sinsp());
std::string gvisor_config = i->generate_gvisor_config(s.options.gvisor_generate_config_with_socket);
printf("%s\n", gvisor_config.c_str());
return run_result::exit();
}

View File

@@ -27,14 +27,14 @@ falco::app::run_result falco::app::actions::print_plugin_info(const falco::app::
{
if(!s.options.print_plugin_info.empty())
{
sinsp inspector;
std::unique_ptr<sinsp> inspector(new sinsp());
for(auto &pc : s.config->m_plugins)
{
if (pc.m_name == s.options.print_plugin_info
|| pc.m_library_path == s.options.print_plugin_info)
{
// load the plugin
auto p = inspector.register_plugin(pc.m_library_path);
auto p = inspector->register_plugin(pc.m_library_path);
// print plugin descriptive info
std::ostringstream os;
@@ -61,7 +61,7 @@ falco::app::run_result falco::app::actions::print_plugin_info(const falco::app::
os << schema << std::endl;
os << std::endl;
printf("%s", os.str().c_str());
// init the plugin
std::string err;
if (!p->init(pc.m_init_config, err))

View File

@@ -108,7 +108,7 @@ falco::app::run_result falco::app::actions::print_support(falco::app::state& s)
support["version"] = infos.falco_version;
support["engine_info"] = infos.as_json();
support["cmdline"] = s.cmdline;
support["config"] = s.config->dump();
support["config"] = read_file(s.options.conf_filename);
support["rules_files"] = nlohmann::json::array();
for(const auto& filename : s.config->m_loaded_rules_filenames)
{

View File

@@ -199,7 +199,7 @@ static falco::app::run_result do_inspect(
}
else if(rc == SCAP_TIMEOUT)
{
if(ev == nullptr) [[unlikely]]
if(unlikely(ev == nullptr))
{
timeouts_since_last_success_or_msg++;
if(timeouts_since_last_success_or_msg > s.config->m_syscall_evt_timeout_max_consecutives
@@ -310,7 +310,7 @@ static falco::app::run_result do_inspect(
auto res = s.engine->process_event(source_engine_idx, ev, s.config->m_rule_matching);
if(res != nullptr)
{
for(auto& rule_res : *res)
for(auto& rule_res : *res.get())
{
s.outputs->handle_event(rule_res.evt, rule_res.rule, rule_res.source, rule_res.priority_num, rule_res.format, rule_res.tags);
}
@@ -413,9 +413,9 @@ static falco::app::run_result init_stats_writer(
return falco::app::run_result::fatal("Metrics interval was passed as numeric value without Prometheus time unit. Please specify a time unit");
}
if (config->m_metrics_enabled && !(sw->has_output() || config->m_webserver_config.m_prometheus_metrics_enabled))
if (config->m_metrics_enabled && !sw->has_output())
{
return falco::app::run_result::fatal("Metrics are enabled with no output configured. Please enable at least one output channel ('metrics.output_rule', 'metrics.output_file' or 'webserver.prometheus_metrics_enabled')");
return falco::app::run_result::fatal("Metrics are enabled with no output configured. Please enable at least one output channel");
}
falco_logger::log(falco_logger::level::INFO, "Setting metrics interval to " + config->m_metrics_interval_str + ", equivalent to " + std::to_string(config->m_metrics_interval) + " (ms)\n");
@@ -436,7 +436,7 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
s.engine->complete_rule_loading();
// Initialize stats writer
auto statsw = std::make_shared<stats_writer>(s.outputs, s.config, s.engine);
auto statsw = std::make_shared<stats_writer>(s.outputs, s.config);
auto res = init_stats_writer(statsw, s.config, s.options.dry_run);
if (s.options.dry_run)
@@ -488,9 +488,10 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
ctxs.reserve(s.enabled_sources.size());
for (const auto& source : s.enabled_sources)
{
auto& ctx = ctxs.emplace_back();
ctxs.emplace_back();
auto& ctx = ctxs[ctxs.size() - 1];
ctx.source = source;
ctx.sync = std::make_unique<source_sync_context>(termination_sem);
ctx.sync.reset(new source_sync_context(termination_sem));
auto src_info = s.source_infos.at(source);
try
@@ -516,9 +517,9 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
{
auto res_ptr = &ctx.res;
auto sync_ptr = ctx.sync.get();
ctx.thread = std::make_unique<std::thread>([&s, src_info, &statsw, source, sync_ptr, res_ptr]() {
ctx.thread.reset(new std::thread([&s, src_info, &statsw, source, sync_ptr, res_ptr](){
process_inspector_events(s, src_info->inspector, statsw, source, sync_ptr, res_ptr);
});
}));
}
}
catch (std::exception &e)
@@ -535,9 +536,9 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
// wait for event processing to terminate for all sources
// if a thread terminates with an error, we trigger the app termination
// to force all other event streams to terminate too.
// We accumulate the errors in a single run_result.
size_t stopped_count = 0;
while (stopped_count < ctxs.size())
// We accomulate the errors in a single run_result.
size_t closed_count = 0;
while (closed_count < ctxs.size())
{
if (!res.success && !termination_forced)
{
@@ -572,12 +573,12 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
ctx.thread->join();
}
falco_logger::log(falco_logger::level::DEBUG, "Stopping capture for event source '" + ctx.source + "'\n");
s.source_infos.at(ctx.source)->inspector->stop_capture();
falco_logger::log(falco_logger::level::DEBUG, "Closing event source '" + ctx.source + "'\n");
s.source_infos.at(ctx.source)->inspector->close();
res = run_result::merge(res, ctx.res);
ctx.sync->join();
stopped_count++;
closed_count++;
}
}
}

View File

@@ -24,48 +24,53 @@ limitations under the License.
using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::start_webserver(falco::app::state& state)
falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s)
{
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(!state.is_capture_mode() && state.config->m_webserver_enabled)
if(!s.is_capture_mode() && s.config->m_webserver_enabled)
{
if (state.options.dry_run)
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping starting webserver in dry-run\n");
return run_result::ok();
}
falco_configuration::webserver_config webserver_config = state.config->m_webserver_config;
std::string ssl_option = (webserver_config.m_ssl_enabled ? " (SSL)" : "");
std::string ssl_option = (s.config->m_webserver_ssl_enabled ? " (SSL)" : "");
falco_logger::log(falco_logger::level::INFO, "Starting health webserver with threadiness "
+ std::to_string(webserver_config.m_threadiness)
+ std::to_string(s.config->m_webserver_threadiness)
+ ", listening on "
+ webserver_config.m_listen_address
+ s.config->m_webserver_listen_address
+ ":"
+ std::to_string(webserver_config.m_listen_port)
+ std::to_string(s.config->m_webserver_listen_port)
+ ssl_option + "\n");
state.webserver.start(
state,
webserver_config);
s.webserver.start(
s.offline_inspector,
s.config->m_webserver_threadiness,
s.config->m_webserver_listen_port,
s.config->m_webserver_listen_address,
s.config->m_webserver_k8s_healthz_endpoint,
s.config->m_webserver_ssl_certificate,
s.config->m_webserver_ssl_enabled);
}
#endif
return run_result::ok();
}
falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& state)
falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& s)
{
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(!state.is_capture_mode() && state.config->m_webserver_enabled)
if(!s.is_capture_mode() && s.config->m_webserver_enabled)
{
if (state.options.dry_run)
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping stopping webserver in dry-run\n");
return run_result::ok();
}
state.webserver.stop();
s.webserver.stop();
}
#endif
return run_result::ok();
}

View File

@@ -95,7 +95,6 @@ bool falco::app::run(falco::app::state& s, bool& restart, std::string& errstr)
falco::app::actions::unregister_signal_handlers,
falco::app::actions::stop_grpc_server,
falco::app::actions::stop_webserver,
falco::app::actions::close_inspectors,
};
falco::app::run_result res = falco::app::run_result::ok();

View File

@@ -26,6 +26,25 @@ limitations under the License.
namespace falco {
namespace app {
// Most bool member variables do not need to be set explicitly, as
// they are bound to command line options that have default
// values. However, a few options can be ifdef'd out so explicitly
// initialize their linked variables.
options::options()
: event_buffer_format(sinsp_evt::PF_NORMAL),
list_fields(false),
list_plugins(false),
list_syscall_events(false),
markdown(false),
unbuffered_outputs(false),
dry_run(false)
{
}
options::~options()
{
}
bool options::parse(int argc, char **argv, std::string &errstr)
{
cxxopts::Options opts("falco", "Falco - Cloud Native Runtime Security");
@@ -98,7 +117,6 @@ bool options::parse(int argc, char **argv, std::string &errstr)
// Convert the vectors of enabled/disabled tags into sets to match falco engine API
if(m_cmdline_parsed.count("T") > 0)
{
falco_logger::log(falco_logger::level::WARNING, "The -T option is deprecated and will be removed in Falco 0.39.0. Use -o rules[].disable.tag=<tag> instead.");
for(auto &tag : m_cmdline_parsed["T"].as<std::vector<std::string>>())
{
disabled_rule_tags.insert(tag);
@@ -107,18 +125,12 @@ bool options::parse(int argc, char **argv, std::string &errstr)
if(m_cmdline_parsed.count("t") > 0)
{
falco_logger::log(falco_logger::level::WARNING, "The -t option is deprecated and will be removed in Falco 0.39.0. Use -o rules[].disable.rule=* -o rules[].enable.tag=<tag> instead.");
for(auto &tag : m_cmdline_parsed["t"].as<std::vector<std::string>>())
{
enabled_rule_tags.insert(tag);
}
}
if(disabled_rule_substrings.size() > 0)
{
falco_logger::log(falco_logger::level::WARNING, "The -D option is deprecated and will be removed in Falco 0.39.0. Use -o rules[].disable.rule=<wildcard-pattern> instead.");
}
// Some combinations of arguments are not allowed.
// You can't both disable and enable rules
@@ -156,7 +168,7 @@ void options::define(cxxopts::Options& opts)
#endif
("disable-source", "Turn off a specific <event_source>. By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times, but turning off all event sources simultaneously is not permitted. This option can not be mixed with --enable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(disable_sources), "<event_source>")
("dry-run", "Run Falco without processing events. It can help check that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false"))
("D", "DEPRECATED: use -o rules[].disable.rule=<wildcard-pattern> instead. Turn off any rules with names having the substring <substring>. This option can be passed multiple times. It cannot be mixed with -t.", cxxopts::value(disabled_rule_substrings), "<substring>")
("D", "Turn off any rules with names having the substring <substring>. This option can be passed multiple times. It cannot be mixed with -t.", cxxopts::value(disabled_rule_substrings), "<substring>")
("enable-source", "Enable a specific <event_source>. By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. When using this option, only the event sources specified by it will be enabled. This option can not be mixed with --disable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(enable_sources), "<event_source>")
#ifdef HAS_GVISOR
("gvisor-generate-config", "Generate a configuration file that can be used for gVisor and exit. See --gvisor-config for more details.", cxxopts::value<std::string>(gvisor_generate_config_with_socket)->implicit_value("/run/falco/gvisor.sock"), "<socket_path>")
@@ -172,13 +184,13 @@ void options::define(cxxopts::Options& opts)
("N", "Only print field names when used in conjunction with the --list option. It has no effect when used with other options.", cxxopts::value(names_only)->default_value("false"))
("o,option", "Set the value of option <opt> to <val>. Overrides values in the configuration file. <opt> can be identified using its location in the configuration file using dot notation. Elements of list entries can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "<opt>=<val>")
("plugin-info", "Print info for the plugin specified by <plugin_name> and exit.\nThis includes all descriptive information like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n<plugin_name> can be the plugin's name or its configured 'library_path'.", cxxopts::value(print_plugin_info), "<plugin_name>")
("p,print", "Print (or replace) additional information in the rule's output.\nUse -pc or -pcontainer to append container details to syscall events.\nUse -pk or -pkubernetes to add both container and Kubernetes details to syscall events.\nIf using gVisor, choose -pcg or -pkg variants (or -pcontainer-gvisor and -pkubernetes-gvisor, respectively).\nIf a syscall rule's output contains %container.info, it will be replaced with the corresponding details. Otherwise, these details will be directly appended to the rule's output.\nAlternatively, use -p <output_format> for a custom format. In this case, the given <output_format> will be appended to the rule's output without any replacement to all events, including plugin events.", cxxopts::value(print_additional), "<output_format>")
("p,print", "Print (or replace) additional information in the rule's output.\nUse -pc or -pcontainer to append container details.\nUse -pk or -pkubernetes to add both container and Kubernetes details.\nIf using gVisor, choose -pcg or -pkg variants (or -pcontainer-gvisor and -pkubernetes-gvisor, respectively).\nIf a rule's output contains %container.info, it will be replaced with the corresponding details. Otherwise, these details will be directly appended to the rule's output.\nAlternatively, use -p <output_format> for a custom format. In this case, the given <output_format> will be appended to the rule's output without any replacement.", cxxopts::value(print_additional), "<output_format>")
("P,pidfile", "Write PID to specified <pid_file> path. By default, no PID file is created.", cxxopts::value(pidfilename)->default_value(""), "<pid_file>")
("r", "Rules file or directory to be loaded. This option can be passed multiple times. Falco defaults to the values in the configuration file when this option is not specified.", cxxopts::value<std::vector<std::string>>(), "<rules_file>")
("S,snaplen", "Collect only the first <len> bytes of each I/O buffer for 'syscall' events. By default, the first 80 bytes are collected by the driver and sent to the user space for processing. Use this option with caution since it can have a strong performance impact.", cxxopts::value(snaplen)->default_value("0"), "<len>")
("support", "Print support information, including version, rules files used, loaded configuration, etc., and exit. The output is in JSON format.", cxxopts::value(print_support)->default_value("false"))
("T", "DEPRECATED: use -o rules[].disable.tag=<tag> instead. Turn off any rules with a tag=<tag>. This option can be passed multiple times. This option can not be mixed with -t.", cxxopts::value<std::vector<std::string>>(), "<tag>")
("t", "DEPRECATED: use -o rules[].disable.rule=* -o rules[].enable.tag=<tag> instead. Only enable those rules with a tag=<tag>. This option can be passed multiple times. This option can not be mixed with -T/-D.", cxxopts::value<std::vector<std::string>>(), "<tag>")
("T", "Turn off any rules with a tag=<tag>. This option can be passed multiple times. This option can not be mixed with -t.", cxxopts::value<std::vector<std::string>>(), "<tag>")
("t", "Only enable those rules with a tag=<tag>. This option can be passed multiple times. This option can not be mixed with -T/-D.", cxxopts::value<std::vector<std::string>>(), "<tag>")
("U,unbuffered", "Turn off output buffering for configured outputs. This causes every single line emitted by Falco to be flushed, which generates higher CPU usage but is useful when piping those outputs into another process or a script.", cxxopts::value(unbuffered_outputs)->default_value("false"))
("V,validate", "Read the contents of the specified <rules_file> file(s), validate the loaded rules, and exit. This option can be passed multiple times to validate multiple files.", cxxopts::value(validate_rules_filenames), "<rules_file>")
("v", "Enable verbose output.", cxxopts::value(verbose)->default_value("false"))

View File

@@ -31,50 +31,50 @@ namespace app {
class options {
public:
options() = default;
~options() = default;
options();
virtual ~options();
options(options&&) = default;
options& operator = (options&&) = default;
options(const options&) = default;
options& operator = (const options&) = default;
// Each of these maps directly to a command line option.
bool help = false;
bool help;
std::string conf_filename;
bool all_events = false;
sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL;
bool all_events;
sinsp_evt::param_fmt event_buffer_format;
std::vector<std::string> cri_socket_paths;
bool disable_cri_async = false;
bool disable_cri_async;
std::vector<std::string> disable_sources;
std::vector<std::string> disabled_rule_substrings;
std::vector<std::string> enable_sources;
std::string gvisor_generate_config_with_socket;
bool describe_all_rules = false;
bool describe_all_rules;
std::string describe_rule;
bool print_ignored_events;
bool list_fields = false;
bool list_fields;
std::string list_source_fields;
bool list_plugins = false;
bool list_plugins;
std::string print_plugin_info;
bool list_syscall_events = false;
bool markdown = false;
int duration_to_tot = 0;
bool names_only = false;
bool list_syscall_events;
bool markdown;
int duration_to_tot;
bool names_only;
std::vector<std::string> cmdline_config_options;
std::string print_additional;
std::string pidfilename;
// Rules list as passed by the user, via cmdline option '-r'
std::list<std::string> rules_filenames;
uint64_t snaplen = 0;
bool print_support = false;
uint64_t snaplen;
bool print_support;
std::set<std::string> disabled_rule_tags;
std::set<std::string> enabled_rule_tags;
bool unbuffered_outputs = false;
bool unbuffered_outputs;
std::vector<std::string> validate_rules_filenames;
bool verbose = false;
bool print_version_info = false;
bool print_page_size = false;
bool dry_run = false;
bool verbose;
bool print_version_info;
bool print_page_size;
bool dry_run;
bool parse(int argc, char **argv, std::string &errstr);

View File

@@ -17,7 +17,7 @@ limitations under the License.
#include "restart_handler.h"
#include "signals.h"
#include "logger.h"
#include "../logger.h"
#include <string.h>
#include <fcntl.h>

View File

@@ -48,11 +48,18 @@ struct state
// Holds the info mapped for each loaded event source
struct source_info
{
source_info() : filterchecks(std::make_shared<filter_check_list>()) {}
source_info():
engine_idx(-1),
filterchecks(new filter_check_list()),
inspector(nullptr) { }
source_info(source_info&&) = default;
source_info& operator = (source_info&&) = default;
source_info(const source_info&) = default;
source_info& operator = (const source_info&) = default;
// The index of the given event source in the state's falco_engine,
// as returned by falco_engine::add_source
std::size_t engine_idx = -1;
std::size_t engine_idx;
// The filtercheck list containing all fields compatible
// with the given event source
std::shared_ptr<filter_check_list> filterchecks;
@@ -64,21 +71,32 @@ struct state
};
state():
restart(false),
config(std::make_shared<falco_configuration>()),
outputs(nullptr),
engine(std::make_shared<falco_engine>()),
offline_inspector(std::make_shared<sinsp>())
loaded_sources(),
enabled_sources(),
offline_inspector(std::make_shared<sinsp>()),
source_infos(),
plugin_configs(),
selected_sc_set(),
syscall_buffer_bytes_size(DEFAULT_DRIVER_BUFFER_BYTES_DIM),
restarter(nullptr)
{
}
state(const std::string& cmd, const falco::app::options& opts): state()
{
cmdline = cmd;
options = opts;
cmdline = cmd;
options = opts;
}
~state() = default;
std::string cmdline;
falco::app::options options;
std::atomic<bool> restart = false;
std::atomic<bool> restart;
std::shared_ptr<falco_configuration> config;
@@ -111,7 +129,7 @@ struct state
libsinsp::events::set<ppm_sc_code> selected_sc_set;
// Dimension of the syscall buffer in bytes.
uint64_t syscall_buffer_bytes_size = DEFAULT_DRIVER_BUFFER_BYTES_DIM;
uint64_t syscall_buffer_bytes_size;
// Helper responsible for watching of handling hot application restarts
std::shared_ptr<restart_handler> restarter;

View File

@@ -60,35 +60,39 @@ falco_configuration::falco_configuration():
m_grpc_enabled(false),
m_grpc_threadiness(0),
m_webserver_enabled(false),
m_webserver_threadiness(0),
m_webserver_listen_port(8765),
m_webserver_listen_address("0.0.0.0"),
m_webserver_k8s_healthz_endpoint("/healthz"),
m_webserver_ssl_enabled(false),
m_syscall_evt_drop_threshold(.1),
m_syscall_evt_drop_rate(.03333),
m_syscall_evt_drop_max_burst(1),
m_syscall_evt_simulate_drops(false),
m_syscall_evt_timeout_max_consecutives(1000),
m_falco_libs_thread_table_size(DEFAULT_FALCO_LIBS_THREAD_TABLE_SIZE),
m_base_syscalls_repair(false),
m_metrics_enabled(false),
m_metrics_interval_str("5000"),
m_metrics_interval(5000),
m_metrics_stats_rule_enabled(false),
m_metrics_output_file(""),
m_metrics_flags(0),
m_metrics_flags((PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS | PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS)),
m_metrics_convert_memory_to_mb(true),
m_metrics_include_empty_values(false)
{
}
void falco_configuration::init_from_content(const std::string& config_content, const std::vector<std::string>& cmdline_options, const std::string& filename)
void falco_configuration::init(const std::vector<std::string>& cmdline_options)
{
config.load_from_string(config_content);
init_cmdline_options(cmdline_options);
load_yaml(filename);
yaml_helper config;
config.load_from_string("");
init_cmdline_options(config, cmdline_options);
load_yaml("default", config);
}
void falco_configuration::init_from_file(const std::string& conf_filename, std::vector<std::string>& loaded_conf_files,
const std::vector<std::string> &cmdline_options)
void falco_configuration::init(const std::string& conf_filename, const std::vector<std::string> &cmdline_options)
{
loaded_conf_files.clear();
yaml_helper config;
try
{
config.load_from_file(conf_filename);
@@ -98,90 +102,12 @@ void falco_configuration::init_from_file(const std::string& conf_filename, std::
std::cerr << "Cannot read config file (" + conf_filename + "): " + e.what() + "\n";
throw e;
}
init_cmdline_options(cmdline_options);
merge_config_files(conf_filename, loaded_conf_files);
load_yaml(conf_filename);
init_cmdline_options(config, cmdline_options);
load_yaml(conf_filename, config);
}
std::string falco_configuration::dump()
{
return config.dump();
}
void falco_configuration::merge_config_files(const std::string& config_name, std::vector<std::string>& loaded_config_files)
{
// Load configs files to be included and merge them into current config
// NOTE: loaded_config_files will resolve to the filepaths list of loaded config.
// m_loaded_configs_filenames and m_loaded_configs_folders instead will hold the list of
// filenames and folders specified in config (minus the skipped ones).
loaded_config_files.push_back(config_name);
m_loaded_configs_filenames.push_back(config_name);
const auto ppath = std::filesystem::path(config_name);
// Parse files to be included
std::vector<std::string> include_files;
config.get_sequence<std::vector<std::string>>(include_files, yaml_helper::configs_key);
for(const std::string& include_file : include_files)
{
auto include_file_path = std::filesystem::path(include_file);
if (include_file_path == ppath)
{
throw std::logic_error(
"Config error: '" + yaml_helper::configs_key + "' directive tried to recursively include main config file: " + config_name + ".");
}
if (!std::filesystem::exists(include_file_path))
{
// Same we do for rules_file: just skip the entry.
continue;
}
if (std::filesystem::is_regular_file(include_file_path))
{
config.include_config_file(include_file_path.string());
loaded_config_files.push_back(include_file);
m_loaded_configs_filenames.push_back(include_file);
}
else if (std::filesystem::is_directory(include_file_path))
{
m_loaded_configs_folders.push_back(include_file);
std::vector<std::string> v;
const auto it_options = std::filesystem::directory_options::follow_directory_symlink
| std::filesystem::directory_options::skip_permission_denied;
for (auto const& dir_entry : std::filesystem::directory_iterator(include_file_path, it_options))
{
if (std::filesystem::is_regular_file(dir_entry.path()))
{
v.push_back(dir_entry.path().string());
}
}
std::sort(v.begin(), v.end());
for (const auto &f : v)
{
config.include_config_file(f);
loaded_config_files.push_back(f);
}
}
}
#if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__)
for(auto &filename : m_loaded_configs_filenames)
{
m_loaded_configs_filenames_sha256sum.insert({filename, falco::utils::calculate_file_sha256sum(filename)});
}
#endif
}
void falco_configuration::init_logger()
{
m_log_level = config.get_scalar<std::string>("log_level", "info");
falco_logger::set_level(m_log_level);
falco_logger::set_sinsp_logging(
config.get_scalar<bool>("libs_logger.enabled", false),
config.get_scalar<std::string>("libs_logger.severity", "debug"),
"[libs]: ");
falco_logger::log_stderr = config.get_scalar<bool>("log_stderr", false);
falco_logger::log_syslog = config.get_scalar<bool>("log_syslog", true);
}
void falco_configuration::load_engine_config(const std::string& config_name)
void falco_configuration::load_engine_config(const std::string& config_name, const yaml_helper& config)
{
// Set driver mode if not already set.
const std::unordered_map<std::string, engine_kind_t> engine_mode_lut = {
@@ -250,34 +176,17 @@ void falco_configuration::load_engine_config(const std::string& config_name)
}
}
void falco_configuration::load_yaml(const std::string& config_name)
void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config)
{
init_logger();
load_engine_config(config_name);
load_engine_config(config_name, config);
m_log_level = config.get_scalar<std::string>("log_level", "info");
std::list<std::string> rules_files;
// Small glue code to support old deprecated 'rules_file' config key.
int num_rules_files_opts = 0;
if (config.is_defined("rules_files"))
{
num_rules_files_opts++;
config.get_sequence<std::list<std::string>>(rules_files, std::string("rules_files"));
}
if (config.is_defined("rules_file"))
{
num_rules_files_opts++;
config.get_sequence<std::list<std::string>>(rules_files, std::string("rules_file"));
falco_logger::log(falco_logger::level::WARNING, "Using deprecated config key 'rules_file' (singular form). Please use new 'rules_files' config key (plural form).");
}
if (num_rules_files_opts == 2)
{
throw std::logic_error("Error reading config file (" + config_name + "): both 'rules_files' and 'rules_file' keys set");
}
config.get_sequence<std::list<std::string>>(rules_files, std::string("rules_file"));
m_rules_filenames.clear();
m_loaded_rules_filenames.clear();
m_loaded_rules_filenames_sha256sum.clear();
m_loaded_rules_folders.clear();
for(auto &file : rules_files)
{
@@ -424,6 +333,19 @@ void falco_configuration::load_yaml(const std::string& config_name)
m_outputs.push_back(grpc_output);
}
m_log_level = config.get_scalar<std::string>("log_level", "info");
falco_logger::set_level(m_log_level);
falco_logger::set_sinsp_logging(
config.get_scalar<bool>("libs_logger.enabled", false),
config.get_scalar<std::string>("libs_logger.severity", "debug"),
"[libs]: ");
falco_logger::log_stderr = config.get_scalar<bool>("log_stderr", false);
falco_logger::log_syslog = config.get_scalar<bool>("log_syslog", true);
m_output_timeout = config.get_scalar<uint32_t>("output_timeout", 2000);
std::string rule_matching = config.get_scalar<std::string>("rule_matching", "first");
@@ -449,22 +371,21 @@ void falco_configuration::load_yaml(const std::string& config_name)
m_time_format_iso_8601 = config.get_scalar<bool>("time_format_iso_8601", false);
m_webserver_enabled = config.get_scalar<bool>("webserver.enabled", false);
m_webserver_config.m_threadiness = config.get_scalar<uint32_t>("webserver.threadiness", 0);
m_webserver_config.m_listen_port = config.get_scalar<uint32_t>("webserver.listen_port", 8765);
m_webserver_config.m_listen_address = config.get_scalar<std::string>("webserver.listen_address", "0.0.0.0");
if(!re2::RE2::FullMatch(m_webserver_config.m_listen_address, ip_address_re))
m_webserver_threadiness = config.get_scalar<uint32_t>("webserver.threadiness", 0);
m_webserver_listen_port = config.get_scalar<uint32_t>("webserver.listen_port", 8765);
m_webserver_listen_address = config.get_scalar<std::string>("webserver.listen_address", "0.0.0.0");
if(!re2::RE2::FullMatch(m_webserver_listen_address, ip_address_re))
{
throw std::logic_error("Error reading config file (" + config_name + "): webserver listen address \"" + m_webserver_config.m_listen_address + "\" is not a valid IP address");
throw std::logic_error("Error reading config file (" + config_name + "): webserver listen address \"" + m_webserver_listen_address + "\" is not a valid IP address");
}
m_webserver_config.m_k8s_healthz_endpoint = config.get_scalar<std::string>("webserver.k8s_healthz_endpoint", "/healthz");
m_webserver_config.m_ssl_enabled = config.get_scalar<bool>("webserver.ssl_enabled", false);
m_webserver_config.m_ssl_certificate = config.get_scalar<std::string>("webserver.ssl_certificate", "/etc/falco/falco.pem");
if(m_webserver_config.m_threadiness == 0)
m_webserver_k8s_healthz_endpoint = config.get_scalar<std::string>("webserver.k8s_healthz_endpoint", "/healthz");
m_webserver_ssl_enabled = config.get_scalar<bool>("webserver.ssl_enabled", false);
m_webserver_ssl_certificate = config.get_scalar<std::string>("webserver.ssl_certificate", "/etc/falco/falco.pem");
if(m_webserver_threadiness == 0)
{
m_webserver_config.m_threadiness = falco::utils::hardware_concurrency();
m_webserver_threadiness = falco::utils::hardware_concurrency();
}
m_webserver_config.m_prometheus_metrics_enabled = config.get_scalar<bool>("webserver.prometheus_metrics_enabled", false);
std::list<std::string> syscall_event_drop_acts;
config.get_sequence(syscall_event_drop_acts, "syscall_event_drops.actions");
@@ -522,8 +443,6 @@ void falco_configuration::load_yaml(const std::string& config_name)
throw std::logic_error("Error reading config file(" + config_name + "): the maximum consecutive timeouts without an event must be an unsigned integer > 0");
}
m_falco_libs_thread_table_size = config.get_scalar<std::uint32_t>("falco_libs.thread_table_size", DEFAULT_FALCO_LIBS_THREAD_TABLE_SIZE);
m_base_syscalls_custom_set.clear();
config.get_sequence<std::unordered_set<std::string>>(m_base_syscalls_custom_set, std::string("base_syscalls.custom_set"));
m_base_syscalls_repair = config.get_scalar<bool>("base_syscalls.repair", false);
@@ -535,36 +454,30 @@ void falco_configuration::load_yaml(const std::string& config_name)
m_metrics_output_file = config.get_scalar<std::string>("metrics.output_file", "");
m_metrics_flags = 0;
if (config.get_scalar<bool>("metrics.rules_counters_enabled", true))
{
m_metrics_flags |= METRICS_V2_RULE_COUNTERS;
}
if (config.get_scalar<bool>("metrics.resource_utilization_enabled", true))
{
m_metrics_flags |= METRICS_V2_RESOURCE_UTILIZATION;
m_metrics_flags |= PPM_SCAP_STATS_RESOURCE_UTILIZATION;
}
if (config.get_scalar<bool>("metrics.state_counters_enabled", true))
{
m_metrics_flags |= METRICS_V2_STATE_COUNTERS;
m_metrics_flags |= PPM_SCAP_STATS_STATE_COUNTERS;
}
if (config.get_scalar<bool>("metrics.kernel_event_counters_enabled", true))
{
m_metrics_flags |= METRICS_V2_KERNEL_COUNTERS;
m_metrics_flags |= PPM_SCAP_STATS_KERNEL_COUNTERS;
}
if (config.get_scalar<bool>("metrics.libbpf_stats_enabled", true))
{
m_metrics_flags |= METRICS_V2_LIBBPF_STATS;
}
if (config.get_scalar<bool>("metrics.plugins_metrics_enabled", true))
{
m_metrics_flags |= METRICS_V2_PLUGINS;
m_metrics_flags |= PPM_SCAP_STATS_LIBBPF_STATS;
}
m_metrics_convert_memory_to_mb = config.get_scalar<bool>("metrics.convert_memory_to_mb", true);
m_metrics_include_empty_values = config.get_scalar<bool>("metrics.include_empty_values", false);
config.get_sequence<std::vector<rule_selection_config>>(m_rules_selection, "rules");
std::vector<std::string> load_plugins;
bool load_plugins_node_defined = config.is_defined("load_plugins");
@@ -632,7 +545,7 @@ void falco_configuration::read_rules_file_directory(const std::string &path, std
std::vector<std::string> dir_filenames;
const auto it_options = fs::directory_options::follow_directory_symlink
| fs::directory_options::skip_permission_denied;
| fs::directory_options::follow_directory_symlink;
for (auto const& dir_entry : fs::directory_iterator(rules_path, it_options))
{
@@ -673,15 +586,15 @@ static bool split(const std::string &str, char delim, std::pair<std::string, std
return true;
}
void falco_configuration::init_cmdline_options(const std::vector<std::string> &cmdline_options)
void falco_configuration::init_cmdline_options(yaml_helper& config, const std::vector<std::string> &cmdline_options)
{
for(const std::string &option : cmdline_options)
{
set_cmdline_option(option);
set_cmdline_option(config, option);
}
}
void falco_configuration::set_cmdline_option(const std::string &opt)
void falco_configuration::set_cmdline_option(yaml_helper& config, const std::string &opt)
{
std::pair<std::string, std::string> keyval;

View File

@@ -83,55 +83,20 @@ public:
std::string m_root;
};
struct webserver_config {
uint32_t m_threadiness = 0;
uint32_t m_listen_port = 8765;
std::string m_listen_address = "0.0.0.0";
std::string m_k8s_healthz_endpoint = "/healthz";
bool m_ssl_enabled = false;
std::string m_ssl_certificate;
bool m_prometheus_metrics_enabled = false;
};
enum class rule_selection_operation {
enable,
disable
};
struct rule_selection_config {
rule_selection_operation m_op;
std::string m_tag;
std::string m_rule;
};
falco_configuration();
virtual ~falco_configuration() = default;
void init_from_file(const std::string& conf_filename, std::vector<std::string>& loaded_conf_files, const std::vector<std::string>& cmdline_options);
void init_from_content(const std::string& config_content, const std::vector<std::string>& cmdline_options, const std::string& filename="default");
std::string dump();
void init(const std::string& conf_filename, const std::vector<std::string>& cmdline_options);
void init(const std::vector<std::string>& cmdline_options);
static void read_rules_file_directory(const std::string& path, std::list<std::string>& rules_filenames, std::list<std::string> &rules_folders);
// Config list as passed by the user. Filenames.
std::list<std::string> m_loaded_configs_filenames;
// Map with filenames and their sha256 of the loaded configs files
std::unordered_map<std::string, std::string> m_loaded_configs_filenames_sha256sum;
// Config list as passed by the user. Folders.
std::list<std::string> m_loaded_configs_folders;
// Rules list as passed by the user
std::list<std::string> m_rules_filenames;
// Actually loaded rules, with folders inspected
std::list<std::string> m_loaded_rules_filenames;
// Map with filenames and their sha256 of the loaded rules files
std::unordered_map<std::string, std::string> m_loaded_rules_filenames_sha256sum;
// List of loaded rule folders
std::list<std::string> m_loaded_rules_folders;
// Rule selection options passed by the user
std::vector<rule_selection_config> m_rules_selection;
bool m_json_output;
bool m_json_include_output_property;
bool m_json_include_tags_property;
@@ -155,7 +120,12 @@ public:
std::string m_grpc_root_certs;
bool m_webserver_enabled;
webserver_config m_webserver_config;
uint32_t m_webserver_threadiness;
uint32_t m_webserver_listen_port;
std::string m_webserver_listen_address;
std::string m_webserver_k8s_healthz_endpoint;
bool m_webserver_ssl_enabled;
std::string m_webserver_ssl_certificate;
syscall_evt_drop_actions m_syscall_evt_drop_actions;
double m_syscall_evt_drop_threshold;
@@ -166,8 +136,6 @@ public:
uint32_t m_syscall_evt_timeout_max_consecutives;
uint32_t m_falco_libs_thread_table_size;
// User supplied base_syscalls, overrides any Falco state engine enforcement.
std::unordered_set<std::string> m_base_syscalls_custom_set;
bool m_base_syscalls_repair;
@@ -191,110 +159,23 @@ public:
replay_config m_replay = {};
gvisor_config m_gvisor = {};
// Needed by tests
yaml_helper config;
private:
void merge_config_files(const std::string& config_name, std::vector<std::string>& loaded_config_files);
void load_yaml(const std::string& config_name);
void init_logger();
void load_engine_config(const std::string& config_name);
void init_cmdline_options(const std::vector<std::string>& cmdline_options);
void load_yaml(const std::string& config_name, const yaml_helper& config);
void load_engine_config(const std::string& config_name, const yaml_helper& config);
void init_cmdline_options(yaml_helper& config, const std::vector<std::string>& cmdline_options);
/**
* Given a <key>=<value> specifier, set the appropriate option
* in the underlying yaml config. <key> can contain '.'
* characters for nesting. Currently only 1- or 2- level keys
* are supported and only scalar values are supported.
*/
void set_cmdline_option(const std::string& spec);
void set_cmdline_option(yaml_helper& config, const std::string& spec);
};
namespace YAML {
template<>
struct convert<falco_configuration::rule_selection_config> {
static Node encode(const falco_configuration::rule_selection_config & rhs) {
Node node;
Node subnode;
if(rhs.m_rule != "")
{
subnode["rule"] = rhs.m_rule;
}
if(rhs.m_tag != "")
{
subnode["tag"] = rhs.m_tag;
}
if(rhs.m_op == falco_configuration::rule_selection_operation::enable)
{
node["enable"] = subnode;
}
else if(rhs.m_op == falco_configuration::rule_selection_operation::disable)
{
node["disable"] = subnode;
}
return node;
}
static bool decode(const Node& node, falco_configuration::rule_selection_config & rhs) {
if(!node.IsMap())
{
return false;
}
if(node["enable"])
{
rhs.m_op = falco_configuration::rule_selection_operation::enable;
const Node& enable = node["enable"];
if(!enable.IsMap())
{
return false;
}
if(enable["rule"])
{
rhs.m_rule = enable["rule"].as<std::string>();
}
if(enable["tag"])
{
rhs.m_tag = enable["tag"].as<std::string>();
}
}
else if(node["disable"])
{
rhs.m_op = falco_configuration::rule_selection_operation::disable;
const Node& disable = node["disable"];
if(!disable.IsMap())
{
return false;
}
if(disable["rule"])
{
rhs.m_rule = disable["rule"].as<std::string>();
}
if(disable["tag"])
{
rhs.m_tag = disable["tag"].as<std::string>();
}
}
else
{
return false;
}
if (rhs.m_rule == "" && rhs.m_tag == "")
{
return false;
}
return true;
}
};
template<>
struct convert<falco_configuration::plugin_config> {

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