Compare commits

..

75 Commits

Author SHA1 Message Date
Federico Di Pierro
b9d5c39dd4 test
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-05 09:36:59 +02:00
Federico Di Pierro
fd6e149db0 chore: test test test ci.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-05 09:32:02 +02:00
Leonardo Grasso
b2374b3c19 fix(userspace/falco): apply suggestions for CLI help messages
Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-04 18:50:52 +02:00
Leonardo Grasso
93e8be1e32 update(userspace/falco): revised CLI help messages
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-04 18:50:52 +02:00
Luca Guerra
b246bcb052 fix(engine): fix werror reorder
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-04 17:26:52 +02:00
Andrea Terzolo
6251af0ab6 new: introduce new stats updated to the latest libs version
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 17:24:52 +02:00
Andrea Terzolo
ce79e01ae8 ci: support tests on amazon-linux
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 15:12:51 +02:00
Leonardo Grasso
9db4c9b2cb build(cmake/modules): upgrade falcoctl to version 0.6.0
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-04 14:18:51 +02:00
Andrea Terzolo
dba685eeda tests: enable e2e falco-driver-loader tests
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 12:19:46 +02:00
Andrea Terzolo
4f8d11acdd chore: bump engine version and checksum
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 12:19:46 +02:00
Andrea Terzolo
3c47915c56 chore: bump Falco to latest libs master
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 12:19:46 +02:00
Federico Di Pierro
0ec492086e fix(userspace/falco): properly delete metrics timer upon leaving.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-04 11:22:46 +02:00
Andrea Terzolo
442d1accbe cleanup: deprecate rate limiter mechanism
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 10:11:45 +02:00
Melissa Kilby
79577237a1 cleanup(config): add info about performance impact wrt rule_matching
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-04 10:10:46 +02:00
Melissa Kilby
08237b946f cleanup(config): add more info
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-04 10:10:46 +02:00
Andrea Terzolo
62e762a467 cleanup: deprecate no more supported userspace mode
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 10:09:46 +02:00
Andrea Terzolo
e6fe0a516d fix: fix falco MINIMAL_BUILD
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 10:09:46 +02:00
dependabot[bot]
a6b12a5c97 build(deps): Bump submodules/falcosecurity-testing
Bumps [submodules/falcosecurity-testing](https://github.com/falcosecurity/testing) from `b39c807` to `9110022`.
- [Commits](b39c807a19...91100227b0)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-testing
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 10:08:46 +02:00
dependabot[bot]
b15a51a825 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `3f52480` to `b42893a`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](3f52480618...b42893a6eb)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-01 06:50:31 +02:00
Jason Dellaluce
c8122ff474 fix(userspace/engine): support appending to unknown sources
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-01 06:46:31 +02:00
Jason Dellaluce
88dcdaac8a update(submodules): bump falcosecurity-testing to b39c807
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-31 18:33:30 +02:00
Jason Dellaluce
eabf49892d update(userspace/falco): bump engine version to 24
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-31 18:33:30 +02:00
Jason Dellaluce
901fca2257 update(userspace/engine): upgrade skip-if-unknown-filter YAML field
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-31 18:33:30 +02:00
Andrea Terzolo
cc8d6705f6 fix: fix "ebpf_enabled" output stat
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-31 17:37:29 +02:00
Federico Di Pierro
26f626c1d5 chore(userspace/falco): properly check that parent init() did not fail for reasons.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-31 16:11:29 +02:00
Federico Di Pierro
acaaa0b4ca cleanup(userspace/falco): improvements to the http output perf.
Moreover, add option to disable stdout echoing.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-08-31 16:11:29 +02:00
hjenkins
63ba15962b fix(scripts): falco-driver-loader add print env
Fixes #2352

Needed to refactor the target_id code paths to allow this to be used in
env printing and sourcing.

Signed-off-by: hjenkins <henry@henryjenkins.name>
2023-08-31 12:10:28 +02:00
dependabot[bot]
f163780d62 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `3ceea88` to `40a9817`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](3ceea88eeb...40a9817330)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-31 09:22:29 +02:00
Jason Dellaluce
01093d2dfc fix(userspace/engine): support both old and new gcc + std::move
Old gcc versions (e.g. 4.8.3) won't allow move elision
but newer versions (e.g. 10.2.1) would complain about
the redundant move.

Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-30 20:57:27 +02:00
Jason Dellaluce
a6c2bf7123 update(cmake): support building libs and driver from forks
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-30 19:13:26 +02:00
Andrea Terzolo
988703b601 clenaup: remove b64 from falco dependencies
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-30 19:12:26 +02:00
jabdr
66841d8009 Support reload in falco-modern-bpf.service
Signed-off-by: jabdr <jd@q321.de>
2023-08-30 15:28:26 +02:00
jabdr
43ae8b0cac Support reload in falco-custom.service
Signed-off-by: jabdr <jd@q321.de>
2023-08-30 15:28:26 +02:00
jabdr
9a5f625d5f Support reload in falco-bpf.service
Signed-off-by: jabdr <jd@q321.de>
2023-08-30 15:28:26 +02:00
jabdr
799c09e638 Support reload in falco-kmod.service
Signed-off-by: jabdr <jd@q321.de>
2023-08-30 15:28:26 +02:00
Richard Tweed
2f267a044e Merge in master
Signed-off-by: Richard Tweed <RichardoC@users.noreply.github.com>
2023-08-29 17:57:21 +02:00
Richard Tweed
7b6d45c394 Update README. based on FedeDP's suggestion
Co-authored-by: Federico Di Pierro <nierro92@gmail.com>
Signed-off-by: Richard Tweed <RichardoC@users.noreply.github.com>
2023-08-29 17:57:21 +02:00
Richard Tweed
368796df61 Issue 2391 Document why Falco is written in C++ rather than anything else
Signed-off-by: Richard Tweed <RichardoC@users.noreply.github.com>
2023-08-29 17:57:21 +02:00
Andrea Terzolo
8d6c6900d3 cleanup: turn a warning into an error
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-29 13:46:21 +02:00
Andrea Terzolo
34d796439f cleanup: fail if the time unit is not specified
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-29 13:46:21 +02:00
Anna Simon
c8d1637130 feat(userspace/outputs_http): Add option for mTLS
Signed-off-by: Anna Simon <asimon@mercari.com>
2023-08-29 10:28:21 +02:00
Jason Dellaluce
600318aaae update(ci): minimize retention days for build-only CI artifacts
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-29 09:33:21 +02:00
Andrea Terzolo
ba1528e3c2 cleanup: remove unused --pidfile option
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-28 17:06:19 +02:00
Melissa Kilby
37ea9b25c4 feat(userspace): deprecate -d daemonize option
Deprecate `-d` option (currently broken).

Symptoms included the message queue filling up without popping any messages
even though events were handled normally.

Maintainers decided to deprecate not needed `-d` option while keeping
the useful `pidfile` command args option.

Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-25 18:14:45 +02:00
Melissa Kilby
b66bf2c6e4 cleanup: remove some unused variables
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-25 15:20:45 +02:00
Melissa Kilby
0d4e77bcbe cleanup(config): assign Stable to metrics config
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-25 15:20:45 +02:00
Melissa Kilby
6cdb740786 cleanup(userspace): update parse_prometheus_interval
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-25 15:20:45 +02:00
Melissa Kilby
9a12a93342 feat(userspace): deprecate stats command args option in favor of metrics configs in falco.yaml
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-25 15:20:45 +02:00
Leonardo Grasso
84fe33a029 fix(userspace/falco): correct typo in -p help message
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-25 15:18:45 +02:00
Leonardo Grasso
8fbf49bbba update(userspace/falco): new defaults for -p presets
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-25 15:18:45 +02:00
Leonardo Grasso
f10d0499d2 update(userspace/falco): improve help message for -p option
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-25 15:18:45 +02:00
dependabot[bot]
259095651b build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `bf1639a` to `3ceea88`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](bf1639a574...3ceea88eeb)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-25 10:26:45 +02:00
dependabot[bot]
e5b9dd2dfc build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `64ce419` to `bf1639a`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](64ce419d92...bf1639a574)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-24 11:48:39 +02:00
Melissa Kilby
9620515e40 cleanup(config): assign Stable to base_syscalls config
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-24 10:41:39 +02:00
Jason Dellaluce
4f3181cb1c update(userspace/engine): bump engine version to 23
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
fe66abf15c update(cmake): bump libs and driver to 6caaa3c85d7c783b29cd32832f2552a4bd6cd739
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
527c42c030 chore: polish conditional compilation flags for emscripten
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
aa62b65c70 update(cmake): bump libs and drivers to 1bb3eea5380c06a4aceb635f70cf62829951ef00
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
78e2ddc63e fix: solve cmake issues
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
179b191f70 chore(cmake): cleanup comment
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
a439d5b556 refactor(ci): build and upload WASM packages
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
828fa7d14d update(cmake): fix wasm package content
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
590b034a55 fix: solve plugin loading error
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
54ab1eed9e update(cmake): update add emmc link_options
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
rohith-raju
05f483d751 update(cleanup): clean gitignore file
Signed-off-by: rohith-raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
rohith-raju
c73e43c973 cleanup: fix workflow and build errors
Signed-off-by: rohith-raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
rohith-raju
e8ee850dee update(ci,cmake): add support for emscripten build
Signed-off-by: rohith-raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
rohith-raju
105f2f6ee3 update(unit_tests): use typecast as wasm can't handle 64 bit int
Signed-off-by: rohith-raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
ce6368a89e fix: solve runtime issues with emscripten build
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
0faa45669b update(build): setup cpack for emscripten build
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
aa6061681d update: adapt code to multi-platform builds
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
86e76924a1 update: adapt cmake setup for non-linux and emscripten builds
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Johanan Liebermann
e7c5139563 Allow specifying kernel release and version
Signed-off-by: Johanan Liebermann <jliebermann@microsoft.com>
2023-08-24 09:17:39 +02:00
Andrea Terzolo
bc12e567e5 docs(config.yaml): fix wrong severity levels in sinsp
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-23 11:44:28 +02:00
dependabot[bot]
b2ad928d6c build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `0d0e333` to `64ce419`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](0d0e333151...64ce419d92)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-23 10:20:27 +02:00
68 changed files with 918 additions and 573 deletions

View File

@@ -13,6 +13,18 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
my-test:
runs-on: [ "self-hosted", "linux", "ARM64" ]
steps:
- name: etc os release
run: cat /etc/os-release
- name: uname
run: uname -a
- name: install deps
run: sudo yum update && sudo yum install make
fetch-version: fetch-version:
uses: ./.github/workflows/reusable_fetch_version.yaml uses: ./.github/workflows/reusable_fetch_version.yaml

View File

@@ -71,3 +71,4 @@ jobs:
with: with:
name: falco-images name: falco-images
path: /tmp/falco-*.tar path: /tmp/falco-*.tar
retention-days: 1

View File

@@ -36,6 +36,7 @@ jobs:
with: with:
name: bpf_probe_${{ inputs.arch }}.skel.h name: bpf_probe_${{ inputs.arch }}.skel.h
path: skeleton-build/skel_dir/bpf_probe.skel.h path: skeleton-build/skel_dir/bpf_probe.skel.h
retention-days: 1
build-packages: build-packages:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936 # See https://github.com/actions/runner/issues/409#issuecomment-1158849936
@@ -158,3 +159,59 @@ jobs:
name: falco-${{ inputs.version }}-static-x86_64.tar.gz name: falco-${{ inputs.version }}-static-x86_64.tar.gz
path: | path: |
${{ github.workspace }}/build/falco-${{ inputs.version }}-static-x86_64.tar.gz ${{ github.workspace }}/build/falco-${{ inputs.version }}-static-x86_64.tar.gz
build-wasm-package:
if: ${{ inputs.arch == 'x86_64' }}
runs-on: ubuntu-latest
steps:
# Always install deps before invoking checkout action, to properly perform a full clone.
- name: Install build dependencies
run: |
sudo apt update
sudo DEBIAN_FRONTEND=noninteractive apt install cmake build-essential git emscripten -y
- name: Select node version
uses: actions/setup-node@v3
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Prepare project
run: |
mkdir build && cd build
emcmake cmake \
-DBUILD_BPF=Off \
-DBUILD_DRIVER=Off \
-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 }} \
..
- 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@v3
with:
name: falco-${{ inputs.version }}-wasm.tar.gz
path: |
${{ github.workspace }}/build/falco-${{ inputs.version }}-wasm.tar.gz

View File

@@ -44,6 +44,20 @@ jobs:
cd falco-${{ inputs.version }}-${{ inputs.arch }} cd falco-${{ inputs.version }}-${{ inputs.arch }}
sudo cp -r * / sudo cp -r * /
# aarch64 job run on amazon-linux-2
- name: Install dependencies for falco-driver-loader tests on aarch64
if: ${{ inputs.arch == 'aarch64' }}
run: |
sudo yum update -y
sudo yum install -y build-essential clang make llvm gcc dkms kernel-devel-$(uname -r)
# x86_64 job run on ubuntu-22.04
- name: Install dependencies for falco-driver-loader tests on x86
if: ${{ inputs.arch == 'x86_64' }}
run: |
sudo apt update -y
sudo apt install -y --no-install-recommends build-essential clang make llvm gcc dkms linux-headers-$(uname -r)
- name: Install go-junit-report - name: Install go-junit-report
run: | run: |
pushd submodules/falcosecurity-testing pushd submodules/falcosecurity-testing
@@ -63,6 +77,7 @@ jobs:
if ${{ inputs.static && 'false' || 'true' }}; then if ${{ inputs.static && 'false' || 'true' }}; then
./build/falcoctl.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true ./build/falcoctl.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
./build/k8saudit.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true ./build/k8saudit.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
sudo ./build/falco-driver-loader.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
fi fi
cat ./report.txt | go-junit-report -set-exit-code > report.xml cat ./report.txt | go-junit-report -set-exit-code > report.xml
popd popd

View File

@@ -20,6 +20,14 @@ option(MINIMAL_BUILD "Build a minimal version of Falco, containing only the engi
option(MUSL_OPTIMIZED_BUILD "Enable if you want a musl optimized build" 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(BUILD_FALCO_UNIT_TESTS "Build falco unit tests" OFF)
if(EMSCRIPTEN)
set(USE_BUNDLED_DEPS ON CACHE BOOL "" FORCE)
set(BUILD_DRIVER OFF CACHE BOOL "" FORCE)
set(ENABLE_DKMS OFF CACHE BOOL "" FORCE)
set(BUILD_BPF OFF CACHE BOOL "" FORCE)
set(CPACK_GENERATOR TGZ CACHE BOOL "" FORCE)
endif()
# gVisor is currently only supported on Linux x86_64 # gVisor is currently only supported on Linux x86_64
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD) if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
option(BUILD_FALCO_GVISOR "Build gVisor support for Falco" ON) option(BUILD_FALCO_GVISOR "Build gVisor support for Falco" ON)
@@ -68,7 +76,11 @@ if(NOT DEFINED FALCO_ETC_DIR)
endif() endif()
# This will be used to print the architecture for which Falco is compiled. # This will be used to print the architecture for which Falco is compiled.
if (EMSCRIPTEN)
set(FALCO_TARGET_ARCH "wasm")
else()
set(FALCO_TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR}) set(FALCO_TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR})
endif()
if(NOT FALCO_EXTRA_DEBUG_FLAGS) if(NOT FALCO_EXTRA_DEBUG_FLAGS)
set(FALCO_EXTRA_DEBUG_FLAGS "-D_DEBUG") set(FALCO_EXTRA_DEBUG_FLAGS "-D_DEBUG")
@@ -95,7 +107,10 @@ endif()
# explicitly set hardening flags # explicitly set hardening flags
set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(FALCO_SECURITY_FLAGS "-Wl,-z,relro,-z,now -fstack-protector-strong") set(FALCO_SECURITY_FLAGS "")
if(NOT EMSCRIPTEN)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -Wl,-z,relro,-z,now -fstack-protector-strong")
endif()
if(CMAKE_BUILD_TYPE STREQUAL "release") if(CMAKE_BUILD_TYPE STREQUAL "release")
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -D_FORTIFY_SOURCE=2") set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -D_FORTIFY_SOURCE=2")
endif() endif()
@@ -154,19 +169,17 @@ include(jq)
# nlohmann-json # nlohmann-json
include(njson) include(njson)
# b64
include(b64)
# yaml-cpp # yaml-cpp
include(yaml-cpp) include(yaml-cpp)
if(NOT MINIMAL_BUILD) if(NOT WIN32 AND NOT APPLE AND NOT MINIMAL_BUILD AND NOT EMSCRIPTEN)
# OpenSSL # OpenSSL
include(openssl) include(openssl)
# libcurl # libcurl
include(curl) include(curl)
# todo(jasondellaluce,rohith-raju): support webserver for non-linux builds too
# cpp-httlib # cpp-httlib
include(cpp-httplib) include(cpp-httplib)
endif() endif()
@@ -174,15 +187,19 @@ endif()
include(cxxopts) include(cxxopts)
# One TBB # One TBB
if (NOT EMSCRIPTEN)
include(tbb) include(tbb)
endif()
if (NOT MINIMAL_BUILD) if (NOT MINIMAL_BUILD)
include(zlib) include(zlib)
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN)
include(cares) include(cares)
include(protobuf) include(protobuf)
# gRPC # gRPC
include(grpc) include(grpc)
endif() endif()
endif()
# Installation # Installation
install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}") install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
@@ -212,11 +229,10 @@ add_subdirectory(scripts)
add_subdirectory(userspace/engine) add_subdirectory(userspace/engine)
add_subdirectory(userspace/falco) add_subdirectory(userspace/falco)
if(NOT MUSL_OPTIMIZED_BUILD) if(NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT MUSL_OPTIMIZED_BUILD)
include(plugins) include(plugins)
endif()
include(falcoctl) include(falcoctl)
endif()
# Packages configuration # Packages configuration
include(CPackConfig) include(CPackConfig)

View File

@@ -73,11 +73,24 @@ To report security vulnerabilities, please follow the community process outlined
Stay updated with Falco's evolving capabilities by exploring the [Falco Roadmap](https://github.com/orgs/falcosecurity/projects/5), which provides insights into the features currently under development and planned for future releases. Stay updated with Falco's evolving capabilities by exploring the [Falco Roadmap](https://github.com/orgs/falcosecurity/projects/5), which provides insights into the features currently under development and planned for future releases.
## License ## License
Falco is licensed to you under the [Apache 2.0](./COPYING) open source license. Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
## Why is Falco in C++ rather than Go or {language}?
1. The first lines of code at the base of Falco were written some time ago, where Go didn't yet have the same level of maturity and adoption as today.
2. The Falco execution model is sequential and mono-thread due to the statefulness requirements of the tool, and so most of the concurrency-related selling points of the Go runtime would not be leveraged at all.
3. The Falco code deals with very low-level programming in many places (e.g. some headers are shared with the eBPF probe and the Kernel module), and we all know that interfacing Go with C is possible but brings tons of complexity and tradeoffs to the table.
4. As a security tool meant to consume a crazy high throughput of events per second, Falco needs to squeeze performance in all hot paths at runtime and requires deep control on memory allocation, which the Go runtime can't provide (there's also garbage collection involved).
5. Although Go didn't suit the engineering requirements of the core of Falco, we still thought that it could be a good candidate for writing Falco extensions through the plugin system. This is the main reason we gave special attention and high priority to the development of the plugin-sdk-go.
6. Go is not a requirement for having statically-linked binaries. In fact, we provide fully-static Falco builds since few years. The only issue with those is that the plugin system can't be supported with the current dynamic library model we currently have.
7. The plugin system has been envisioned to support multiple languages, so on our end maintaining a C-compatible codebase is the best strategy to ensure maximum cross-language compatibility.
8. In general, plugins have GLIBC requirements/dependencies because they have low-level C bindings required for dynamic loading. A potential solution for the future could be to also support plugin to be statically-linked at compilation time and so released as bundled in the Falco binary. Although no work started yet in this direction, this would solve most issues you reported and would provide a totally-static binary too. Of course, this would not be compatible with dynamic loading anymore, but it may be a viable solution for our static-build flavor of Falco.
9. Memory safety is definitely a concern and we try our best to keep an high level of quality even though C++ is quite error prone. For instance, we try to use smart pointers whenever possible, we build the libraries with an address sanitizer in our CI, we run Falco through Valgrind before each release, and have ways to stress-test it to detect performance regressions or weird memory usage (e.g. https://github.com/falcosecurity/event-generator). On top of that, we also have third parties auditing the codebase by time to time. None of this make a perfect safety standpoint of course, but we try to maximize our odds. Go would definitely make our life easier from this perspective, however the tradeoffs never made it worth it so far due to the points above.
10. The C++ codebase of falcosecurity/libs, which is at the core of Falco, is quite large and complex. Porting all that code to another language would be a major effort requiring lots of development resource and with an high chance of failure and regression. As such, our approach so far has been to choose refactors and code polishing instead, up until we'll reach an optimal level of stability, quality, and modularity, on that portion of code. This would allow further developments to be smoother and more feasibile in the future.
## Resources ## Resources
- [Governance](https://github.com/falcosecurity/evolution/blob/main/GOVERNANCE.md) - [Governance](https://github.com/falcosecurity/evolution/blob/main/GOVERNANCE.md)

View File

@@ -20,24 +20,36 @@ set(CPACK_PACKAGE_VERSION "${FALCO_VERSION}")
set(CPACK_PACKAGE_VERSION_MAJOR "${FALCO_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MAJOR "${FALCO_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${FALCO_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_MINOR "${FALCO_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${FALCO_VERSION_PATCH}") set(CPACK_PACKAGE_VERSION_PATCH "${FALCO_VERSION_PATCH}")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}")
set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_SOURCE_DIR}/cmake/cpack/CMakeCPackOptions.cmake") set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_SOURCE_DIR}/cmake/cpack/CMakeCPackOptions.cmake")
set(CPACK_STRIP_FILES "ON") set(CPACK_STRIP_FILES "ON")
set(CPACK_PACKAGE_RELOCATABLE "OFF") set(CPACK_PACKAGE_RELOCATABLE "OFF")
if (EMSCRIPTEN)
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-wasm")
else()
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}")
endif()
# Built packages will include only the following components # Built packages will include only the following components
set(CPACK_INSTALL_CMAKE_PROJECTS set(CPACK_INSTALL_CMAKE_PROJECTS
"${CMAKE_CURRENT_BINARY_DIR};${FALCO_COMPONENT_NAME};${FALCO_COMPONENT_NAME};/" "${CMAKE_CURRENT_BINARY_DIR};${FALCO_COMPONENT_NAME};${FALCO_COMPONENT_NAME};/"
"${CMAKE_CURRENT_BINARY_DIR};${DRIVER_COMPONENT_NAME};${DRIVER_COMPONENT_NAME};/"
) )
if(NOT MUSL_OPTIMIZED_BUILD) # static builds do not have plugins
if(CMAKE_SYSTEM_NAME MATCHES "Linux") # only Linux has drivers
list(APPEND CPACK_INSTALL_CMAKE_PROJECTS list(APPEND CPACK_INSTALL_CMAKE_PROJECTS
"${CMAKE_CURRENT_BINARY_DIR};${PLUGINS_COMPONENT_NAME};${PLUGINS_COMPONENT_NAME};/" "${CMAKE_CURRENT_BINARY_DIR};${DRIVER_COMPONENT_NAME};${DRIVER_COMPONENT_NAME};/")
) endif()
if(NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT MUSL_OPTIMIZED_BUILD) # static builds do not have plugins
list(APPEND CPACK_INSTALL_CMAKE_PROJECTS
"${CMAKE_CURRENT_BINARY_DIR};${PLUGINS_COMPONENT_NAME};${PLUGINS_COMPONENT_NAME};/")
endif() endif()
if(NOT CPACK_GENERATOR) if(NOT CPACK_GENERATOR)
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
set(CPACK_GENERATOR DEB RPM TGZ) set(CPACK_GENERATOR DEB RPM TGZ)
else()
set(CPACK_GENERATOR TGZ)
endif()
endif() endif()
message(STATUS "Using package generators: ${CPACK_GENERATOR}") message(STATUS "Using package generators: ${CPACK_GENERATOR}")

View File

@@ -15,11 +15,12 @@ cmake_minimum_required(VERSION 3.5.1)
project(driver-repo NONE) project(driver-repo NONE)
include(ExternalProject) include(ExternalProject)
message(STATUS "Driver repository: ${DRIVER_REPO}")
message(STATUS "Driver version: ${DRIVER_VERSION}") message(STATUS "Driver version: ${DRIVER_VERSION}")
ExternalProject_Add( ExternalProject_Add(
driver driver
URL "https://github.com/falcosecurity/libs/archive/${DRIVER_VERSION}.tar.gz" URL "https://github.com/${DRIVER_REPO}/archive/${DRIVER_VERSION}.tar.gz"
URL_HASH "${DRIVER_CHECKSUM}" URL_HASH "${DRIVER_CHECKSUM}"
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""

View File

@@ -20,18 +20,29 @@ if(DRIVER_SOURCE_DIR)
set(DRIVER_VERSION "0.0.0-local") set(DRIVER_VERSION "0.0.0-local")
message(STATUS "Using local version for driver: '${DRIVER_SOURCE_DIR}'") message(STATUS "Using local version for driver: '${DRIVER_SOURCE_DIR}'")
else() else()
# DRIVER_REPO accepts a repository name (<org name>/<repo name>) alternative to the falcosecurity/libs repository.
# In case you want to test against a fork of falcosecurity/libs just pass the variable -
# ie., `cmake -DDRIVER_REPO=<your-gh-handle>/libs ..`
if (NOT DRIVER_REPO)
set(DRIVER_REPO "falcosecurity/libs")
endif()
# DRIVER_VERSION accepts a git reference (branch name, commit hash, or tag) to the falcosecurity/libs repository # DRIVER_VERSION accepts a git reference (branch name, commit hash, or tag) to the falcosecurity/libs repository
# which contains the driver source code under the `/driver` directory. # which contains the driver source code under the `/driver` directory.
# The chosen driver version must be compatible with the given FALCOSECURITY_LIBS_VERSION. # The chosen driver version must be compatible with the given FALCOSECURITY_LIBS_VERSION.
# In case you want to test against another driver version (or branch, or commit) just pass the variable - # In case you want to test against another driver version (or branch, or commit) just pass the variable -
# ie., `cmake -DDRIVER_VERSION=dev ..` # ie., `cmake -DDRIVER_VERSION=dev ..`
if(NOT DRIVER_VERSION) if(NOT DRIVER_VERSION)
set(DRIVER_VERSION "942a2249b7b9f65def0a01acfb1fba84f629b3bf") set(DRIVER_VERSION "6301c01b9279c3f4981df24b3e8e0d97c18f76e8")
set(DRIVER_CHECKSUM "SHA256=8670d7b24fad659674cea90b9b3d86e5d0775a6b2faedc0d5303f910242282ff") set(DRIVER_CHECKSUM "SHA256=cc5c51b4a01cf83d36c3af0670a36b2c8b55f3baebc03736725dc6425898d018")
endif() endif()
# cd /path/to/build && cmake /path/to/source # cd /path/to/build && cmake /path/to/source
execute_process(COMMAND "${CMAKE_COMMAND}" -DDRIVER_VERSION=${DRIVER_VERSION} -DDRIVER_CHECKSUM=${DRIVER_CHECKSUM} execute_process(COMMAND "${CMAKE_COMMAND}"
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"
-DDRIVER_REPO=${DRIVER_REPO}
-DDRIVER_VERSION=${DRIVER_VERSION}
-DDRIVER_CHECKSUM=${DRIVER_CHECKSUM}
${DRIVER_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${DRIVER_CMAKE_WORKING_DIR}) ${DRIVER_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${DRIVER_CMAKE_WORKING_DIR})
# cmake --build . # cmake --build .

View File

@@ -15,14 +15,14 @@ include(ExternalProject)
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} FALCOCTL_SYSTEM_NAME) string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} FALCOCTL_SYSTEM_NAME)
set(FALCOCTL_VERSION "0.5.1") set(FALCOCTL_VERSION "0.6.0")
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64") if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(FALCOCTL_SYSTEM_PROC_GO "amd64") set(FALCOCTL_SYSTEM_PROC_GO "amd64")
set(FALCOCTL_HASH "ea7c89134dc745a1cbdbcf8f839d3b47851a40e1aebee20702a606b03b45b897") set(FALCOCTL_HASH "b81c36449b525e1de871288741beeadead021ac133d9b306f0636be1befe58a5")
else() # aarch64 else() # aarch64
set(FALCOCTL_SYSTEM_PROC_GO "arm64") set(FALCOCTL_SYSTEM_PROC_GO "arm64")
set(FALCOCTL_HASH "22797200bf0e4c7c45f69207ed85218a3839115a302dc07939d3006778d41300") set(FALCOCTL_HASH "6e99fd765f67cdd46fa8c5b2969e97497856d2e615698ced04046c8898187b18")
endif() endif()
ExternalProject_Add( ExternalProject_Add(

View File

@@ -15,11 +15,12 @@ cmake_minimum_required(VERSION 3.5.1)
project(falcosecurity-libs-repo NONE) project(falcosecurity-libs-repo NONE)
include(ExternalProject) include(ExternalProject)
message(STATUS "Libs repository: ${FALCOSECURITY_LIBS_REPO}")
message(STATUS "Libs version: ${FALCOSECURITY_LIBS_VERSION}") message(STATUS "Libs version: ${FALCOSECURITY_LIBS_VERSION}")
ExternalProject_Add( ExternalProject_Add(
falcosecurity-libs falcosecurity-libs
URL "https://github.com/falcosecurity/libs/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz" URL "https://github.com/${FALCOSECURITY_LIBS_REPO}/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz"
URL_HASH "${FALCOSECURITY_LIBS_CHECKSUM}" URL_HASH "${FALCOSECURITY_LIBS_CHECKSUM}"
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""

View File

@@ -23,17 +23,25 @@ if(FALCOSECURITY_LIBS_SOURCE_DIR)
set(FALCOSECURITY_LIBS_VERSION "0.0.0-local") set(FALCOSECURITY_LIBS_VERSION "0.0.0-local")
message(STATUS "Using local version of falcosecurity/libs: '${FALCOSECURITY_LIBS_SOURCE_DIR}'") message(STATUS "Using local version of falcosecurity/libs: '${FALCOSECURITY_LIBS_SOURCE_DIR}'")
else() else()
# FALCOSECURITY_LIBS_REPO accepts a repository name (<org name>/<repo name>) alternative to the falcosecurity/libs repository.
# In case you want to test against a fork of falcosecurity/libs just pass the variable -
# ie., `cmake -DFALCOSECURITY_LIBS_REPO=<your-gh-handle>/libs ..`
if (NOT FALCOSECURITY_LIBS_REPO)
set(FALCOSECURITY_LIBS_REPO "falcosecurity/libs")
endif()
# FALCOSECURITY_LIBS_VERSION accepts a git reference (branch name, commit hash, or tag) to the falcosecurity/libs repository. # FALCOSECURITY_LIBS_VERSION accepts a git reference (branch name, commit hash, or tag) to the falcosecurity/libs repository.
# In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable - # 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 ..` # ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION) if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "942a2249b7b9f65def0a01acfb1fba84f629b3bf") set(FALCOSECURITY_LIBS_VERSION "6301c01b9279c3f4981df24b3e8e0d97c18f76e8")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=8670d7b24fad659674cea90b9b3d86e5d0775a6b2faedc0d5303f910242282ff") set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=cc5c51b4a01cf83d36c3af0670a36b2c8b55f3baebc03736725dc6425898d018")
endif() endif()
# cd /path/to/build && cmake /path/to/source # cd /path/to/build && cmake /path/to/source
execute_process(COMMAND "${CMAKE_COMMAND}" execute_process(COMMAND "${CMAKE_COMMAND}"
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"
-DFALCOSECURITY_LIBS_REPO=${FALCOSECURITY_LIBS_REPO}
-DFALCOSECURITY_LIBS_VERSION=${FALCOSECURITY_LIBS_VERSION} -DFALCOSECURITY_LIBS_VERSION=${FALCOSECURITY_LIBS_VERSION}
-DFALCOSECURITY_LIBS_CHECKSUM=${FALCOSECURITY_LIBS_CHECKSUM} -DFALCOSECURITY_LIBS_CHECKSUM=${FALCOSECURITY_LIBS_CHECKSUM}
${FALCOSECURITY_LIBS_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR}) ${FALCOSECURITY_LIBS_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR})
@@ -45,8 +53,10 @@ endif()
set(LIBS_PACKAGE_NAME "falcosecurity") set(LIBS_PACKAGE_NAME "falcosecurity")
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
add_definitions(-D_GNU_SOURCE) add_definitions(-D_GNU_SOURCE)
add_definitions(-DHAS_CAPTURE) add_definitions(-DHAS_CAPTURE)
endif()
if(MUSL_OPTIMIZED_BUILD) if(MUSL_OPTIMIZED_BUILD)
add_definitions(-DMUSL_OPTIMIZED) add_definitions(-DMUSL_OPTIMIZED)

View File

@@ -134,6 +134,12 @@
# By arranging the order of files and rules thoughtfully, you can ensure that # By arranging the order of files and rules thoughtfully, you can ensure that
# desired customizations and rule behaviors are prioritized and applied as # desired customizations and rule behaviors are prioritized and applied as
# intended. # intended.
#
# With Falco 0.36 and beyond, it's now possible to apply multiple rules that match
# the same event type, eliminating concerns about rule prioritization based on the
# "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_file: rules_file:
- /etc/falco/falco_rules.yaml - /etc/falco/falco_rules.yaml
- /etc/falco/falco_rules.local.yaml - /etc/falco/falco_rules.local.yaml
@@ -266,6 +272,9 @@ buffered_outputs: false
# [Stable] `outputs` # [Stable] `outputs`
# #
# [DEPRECATED]
# This config is deprecated and it will be removed in Falco 0.37
#
# A throttling mechanism, implemented as a token bucket, can be used to control # A throttling mechanism, implemented as a token bucket, can be used to control
# the rate of Falco outputs. Each event source has its own rate limiter, # the rate of Falco outputs. Each event source has its own rate limiter,
# ensuring that alerts from one source do not affect the throttling of others. # ensuring that alerts from one source do not affect the throttling of others.
@@ -302,6 +311,12 @@ outputs:
# trigger, possibly shadowing other rules. # trigger, possibly shadowing other rules.
# In case `all` is used as value, rules still trigger in the order they were # In case `all` is used as value, rules still trigger in the order they were
# defined. # defined.
#
# Effectively, with this setting, it is now possible to apply multiple rules that match
# the same event type. This eliminates concerns about rule prioritization based on the
# "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.
rule_matching: first rule_matching: first
@@ -359,6 +374,14 @@ http_output:
# Path to a folder that will be used as the CA certificate store. CA certificate need to be # Path to a folder that will be used as the CA certificate store. CA certificate need to be
# stored as indivitual PEM files in this directory. # stored as indivitual PEM files in this directory.
ca_path: "/etc/ssl/certs" ca_path: "/etc/ssl/certs"
# Tell Falco to use mTLS
mtls: false
# Path to the client cert.
client_cert: "/etc/ssl/certs/client.crt"
# Path to the client key.
client_key: "/etc/ssl/certs/client.key"
# Whether to echo server answers to stdout
echo: false
# [Stable] `program_output` # [Stable] `program_output`
# #
@@ -510,8 +533,8 @@ log_level: info
# operational logs. It allows you to specify the desired log level for the `libs` # operational logs. It allows you to specify the desired log level for the `libs`
# library specifically, providing more granular control over the logging # library specifically, providing more granular control over the logging
# behavior of the underlying components used by Falco. Only logs of a certain # behavior of the underlying components used by Falco. Only logs of a certain
# severity level or higher will be emitted. Supported levels: "emergency", # severity level or higher will be emitted. Supported levels: "fatal",
# "alert", "critical", "error", "warning", "notice", "info", "debug". It is not # "critical", "error", "warning", "notice", "info", "debug", "trace". It is not
# recommended for production use. # recommended for production use.
libs_logger: libs_logger:
enabled: false enabled: false
@@ -613,7 +636,7 @@ syscall_event_drops:
max_burst: 1 max_burst: 1
simulate_drops: false simulate_drops: false
# [Experimental] `metrics` # [Stable] `metrics`
# #
# Generates "Falco internal: metrics snapshot" rule output when `priority=info` at minimum # Generates "Falco internal: metrics snapshot" rule output when `priority=info` at minimum
# By selecting `output_file`, equivalent JSON output will be appended to a file. # By selecting `output_file`, equivalent JSON output will be appended to a file.
@@ -736,6 +759,8 @@ syscall_event_drops:
metrics: metrics:
enabled: false enabled: false
interval: 1h 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.
output_rule: true output_rule: true
# output_file: /tmp/falco_stats.jsonl # output_file: /tmp/falco_stats.jsonl
resource_utilization_enabled: true resource_utilization_enabled: true
@@ -811,7 +836,7 @@ syscall_buf_size_preset: 4
# visibility into the system. # visibility into the system.
syscall_drop_failed_exit: false syscall_drop_failed_exit: false
# [Experimental] `base_syscalls`, use with caution, read carefully # [Stable] `base_syscalls`, use with caution, read carefully
# #
# --- [Description] # --- [Description]
# #

View File

@@ -15,6 +15,7 @@
# limitations under the License. # limitations under the License.
# #
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
# Systemd # Systemd
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/scripts/systemd) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/scripts/systemd)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod-inject.service" configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod-inject.service"
@@ -40,15 +41,16 @@ configure_file(rpm/postinstall.in rpm/postinstall COPYONLY)
configure_file(rpm/postuninstall.in rpm/postuninstall COPYONLY) configure_file(rpm/postuninstall.in rpm/postuninstall COPYONLY)
configure_file(rpm/preuninstall.in rpm/preuninstall COPYONLY) configure_file(rpm/preuninstall.in rpm/preuninstall COPYONLY)
# driver loader
configure_file(falco-driver-loader falco-driver-loader @ONLY) configure_file(falco-driver-loader falco-driver-loader @ONLY)
install(PROGRAMS ${PROJECT_BINARY_DIR}/scripts/falco-driver-loader
DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}")
endif()
# Install Falcoctl config file # Install Falcoctl config file
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT MUSL_OPTIMIZED_BUILD)
if(NOT DEFINED FALCOCTL_ETC_DIR) if(NOT DEFINED FALCOCTL_ETC_DIR)
set(FALCOCTL_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falcoctl") set(FALCOCTL_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falcoctl")
endif() endif()
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/falcoctl/falcoctl.yaml DESTINATION "${FALCOCTL_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}") install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/falcoctl/falcoctl.yaml DESTINATION "${FALCOCTL_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
install(PROGRAMS ${PROJECT_BINARY_DIR}/scripts/falco-driver-loader
DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}")
endif() endif()

View File

@@ -117,7 +117,9 @@ get_target_id() {
# Older RHEL distros # Older RHEL distros
OS_ID=rhel OS_ID=rhel
else else
return 1 # No target id can be determinand
TARGET_ID="undetermined"
return
fi fi
# Overwrite the OS_ID if /etc/VERSION file is present. # Overwrite the OS_ID if /etc/VERSION file is present.
@@ -163,7 +165,7 @@ get_target_id() {
then then
ARCH_extra="-${BASH_REMATCH[1]}${BASH_REMATCH[2]}" ARCH_extra="-${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
fi fi
if [[ $(uname -v) =~ ([0-9]+\.[0-9]+\.[0-9]+\-[0-9]+) ]]; if [[ ${DRIVER_KERNEL_VERSION} =~ ([0-9]+\.[0-9]+\.[0-9]+\-[0-9]+) ]];
then then
KERNEL_RELEASE="${BASH_REMATCH[1]}${ARCH_extra}" KERNEL_RELEASE="${BASH_REMATCH[1]}${ARCH_extra}"
fi fi
@@ -187,9 +189,9 @@ get_target_id() {
# from the following `uname -v` result # from the following `uname -v` result
# `#26~22.04.1-Ubuntu SMP Mon Apr 24 01:58:15 UTC 2023` # `#26~22.04.1-Ubuntu SMP Mon Apr 24 01:58:15 UTC 2023`
# we obtain the kernelversion`26~22.04.1` # we obtain the kernelversion`26~22.04.1`
if [[ $(uname -v) =~ (^\#[0-9]+\~[^-]*-Ubuntu .*$) ]]; if [[ ${DRIVER_KERNEL_VERSION} =~ (^\#[0-9]+\~[^-]*-Ubuntu .*$) ]];
then then
KERNEL_VERSION=$(uname -v | sed 's/#\([^-\\ ]*\).*/\1/g') KERNEL_VERSION=$(echo "${DRIVER_KERNEL_VERSION}" | sed 's/#\([^-\\ ]*\).*/\1/g')
fi fi
;; ;;
("flatcar") ("flatcar")
@@ -227,7 +229,6 @@ get_target_id() {
TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]') TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]')
;; ;;
esac esac
return 0
} }
flatcar_relocate_tools() { flatcar_relocate_tools() {
@@ -258,7 +259,7 @@ flatcar_relocate_tools() {
load_kernel_module_compile() { load_kernel_module_compile() {
# Skip dkms on UEK hosts because it will always fail # Skip dkms on UEK hosts because it will always fail
if [[ $(uname -r) == *uek* ]]; then if [[ ${DRIVER_KERNEL_RELEASE} == *uek* ]]; then
>&2 echo "Skipping because the dkms install always fail (on UEK hosts)" >&2 echo "Skipping because the dkms install always fail (on UEK hosts)"
return return
fi fi
@@ -269,7 +270,7 @@ load_kernel_module_compile() {
fi fi
if [ "${TARGET_ID}" == "flatcar" ]; then if [ "${TARGET_ID}" == "flatcar" ]; then
KERNEL_RELEASE=$(uname -r) KERNEL_RELEASE=${DRIVER_KERNEL_RELEASE}
echo "* Flatcar detected (version ${VERSION_ID}); relocating kernel tools" echo "* Flatcar detected (version ${VERSION_ID}); relocating kernel tools"
flatcar_relocate_tools flatcar_relocate_tools
fi fi
@@ -355,6 +356,20 @@ print_filename_components() {
echo " - kernel version: ${KERNEL_VERSION}" echo " - kernel version: ${KERNEL_VERSION}"
} }
print_as_env_vars() {
echo "ARCH=\"${ARCH}\""
echo "KERNEL_RELEASE=\"${KERNEL_RELEASE}\""
echo "KERNEL_VERSION=\"${KERNEL_VERSION}\""
echo "ENABLE_COMPILE=\"${ENABLE_COMPILE}\""
echo "ENABLE_DOWNLOAD=\"${ENABLE_DOWNLOAD}\""
echo "TARGET_ID=\"${TARGET_ID}\""
echo "DRIVER=\"${DRIVER}\""
echo "DRIVERS_REPO=\"${DRIVERS_REPO}\""
echo "DRIVER_VERSION=\"${DRIVER_VERSION}\""
echo "DRIVER_NAME=\"${DRIVER_NAME}\""
echo "FALCO_VERSION=\"${FALCO_VERSION}\""
}
clean_kernel_module() { clean_kernel_module() {
echo echo
echo "================ Cleaning phase ================" echo "================ Cleaning phase ================"
@@ -528,7 +543,7 @@ load_bpf_probe_compile() {
MINIKUBE_VERSION="$(cat "${HOST_ROOT}/etc/VERSION")" MINIKUBE_VERSION="$(cat "${HOST_ROOT}/etc/VERSION")"
echo "* Minikube detected (${MINIKUBE_VERSION}), using linux kernel sources for minikube kernel" echo "* Minikube detected (${MINIKUBE_VERSION}), using linux kernel sources for minikube kernel"
local kernel_version local kernel_version
kernel_version=$(uname -r) kernel_version=${DRIVER_KERNEL_RELEASE}
local -r kernel_version_major=$(echo "${kernel_version}" | cut -d. -f1) local -r kernel_version_major=$(echo "${kernel_version}" | cut -d. -f1)
local -r kernel_version_minor=$(echo "${kernel_version}" | cut -d. -f2) local -r kernel_version_minor=$(echo "${kernel_version}" | cut -d. -f2)
local -r kernel_version_patch=$(echo "${kernel_version}" | cut -d. -f3) local -r kernel_version_patch=$(echo "${kernel_version}" | cut -d. -f3)
@@ -541,9 +556,9 @@ load_bpf_probe_compile() {
fi fi
if [ -n "${BPF_USE_LOCAL_KERNEL_SOURCES}" ]; then if [ -n "${BPF_USE_LOCAL_KERNEL_SOURCES}" ]; then
local -r kernel_version_major=$(uname -r | cut -d. -f1) local -r kernel_version_major=$(echo "${DRIVER_KERNEL_RELEASE}" | cut -d. -f1)
local -r kernel_version=$(uname -r | cut -d- -f1) local -r kernel_version=$(echo "${DRIVER_KERNEL_RELEASE}" | cut -d- -f1)
KERNEL_EXTRA_VERSION="-$(uname -r | cut -d- -f2)" KERNEL_EXTRA_VERSION="-$(echo "${DRIVER_KERNEL_RELEASE}" | cut -d- -f2)"
echo "* Using downloaded kernel sources for kernel version ${kernel_version}..." echo "* Using downloaded kernel sources for kernel version ${kernel_version}..."
@@ -666,13 +681,16 @@ print_usage() {
echo " --clean try to remove an already present driver installation" echo " --clean try to remove an already present driver installation"
echo " --compile try to compile the driver locally (default true)" echo " --compile try to compile the driver locally (default true)"
echo " --download try to download a prebuilt driver (default true)" echo " --download try to download a prebuilt driver (default true)"
echo " --source-only skip execution and allow sourcing in another script" echo " --source-only skip execution and allow sourcing in another script using `. falco-driver-loader`"
echo " --print-env skip execution and print env variables for other tools to consume"
echo "" echo ""
echo "Environment variables:" echo "Environment variables:"
echo " DRIVERS_REPO specify different URL(s) where to look for prebuilt Falco drivers (comma separated)" echo " DRIVERS_REPO specify different URL(s) where to look for prebuilt Falco drivers (comma separated)"
echo " DRIVER_NAME specify a different name for the driver" echo " DRIVER_NAME specify a different name for the driver"
echo " DRIVER_INSECURE_DOWNLOAD whether you want to allow insecure downloads or not" echo " DRIVER_INSECURE_DOWNLOAD whether you want to allow insecure downloads or not"
echo " DRIVER_CURL_OPTIONS specify additional options to be passed to curl command used to download Falco drivers" echo " DRIVER_CURL_OPTIONS specify additional options to be passed to curl command used to download Falco drivers"
echo " DRIVER_KERNEL_RELEASE specify the kernel release for which to download/build the driver in the same format used by 'uname -r' (e.g. '6.1.0-10-cloud-amd64')"
echo " DRIVER_KERNEL_VERSION specify the kernel version for which to download/build the driver in the same format used by 'uname -v' (e.g. '#1 SMP PREEMPT_DYNAMIC Debian 6.1.38-2 (2023-07-27)')"
echo "" echo ""
echo "Versions:" echo "Versions:"
echo " Falco version ${FALCO_VERSION}" echo " Falco version ${FALCO_VERSION}"
@@ -682,13 +700,16 @@ print_usage() {
ARCH=$(uname -m) ARCH=$(uname -m)
KERNEL_RELEASE=$(uname -r) DRIVER_KERNEL_RELEASE=${DRIVER_KERNEL_RELEASE:-$(uname -r)}
KERNEL_RELEASE=${DRIVER_KERNEL_RELEASE}
if ! hash sed > /dev/null 2>&1; then if ! hash sed > /dev/null 2>&1; then
>&2 echo "This program requires sed" >&2 echo "This program requires sed"
exit 1 exit 1
fi fi
KERNEL_VERSION=$(uname -v | sed 's/#\([[:digit:]]\+\).*/\1/')
DRIVER_KERNEL_VERSION=${DRIVER_KERNEL_VERSION:-$(uname -v)}
KERNEL_VERSION=$(echo "${DRIVER_KERNEL_VERSION}" | sed 's/#\([[:digit:]]\+\).*/\1/')
DRIVERS_REPO=${DRIVERS_REPO:-"@DRIVERS_REPO@"} DRIVERS_REPO=${DRIVERS_REPO:-"@DRIVERS_REPO@"}
@@ -709,7 +730,8 @@ DRIVER_VERSION=${DRIVER_VERSION:-"@DRIVER_VERSION@"}
DRIVER_NAME=${DRIVER_NAME:-"@DRIVER_NAME@"} DRIVER_NAME=${DRIVER_NAME:-"@DRIVER_NAME@"}
FALCO_VERSION="@FALCO_VERSION@" FALCO_VERSION="@FALCO_VERSION@"
TARGET_ID="placeholder" # when no target id can be fetched, we try to build the driver from source anyway, using a placeholder name TARGET_ID=
get_target_id
DRIVER="module" DRIVER="module"
if [ -v FALCO_BPF_PROBE ]; then if [ -v FALCO_BPF_PROBE ]; then
@@ -724,6 +746,7 @@ ENABLE_DOWNLOAD=
clean= clean=
has_args= has_args=
has_opts= has_opts=
print_env=
source_only= source_only=
while test $# -gt 0; do while test $# -gt 0; do
case "$1" in case "$1" in
@@ -760,6 +783,10 @@ while test $# -gt 0; do
source_only="true" source_only="true"
shift shift
;; ;;
--print-env)
print_env="true"
shift
;;
--*) --*)
>&2 echo "Unknown option: $1" >&2 echo "Unknown option: $1"
print_usage print_usage
@@ -778,7 +805,16 @@ if [ -z "$has_opts" ]; then
ENABLE_DOWNLOAD="yes" ENABLE_DOWNLOAD="yes"
fi fi
if [ -z "$source_only" ]; then if [ -n "$source_only" ]; then
# Return or exit, depending if we've been sourced.
(return 0 2>/dev/null) && return || exit 0
fi
if [ -n "$print_env" ]; then
print_as_env_vars
exit 0
fi
echo "* Running falco-driver-loader for: falco version=${FALCO_VERSION}, driver version=${DRIVER_VERSION}, arch=${ARCH}, kernel release=${KERNEL_RELEASE}, kernel version=${KERNEL_VERSION}" echo "* Running falco-driver-loader for: falco version=${FALCO_VERSION}, driver version=${DRIVER_VERSION}, arch=${ARCH}, kernel release=${KERNEL_RELEASE}, kernel version=${KERNEL_VERSION}"
if [ "$(id -u)" != 0 ]; then if [ "$(id -u)" != 0 ]; then
@@ -786,9 +822,7 @@ if [ -z "$source_only" ]; then
exit 1 exit 1
fi fi
get_target_id if [ "$TARGET_ID" = "undetermined" ]; then
res=$?
if [ $res != 0 ]; then
if [ -n "$ENABLE_COMPILE" ]; then if [ -n "$ENABLE_COMPILE" ]; then
ENABLE_DOWNLOAD= ENABLE_DOWNLOAD=
>&2 echo "Detected an unsupported target system, please get in touch with the Falco community. Trying to compile anyway." >&2 echo "Detected an unsupported target system, please get in touch with the Falco community. Trying to compile anyway."
@@ -829,4 +863,3 @@ if [ -z "$source_only" ]; then
;; ;;
esac esac
fi fi
fi

View File

@@ -8,7 +8,8 @@ Wants=falcoctl-artifact-follow.service
Type=simple Type=simple
User=root User=root
Environment=FALCO_BPF_PROBE= Environment=FALCO_BPF_PROBE=
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid ExecStart=/usr/bin/falco
ExecReload=kill -1 $MAINPID
UMask=0077 UMask=0077
TimeoutSec=30 TimeoutSec=30
RestartSec=15s RestartSec=15s

View File

@@ -7,7 +7,8 @@ Wants=falcoctl-artifact-follow.service
[Service] [Service]
Type=simple Type=simple
User=%u User=%u
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid ExecStart=/usr/bin/falco
ExecReload=kill -1 $MAINPID
UMask=0077 UMask=0077
TimeoutSec=30 TimeoutSec=30
RestartSec=15s RestartSec=15s

View File

@@ -9,7 +9,8 @@ Wants=falcoctl-artifact-follow.service
[Service] [Service]
Type=simple Type=simple
User=root User=root
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid ExecStart=/usr/bin/falco
ExecReload=kill -1 $MAINPID
UMask=0077 UMask=0077
TimeoutSec=30 TimeoutSec=30
RestartSec=15s RestartSec=15s

View File

@@ -7,7 +7,8 @@ Wants=falcoctl-artifact-follow.service
[Service] [Service]
Type=simple Type=simple
User=root User=root
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid --modern-bpf ExecStart=/usr/bin/falco --modern-bpf
ExecReload=kill -1 $MAINPID
UMask=0077 UMask=0077
TimeoutSec=30 TimeoutSec=30
RestartSec=15s RestartSec=15s

View File

@@ -28,9 +28,17 @@ file(GLOB_RECURSE FALCO_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/falco/*.cpp)
set(FALCO_UNIT_TESTS_SOURCES set(FALCO_UNIT_TESTS_SOURCES
"${ENGINE_TESTS}" "${ENGINE_TESTS}"
"${FALCO_TESTS}" falco/test_configuration.cpp
falco/app/actions/test_select_event_sources.cpp
) )
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
list(APPEND FALCO_UNIT_TESTS_SOURCES
falco/test_atomic_signal_handler.cpp
falco/app/actions/test_configure_interesting_sets.cpp
falco/app/actions/test_configure_syscall_buffer_num.cpp)
endif()
set(FALCO_UNIT_TESTS_INCLUDES set(FALCO_UNIT_TESTS_INCLUDES
PRIVATE PRIVATE
${CMAKE_SOURCE_DIR}/userspace ${CMAKE_SOURCE_DIR}/userspace
@@ -62,3 +70,10 @@ add_executable(falco_unit_tests ${FALCO_UNIT_TESTS_SOURCES})
target_include_directories(falco_unit_tests ${FALCO_UNIT_TESTS_INCLUDES}) target_include_directories(falco_unit_tests ${FALCO_UNIT_TESTS_INCLUDES})
target_link_libraries(falco_unit_tests ${FALCO_UNIT_TESTS_LIBRARIES}) target_link_libraries(falco_unit_tests ${FALCO_UNIT_TESTS_LIBRARIES})
add_dependencies(falco_unit_tests ${FALCO_UNIT_TESTS_DEPENDENCIES}) add_dependencies(falco_unit_tests ${FALCO_UNIT_TESTS_DEPENDENCIES})
if (EMSCRIPTEN)
target_compile_options(falco_unit_tests PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
target_link_options(falco_unit_tests PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
target_link_options(falco_unit_tests PRIVATE "-sALLOW_MEMORY_GROWTH=1")
target_link_options(falco_unit_tests PRIVATE "-sEXPORTED_FUNCTIONS=['_main','_htons','_ntohs']")
endif()

View File

@@ -46,7 +46,7 @@ TEST(FalcoUtils, parse_prometheus_interval)
ASSERT_EQ(falco::utils::parse_prometheus_interval("1h"), 3600000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1h"), 3600000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1d"), 86400000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1d"), 86400000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1w"), 604800000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1w"), 604800000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1y"), 31536000000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1y"), (unsigned long)31536000000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("300ms"), 300UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("300ms"), 300UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("255s"), 255000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("255s"), 255000UL);
@@ -57,14 +57,17 @@ TEST(FalcoUtils, parse_prometheus_interval)
/* Test matrix for concatenated time interval examples. */ /* Test matrix for concatenated time interval examples. */
ASSERT_EQ(falco::utils::parse_prometheus_interval("1h3m2s1ms"), 3600000UL + 3 * 60000UL + 2 * 1000UL + 1UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1h3m2s1ms"), 3600000UL + 3 * 60000UL + 2 * 1000UL + 1UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1y1w1d1h1m1s1ms"), 31536000000UL + 604800000UL + 86400000UL + 3600000UL + 60000UL + 1000UL + 1UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1y1w1d1h1m1s1ms"),(unsigned long) 31536000000UL + 604800000UL + 86400000UL + 3600000UL + 60000UL + 1000UL + 1UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("2h5m"), 2 * 3600000UL + 5 * 60000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("2h5m"), 2 * 3600000UL + 5 * 60000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("2h 5m"), 2 * 3600000UL + 5 * 60000UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("2h 5m"), 2 * 3600000UL + 5 * 60000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("200"), 200UL);
/* Invalid, non prometheus compliant time ordering will result in 0ms. */ /* Invalid, non prometheus compliant time ordering will result in 0ms. */
ASSERT_EQ(falco::utils::parse_prometheus_interval("1ms1y"), 0UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1ms1y"), 0UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1t1y"), 0UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1t1y"), 0UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1t"), 0UL); ASSERT_EQ(falco::utils::parse_prometheus_interval("1t"), 0UL);
/* Deprecated option to pass a numeric value in ms without prometheus compliant time unit,
* will result in 0ms and as a result the end user will receive an error warning.
*/
ASSERT_EQ(falco::utils::parse_prometheus_interval("200"), 0UL);
} }

View File

@@ -29,6 +29,10 @@ set(FALCO_ENGINE_SOURCE_FILES
add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES}) add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES})
if (EMSCRIPTEN)
target_compile_options(falco_engine PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
endif()
add_dependencies(falco_engine yamlcpp njson) add_dependencies(falco_engine yamlcpp njson)
if(MINIMAL_BUILD) if(MINIMAL_BUILD)

View File

@@ -246,7 +246,13 @@ std::unique_ptr<load_result> falco_engine::load_rules_file(const std::string &ru
res->add_error(load_result::LOAD_ERR_FILE_READ, e.what(), ctx); res->add_error(load_result::LOAD_ERR_FILE_READ, e.what(), ctx);
// Old gcc versions (e.g. 4.8.3) won't allow move elision but newer versions
// (e.g. 10.2.1) would complain about the redundant move.
#if __GNUC__ > 4
return res; return res;
#else
return std::move(res);
#endif
} }
return load_rules(rules_content, rules_filename); return load_rules(rules_content, rules_filename);
@@ -567,7 +573,7 @@ void falco_engine::describe_rule(std::string *rule, bool json) const
{ {
// build json information for just the specified rule // build json information for just the specified rule
auto ri = m_rule_collector.rules().at(*rule); auto ri = m_rule_collector.rules().at(*rule);
if(ri == nullptr) if(ri == nullptr || ri->unknown_source)
{ {
throw falco_exception("Rule \"" + *rule + "\" is not loaded"); throw falco_exception("Rule \"" + *rule + "\" is not loaded");
} }

View File

@@ -15,7 +15,7 @@ limitations under the License.
*/ */
// The version of this Falco engine. // The version of this Falco engine.
#define FALCO_ENGINE_VERSION (22) #define FALCO_ENGINE_VERSION (25)
// This is the result of running the following command: // This is the result of running the following command:
// FALCO="falco -c ./falco.yaml" // FALCO="falco -c ./falco.yaml"
@@ -23,4 +23,4 @@ limitations under the License.
// It represents the fields supported by this version of Falco, // It represents the fields supported by this version of Falco,
// the event types, and the underlying driverevent schema. It's used to // the event types, and the underlying driverevent schema. It's used to
// detetect changes in engine version in our CI jobs. // detetect changes in engine version in our CI jobs.
#define FALCO_ENGINE_CHECKSUM "41dc03aebd3dd09e1aaaa1bb25055b65902c7c61c180cb9486d1d9850d18d67b" #define FALCO_ENGINE_CHECKSUM "41b5dc700216b243d294b40c46264d4e89d0ee00098fdc1c21bb4b1e7639da06"

View File

@@ -62,7 +62,7 @@ static const std::string warning_codes[] = {
"LOAD_UNKNOWN_SOURCE", "LOAD_UNKNOWN_SOURCE",
"LOAD_UNSAFE_NA_CHECK", "LOAD_UNSAFE_NA_CHECK",
"LOAD_NO_EVTTYPE", "LOAD_NO_EVTTYPE",
"LOAD_UNKNOWN_FIELD", "LOAD_UNKNOWN_FILTER",
"LOAD_UNUSED_MACRO", "LOAD_UNUSED_MACRO",
"LOAD_UNUSED_LIST", "LOAD_UNUSED_LIST",
"LOAD_UNKNOWN_ITEM" "LOAD_UNKNOWN_ITEM"
@@ -77,7 +77,7 @@ static const std::string warning_strings[] = {
"Unknown event source", "Unknown event source",
"Unsafe <NA> comparison in condition", "Unsafe <NA> comparison in condition",
"Condition has no event-type restriction", "Condition has no event-type restriction",
"Unknown field in condition", "Unknown field or event-type in condition or output",
"Unused macro", "Unused macro",
"Unused list", "Unused list",
"Unknown rules file item" "Unknown rules file item"
@@ -92,7 +92,7 @@ static const std::string warning_descs[] = {
"A rule has a unknown event source. This can occur when reading rules content without having a corresponding plugin loaded, etc. The rule will be silently ignored.", "A rule has a unknown event source. This can occur when reading rules content without having a corresponding plugin loaded, etc. The rule will be silently ignored.",
"Comparing a field value with <NA> is unsafe and can lead to unpredictable behavior of the rule condition. If you need to check for the existence of a field, consider using the 'exists' operator instead.", "Comparing a field value with <NA> is unsafe and can lead to unpredictable behavior of the rule condition. If you need to check for the existence of a field, consider using the 'exists' operator instead.",
"A rule condition matches too many evt.type values. This has a significant performance penalty. Make the condition more specific by adding an evt.type field or further restricting the number of evt.type values in the condition.", "A rule condition matches too many evt.type values. This has a significant performance penalty. Make the condition more specific by adding an evt.type field or further restricting the number of evt.type values in the condition.",
"A rule condition refers to a field that does not exist. This is normally an error, but if a rule has a skip-if-unknown-filter property, the error is downgraded to a warning.", "A rule condition or output refers to a field or evt.type that does not exist. This is normally an error, but if a rule has a skip-if-unknown-filter property, the error is downgraded to a warning.",
"A macro is defined in the rules content but is not used by any other macro or rule.", "A 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.", "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." "An unknown top-level object is in the rules content. It will be ignored."

View File

@@ -50,7 +50,7 @@ public:
LOAD_UNKNOWN_SOURCE = 0, LOAD_UNKNOWN_SOURCE = 0,
LOAD_UNSAFE_NA_CHECK, LOAD_UNSAFE_NA_CHECK,
LOAD_NO_EVTTYPE, LOAD_NO_EVTTYPE,
LOAD_UNKNOWN_FIELD, LOAD_UNKNOWN_FILTER,
LOAD_UNUSED_MACRO, LOAD_UNUSED_MACRO,
LOAD_UNUSED_LIST, LOAD_UNUSED_LIST,
LOAD_UNKNOWN_ITEM LOAD_UNKNOWN_ITEM

View File

@@ -61,17 +61,6 @@ uint64_t parse_prometheus_interval(std::string interval_str)
interval_str.erase(remove_if(interval_str.begin(), interval_str.end(), isspace), interval_str.end()); interval_str.erase(remove_if(interval_str.begin(), interval_str.end(), isspace), interval_str.end());
if(!interval_str.empty()) if(!interval_str.empty())
{
/* Option 1: Passing interval directly in ms. Will be deprecated in the future. */
if(std::all_of(interval_str.begin(), interval_str.end(), ::isdigit))
{
/* todo: deprecate for Falco 0.36. */
interval = std::stoull(interval_str, nullptr, 0);
}
/* Option 2: Passing a Prometheus compliant time duration.
* https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations
*/
else
{ {
re2::StringPiece input(interval_str); re2::StringPiece input(interval_str);
std::string args[14]; std::string args[14];
@@ -122,7 +111,6 @@ uint64_t parse_prometheus_interval(std::string interval_str)
} }
} }
} }
}
return interval; return interval;
} }

View File

@@ -16,7 +16,6 @@ limitations under the License.
#pragma once #pragma once
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>

View File

@@ -547,8 +547,8 @@ rule_loader::rule_exception_info::rule_exception_info(context &ctx)
rule_loader::rule_info::rule_info(context &ctx) rule_loader::rule_info::rule_info(context &ctx)
: ctx(ctx), cond_ctx(ctx), output_ctx(ctx), index(0), visibility(0), : ctx(ctx), cond_ctx(ctx), output_ctx(ctx), index(0), visibility(0),
priority(falco_common::PRIORITY_DEBUG), enabled(true), unknown_source(false), priority(falco_common::PRIORITY_DEBUG),
warn_evttypes(true), skip_if_unknown_filter(false) enabled(true), warn_evttypes(true), skip_if_unknown_filter(false)
{ {
} }

View File

@@ -449,6 +449,7 @@ namespace rule_loader
context output_ctx; context output_ctx;
size_t index; size_t index;
size_t visibility; size_t visibility;
bool unknown_source;
std::string name; std::string name;
std::string cond; std::string cond;
std::string source; std::string source;

View File

@@ -54,7 +54,7 @@ static inline void append_info(T* prev, T& info, uint32_t id)
} }
static void validate_exception_info( static void validate_exception_info(
const falco_source& source, const falco_source* source,
rule_loader::rule_exception_info &ex) rule_loader::rule_exception_info &ex)
{ {
if (ex.fields.is_list) if (ex.fields.is_list)
@@ -76,13 +76,16 @@ static void validate_exception_info(
std::string("'") + v.item + "' is not a supported comparison operator", std::string("'") + v.item + "' is not a supported comparison operator",
ex.ctx); ex.ctx);
} }
if (source)
{
for (auto &v : ex.fields.items) for (auto &v : ex.fields.items)
{ {
THROW(!source.is_field_defined(v.item), THROW(!source->is_field_defined(v.item),
std::string("'") + v.item + "' is not a supported filter field", std::string("'") + v.item + "' is not a supported filter field",
ex.ctx); ex.ctx);
} }
} }
}
else else
{ {
if (!ex.comps.is_valid()) if (!ex.comps.is_valid())
@@ -96,11 +99,14 @@ static void validate_exception_info(
THROW((ex.comps.item != "in" && ex.comps.item != "pmatch" && ex.comps.item != "intersects"), THROW((ex.comps.item != "in" && ex.comps.item != "pmatch" && ex.comps.item != "intersects"),
"When fields is a single value, comps must be one of (in, pmatch, intersects)", "When fields is a single value, comps must be one of (in, pmatch, intersects)",
ex.ctx); ex.ctx);
THROW(!source.is_field_defined(ex.fields.item), if (source)
{
THROW(!source->is_field_defined(ex.fields.item),
std::string("'") + ex.fields.item + "' is not a supported filter field", std::string("'") + ex.fields.item + "' is not a supported filter field",
ex.ctx); ex.ctx);
} }
} }
}
void rule_loader::collector::clear() void rule_loader::collector::clear()
{ {
@@ -200,26 +206,25 @@ void rule_loader::collector::append(configuration& cfg, macro_info& info)
void rule_loader::collector::define(configuration& cfg, rule_info& info) void rule_loader::collector::define(configuration& cfg, rule_info& info)
{ {
auto source = cfg.sources.at(info.source);
if (!source)
{
cfg.res->add_warning(falco::load_result::LOAD_UNKNOWN_SOURCE,
"Unknown source " + info.source + ", skipping",
info.ctx);
return;
}
auto prev = m_rule_infos.at(info.name); auto prev = m_rule_infos.at(info.name);
THROW(prev && prev->source != info.source, THROW(prev && prev->source != info.source,
"Rule has been re-defined with a different source", "Rule has been re-defined with a different source",
info.ctx); info.ctx);
auto source = cfg.sources.at(info.source);
if (!source)
{
info.unknown_source = true;
cfg.res->add_warning(falco::load_result::LOAD_UNKNOWN_SOURCE,
"Unknown source " + info.source + ", skipping",
info.ctx);
}
for (auto &ex : info.exceptions) for (auto &ex : info.exceptions)
{ {
THROW(!ex.fields.is_valid(), THROW(!ex.fields.is_valid(),
"Rule exception item must have fields property with a list of fields", "Rule exception item must have fields property with a list of fields",
ex.ctx); ex.ctx);
validate_exception_info(*source, ex); validate_exception_info(source, ex);
} }
define_info(m_rule_infos, info, m_cur_index++); define_info(m_rule_infos, info, m_cur_index++);
@@ -236,11 +241,17 @@ void rule_loader::collector::append(configuration& cfg, rule_info& info)
"Appended rule must have exceptions or condition property", "Appended rule must have exceptions or condition property",
info.ctx); info.ctx);
auto source = cfg.sources.at(prev->source); // note: source can be nullptr in case we've collected a
// note: this is not supposed to happen // rule for which the source is unknown
falco_source* source = nullptr;
if (!prev->unknown_source)
{
// note: if the source is not unknown, this should not return nullptr
source = cfg.sources.at(prev->source);
THROW(!source, THROW(!source,
std::string("Unknown source ") + prev->source, std::string("Unknown source ") + prev->source,
info.ctx); info.ctx);
}
if (!info.cond.empty()) if (!info.cond.empty())
{ {
@@ -261,7 +272,7 @@ void rule_loader::collector::append(configuration& cfg, rule_info& info)
THROW(ex.values.empty(), THROW(ex.values.empty(),
"Rule exception must have values property with a list of values", "Rule exception must have values property with a list of values",
ex.ctx); ex.ctx);
validate_exception_info(*source, ex); validate_exception_info(source, ex);
prev->exceptions.push_back(ex); prev->exceptions.push_back(ex);
} }
else else

View File

@@ -375,6 +375,12 @@ void rule_loader::compiler::compile_macros_infos(
} }
} }
static bool err_is_unknown_type_or_field(const std::string& err)
{
return err.find("nonexistent field") != std::string::npos
|| err.find("invalid formatting token") != std::string::npos
|| err.find("unknown event type") != std::string::npos;
}
void rule_loader::compiler::compile_rule_infos( void rule_loader::compiler::compile_rule_infos(
configuration& cfg, configuration& cfg,
@@ -388,17 +394,22 @@ void rule_loader::compiler::compile_rule_infos(
filter_warning_resolver warn_resolver; filter_warning_resolver warn_resolver;
for (auto &r : col.rules()) for (auto &r : col.rules())
{ {
// skip the rule if it has an unknown source
if (r.unknown_source)
{
continue;
}
// skip the rule if below the minimum priority // skip the rule if below the minimum priority
if (r.priority > cfg.min_priority) if (r.priority > cfg.min_priority)
{ {
continue; continue;
} }
// note: this should not be nullptr if the source is not unknown
auto source = cfg.sources.at(r.source); auto source = cfg.sources.at(r.source);
// note: this is not supposed to happen
THROW(!source, THROW(!source,
std::string("Unknown source ") + r.source, std::string("Unknown source at compile-time") + r.source,
r.ctx); r.ctx);
// build filter AST by parsing the condition, building exceptions, // build filter AST by parsing the condition, building exceptions,
@@ -433,6 +444,14 @@ void rule_loader::compiler::compile_rule_infos(
if(!is_format_valid(*cfg.sources.at(r.source), rule.output, err)) if(!is_format_valid(*cfg.sources.at(r.source), rule.output, err))
{ {
if (err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter)
{
cfg.res->add_warning(
falco::load_result::load_result::LOAD_UNKNOWN_FILTER,
err,
r.output_ctx);
continue;
}
throw rule_load_exception( throw rule_load_exception(
falco::load_result::load_result::LOAD_ERR_COMPILE_OUTPUT, falco::load_result::load_result::LOAD_ERR_COMPILE_OUTPUT,
err, err,
@@ -463,26 +482,21 @@ void rule_loader::compiler::compile_rule_infos(
// skip_if_unknown_filter is true // skip_if_unknown_filter is true
std::string err = e.what(); std::string err = e.what();
if (err.find("nonexistent field") != std::string::npos && if (err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter)
r.skip_if_unknown_filter)
{ {
cfg.res->add_warning( cfg.res->add_warning(
falco::load_result::load_result::LOAD_UNKNOWN_FIELD, falco::load_result::load_result::LOAD_UNKNOWN_FILTER,
e.what(), err,
r.cond_ctx); r.cond_ctx);
continue;
} }
else
{
rule_loader::context ctx(compiler.get_pos(),
condition,
r.cond_ctx);
rule_loader::context ctx(compiler.get_pos(), condition, r.cond_ctx);
throw rule_loader::rule_load_exception( throw rule_loader::rule_load_exception(
falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION, falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION,
e.what(), err,
ctx); ctx);
} }
}
// By default rules are enabled/disabled for the default ruleset // By default rules are enabled/disabled for the default ruleset
if(r.enabled) if(r.enabled)

View File

@@ -22,7 +22,7 @@ set(
app/actions/helpers_inspector.cpp app/actions/helpers_inspector.cpp
app/actions/configure_interesting_sets.cpp app/actions/configure_interesting_sets.cpp
app/actions/create_signal_handlers.cpp app/actions/create_signal_handlers.cpp
app/actions/daemonize.cpp app/actions/pidfile.cpp
app/actions/init_falco_engine.cpp app/actions/init_falco_engine.cpp
app/actions/init_inspectors.cpp app/actions/init_inspectors.cpp
app/actions/init_clients.cpp app/actions/init_clients.cpp
@@ -75,7 +75,6 @@ list(APPEND FALCO_INCLUDE_DIRECTORIES "${FALCO_EXTRA_INCLUDE_DIRS}")
set( set(
FALCO_DEPENDENCIES FALCO_DEPENDENCIES
b64
cxxopts cxxopts
) )
@@ -90,7 +89,7 @@ if(USE_BUNDLED_DEPS)
list(APPEND FALCO_DEPENDENCIES yamlcpp) list(APPEND FALCO_DEPENDENCIES yamlcpp)
endif() endif()
if(NOT MINIMAL_BUILD) if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
list( list(
APPEND FALCO_SOURCES APPEND FALCO_SOURCES
outputs_grpc.cpp outputs_grpc.cpp
@@ -119,7 +118,7 @@ if(NOT MINIMAL_BUILD)
"${CARES_INCLUDE}" "${CARES_INCLUDE}"
) )
if(USE_BUNDLED_GRPC) if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND USE_BUNDLED_GRPC)
list(APPEND FALCO_DEPENDENCIES grpc) list(APPEND FALCO_DEPENDENCIES grpc)
list(APPEND FALCO_LIBRARIES "${GRPC_LIBRARIES}") list(APPEND FALCO_LIBRARIES "${GRPC_LIBRARIES}")
endif() endif()
@@ -143,6 +142,10 @@ add_library(
${FALCO_SOURCES} ${FALCO_SOURCES}
) )
if (EMSCRIPTEN)
target_compile_options(falco_application PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
endif()
add_dependencies(falco_application ${FALCO_DEPENDENCIES}) add_dependencies(falco_application ${FALCO_DEPENDENCIES})
target_link_libraries( target_link_libraries(
@@ -161,7 +164,17 @@ add_dependencies(falco falco_application ${FALCO_DEPENDENCIES})
target_link_libraries(falco falco_application ${FALCO_LIBRARIES}) target_link_libraries(falco falco_application ${FALCO_LIBRARIES})
target_include_directories(falco PUBLIC ${FALCO_INCLUDE_DIRECTORIES}) target_include_directories(falco PUBLIC ${FALCO_INCLUDE_DIRECTORIES})
if(NOT MINIMAL_BUILD) if (EMSCRIPTEN)
target_compile_options(falco PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
target_link_options(falco PRIVATE "-sALLOW_MEMORY_GROWTH=1")
target_link_options(falco PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
target_link_options(falco PRIVATE "-sMODULARIZE=1")
target_link_options(falco PRIVATE "-sEXPORT_ES6=1")
target_link_options(falco PRIVATE "-sEXPORTED_RUNTIME_METHODS=['FS', 'callMain']")
target_link_options(falco PRIVATE "-sEXPORTED_FUNCTIONS=['_main','_htons','_ntohs']")
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
add_custom_command( add_custom_command(
OUTPUT OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc ${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
@@ -200,4 +213,12 @@ if(MUSL_OPTIMIZED_BUILD AND CMAKE_BUILD_TYPE STREQUAL "release")
) )
endif() endif()
if (NOT EMSCRIPTEN)
install(TARGETS falco RUNTIME DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}") install(TARGETS falco RUNTIME DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}")
else()
install(FILES
"$<TARGET_FILE_DIR:falco>/falco.js"
"$<TARGET_FILE_DIR:falco>/falco.wasm"
DESTINATION ${FALCO_BIN_DIR}
COMPONENT "${FALCO_COMPONENT_NAME}")
endif()

View File

@@ -28,7 +28,7 @@ falco::app::run_result configure_syscall_buffer_size(falco::app::state& s);
falco::app::run_result configure_syscall_buffer_num(falco::app::state& s); falco::app::run_result configure_syscall_buffer_num(falco::app::state& s);
falco::app::run_result create_requested_paths(falco::app::state& s); falco::app::run_result create_requested_paths(falco::app::state& s);
falco::app::run_result create_signal_handlers(falco::app::state& s); falco::app::run_result create_signal_handlers(falco::app::state& s);
falco::app::run_result daemonize(falco::app::state& s); falco::app::run_result pidfile(falco::app::state& s);
falco::app::run_result init_clients(falco::app::state& s); falco::app::run_result init_clients(falco::app::state& s);
falco::app::run_result init_falco_engine(falco::app::state& s); falco::app::run_result init_falco_engine(falco::app::state& s);
falco::app::run_result init_inspectors(falco::app::state& s); falco::app::run_result init_inspectors(falco::app::state& s);

View File

@@ -214,6 +214,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
falco::app::run_result falco::app::actions::configure_interesting_sets(falco::app::state& s) falco::app::run_result falco::app::actions::configure_interesting_sets(falco::app::state& s)
{ {
#ifdef __linux__
if (s.engine == nullptr || s.config == nullptr) if (s.engine == nullptr || s.config == nullptr)
{ {
return run_result::fatal("Broken 'configure_interesting_sets' preconditions: engine and config must be non-null"); return run_result::fatal("Broken 'configure_interesting_sets' preconditions: engine and config must be non-null");
@@ -232,5 +233,7 @@ falco::app::run_result falco::app::actions::configure_interesting_sets(falco::ap
auto rules_sc_set = s.engine->sc_codes_for_ruleset(falco_common::syscall_source); auto rules_sc_set = s.engine->sc_codes_for_ruleset(falco_common::syscall_source);
select_event_set(s, rules_sc_set); select_event_set(s, rules_sc_set);
check_for_rules_unsupported_events(s, rules_sc_set); check_for_rules_unsupported_events(s, rules_sc_set);
#endif
return run_result::ok(); return run_result::ok();
} }

View File

@@ -21,6 +21,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco::app::state& s) falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco::app::state& s)
{ {
#ifdef __linux__
if(!s.options.modern_bpf) if(!s.options.modern_bpf)
{ {
return run_result::ok(); return run_result::ok();
@@ -37,6 +38,6 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco::
falco_logger::log(LOG_WARNING, "you required a buffer every '" + std::to_string(s.config->m_cpus_for_each_syscall_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n"); falco_logger::log(LOG_WARNING, "you required a buffer every '" + std::to_string(s.config->m_cpus_for_each_syscall_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n");
s.config->m_cpus_for_each_syscall_buffer = online_cpus; s.config->m_cpus_for_each_syscall_buffer = online_cpus;
} }
#endif
return run_result::ok(); return run_result::ok();
} }

View File

@@ -26,6 +26,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco::app::state& s) falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco::app::state& s)
{ {
#ifdef __linux__
/* We don't need to compute the syscall buffer dimension if we are in capture mode or if the /* We don't need to compute the syscall buffer dimension if we are in capture mode or if the
* the syscall source is not enabled. * the syscall source is not enabled.
*/ */
@@ -71,5 +72,7 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco:
s.syscall_buffer_bytes_size = chosen_size; s.syscall_buffer_bytes_size = chosen_size;
falco_logger::log(LOG_INFO, "The chosen syscall buffer dimension is: " + std::to_string(chosen_size) + " bytes (" + std::to_string(chosen_size / (uint64_t)(1024 * 1024)) + " MBs)\n"); falco_logger::log(LOG_INFO, "The chosen syscall buffer dimension is: " + std::to_string(chosen_size) + " bytes (" + std::to_string(chosen_size / (uint64_t)(1024 * 1024)) + " MBs)\n");
#endif // __linux__
return run_result::ok(); return run_result::ok();
} }

View File

@@ -20,7 +20,9 @@ limitations under the License.
#include "../app.h" #include "../app.h"
#include "../signals.h" #include "../signals.h"
#ifdef __linux__
#include <signal.h> #include <signal.h>
#endif // __linux__
using namespace falco::app; using namespace falco::app;
using namespace falco::app::actions; using namespace falco::app::actions;
@@ -48,6 +50,7 @@ static void restart_signal_handler(int signal)
bool create_handler(int sig, void (*func)(int), run_result &ret) bool create_handler(int sig, void (*func)(int), run_result &ret)
{ {
ret = run_result::ok(); ret = run_result::ok();
#ifdef __linux__
if(signal(sig, func) == SIG_ERR) if(signal(sig, func) == SIG_ERR)
{ {
char errbuf[1024]; char errbuf[1024];
@@ -61,12 +64,15 @@ bool create_handler(int sig, void (*func)(int), run_result &ret)
": " + ": " +
errbuf); errbuf);
} }
#endif
return ret.success; return ret.success;
} }
falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::state& s) falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::state& s)
{ {
auto ret = run_result::ok();
#ifdef __linux__
if (s.options.dry_run) if (s.options.dry_run)
{ {
falco_logger::log(LOG_DEBUG, "Skipping signal handlers creation in dry-run\n"); falco_logger::log(LOG_DEBUG, "Skipping signal handlers creation in dry-run\n");
@@ -84,7 +90,6 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s
falco_logger::log(LOG_WARNING, "Bundled atomics implementation is not lock-free, signal handlers may be unstable\n"); falco_logger::log(LOG_WARNING, "Bundled atomics implementation is not lock-free, signal handlers may be unstable\n");
} }
run_result ret;
if(! create_handler(SIGINT, ::terminate_signal_handler, ret) || if(! create_handler(SIGINT, ::terminate_signal_handler, ret) ||
! create_handler(SIGTERM, ::terminate_signal_handler, ret) || ! create_handler(SIGTERM, ::terminate_signal_handler, ret) ||
! create_handler(SIGUSR1, ::reopen_outputs_signal_handler, ret) || ! create_handler(SIGUSR1, ::reopen_outputs_signal_handler, ret) ||
@@ -146,11 +151,14 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s
{ {
s_restarter = s.restarter; s_restarter = s.restarter;
} }
#endif
return ret; return ret;
} }
falco::app::run_result falco::app::actions::unregister_signal_handlers(falco::app::state& s) falco::app::run_result falco::app::actions::unregister_signal_handlers(falco::app::state& s)
{ {
#ifdef __linux__
if (s.options.dry_run) if (s.options.dry_run)
{ {
falco_logger::log(LOG_DEBUG, "Skipping unregistering signal handlers in dry-run\n"); falco_logger::log(LOG_DEBUG, "Skipping unregistering signal handlers in dry-run\n");
@@ -171,5 +179,7 @@ falco::app::run_result falco::app::actions::unregister_signal_handlers(falco::ap
{ {
return ret; return ret;
} }
#endif // __linux__
return run_result::ok(); return run_result::ok();
} }

View File

@@ -1,87 +0,0 @@
/*
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
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 <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "actions.h"
using namespace falco::app;
using namespace falco::app::actions;
static bool s_daemonized = false;
falco::app::run_result falco::app::actions::daemonize(falco::app::state& s)
{
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping daemonizing in dry-run\n");
return run_result::ok();
}
// If daemonizing, do it here so any init errors will
// be returned in the foreground process.
if (s.options.daemon && !s_daemonized) {
pid_t pid, sid;
pid = fork();
if (pid < 0) {
// error
return run_result::fatal("Could not fork");
} else if (pid > 0) {
// parent. Write child pid to pidfile and exit
std::ofstream pidfile;
pidfile.open(s.options.pidfilename);
if (!pidfile.good())
{
falco_logger::log(LOG_ERR, "Could not write pid to pid file " + s.options.pidfilename + ". Exiting.\n");
exit(-1);
}
pidfile << pid;
pidfile.close();
exit(0);
}
// if here, child.
// Become own process group.
sid = setsid();
if (sid < 0) {
return run_result::fatal("Could not set session id");
}
// Set umask so no files are world anything or group writable.
umask(027);
// Change working directory to '/'
if ((chdir("/")) < 0) {
return run_result::fatal("Could not change working directory to '/'");
}
// Close stdin, stdout, stderr and reopen to /dev/null
close(0);
close(1);
close(2);
open("/dev/null", O_RDONLY);
open("/dev/null", O_RDWR);
open("/dev/null", O_RDWR);
s_daemonized = true;
}
return run_result::ok();
}

View File

@@ -91,7 +91,7 @@ falco::app::run_result falco::app::actions::open_live_inspector(
// //
// Falco uses a ptrace(2) based userspace implementation. // Falco uses a ptrace(2) based userspace implementation.
// Regardless of the implementation, the underlying method remains the same. // Regardless of the implementation, the underlying method remains the same.
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with udig\n"); falco_logger::log(LOG_WARNING, "The udig engine is deprecated and will be removed in Falco 0.37. Opening '" + source + "' source with udig\n");
inspector->open_udig(); inspector->open_udig();
} }
else if(s.is_gvisor_enabled()) /* gvisor engine. */ else if(s.is_gvisor_enabled()) /* gvisor engine. */

View File

@@ -21,7 +21,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::init_clients(falco::app::state& s) falco::app::run_result falco::app::actions::init_clients(falco::app::state& s)
{ {
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
// k8s is useful only if the syscall source is enabled // k8s is useful only if the syscall source is enabled
if (s.is_capture_mode() || !s.is_source_enabled(falco_common::syscall_source)) if (s.is_capture_mode() || !s.is_source_enabled(falco_common::syscall_source))
{ {

View File

@@ -22,27 +22,32 @@ using namespace falco::app::actions;
void configure_output_format(falco::app::state& s) void configure_output_format(falco::app::state& s)
{ {
// See https://falco.org/docs/rules/style-guide/
const std::string container_info = "container_id=%container.id container_image=%container.image.repository container_image_tag=%container.image.tag container_name=%container.name";
const std::string k8s_info = "k8s_ns=%k8s.ns.name k8s_pod_name=%k8s.pod.name";
const std::string gvisor_info = "vpid=%proc.vpid vtid=%thread.vtid";
std::string output_format; std::string output_format;
bool replace_container_info = false; bool replace_container_info = false;
if(s.options.print_additional == "c" || s.options.print_additional == "container") if(s.options.print_additional == "c" || s.options.print_additional == "container")
{ {
output_format = "container=%container.name (id=%container.id)"; output_format = container_info;
replace_container_info = true; replace_container_info = true;
} }
else if(s.options.print_additional == "cg" || s.options.print_additional == "container-gvisor") else if(s.options.print_additional == "cg" || s.options.print_additional == "container-gvisor")
{ {
output_format = "container=%container.name (id=%container.id) vpid=%proc.vpid vtid=%thread.vtid"; output_format = gvisor_info + " " + container_info;
replace_container_info = true; replace_container_info = true;
} }
else if(s.options.print_additional == "k" || s.options.print_additional == "kubernetes") else if(s.options.print_additional == "k" || s.options.print_additional == "kubernetes")
{ {
output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id"; output_format = container_info + " " + k8s_info;
replace_container_info = true; replace_container_info = true;
} }
else if(s.options.print_additional == "kg" || s.options.print_additional == "kubernetes-gvisor") else if(s.options.print_additional == "kg" || s.options.print_additional == "kubernetes-gvisor")
{ {
output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id vpid=%proc.vpid vtid=%thread.vtid"; output_format = gvisor_info + " " + container_info + " " + k8s_info;
replace_container_info = true; replace_container_info = true;
} }
else if(!s.options.print_additional.empty()) else if(!s.options.print_additional.empty())

View File

@@ -51,7 +51,7 @@ falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s)
if (s.options.dry_run) if (s.options.dry_run)
{ {
falco_logger::log(LOG_DEBUG, "Skipping daemonizing in dry-run\n"); falco_logger::log(LOG_DEBUG, "Skipping outputs initialization in dry-run\n");
return run_result::ok(); return run_result::ok();
} }

View File

@@ -25,20 +25,7 @@ static void apply_deprecated_options(
const falco::app::options& opts, const falco::app::options& opts,
const std::shared_ptr<falco_configuration>& cfg) const std::shared_ptr<falco_configuration>& cfg)
{ {
if (!opts.stats_output_file.empty() || !opts.stats_interval.empty()) // Keep for future use cases.
{
falco_logger::log(LOG_WARNING, "Options '-s' and '--stats-interval' will be deprecated in the future, metrics must be configured through config file");
if (!opts.stats_output_file.empty())
{
cfg->m_metrics_enabled = true;
cfg->m_metrics_output_file = opts.stats_output_file;
if (!opts.stats_interval.empty())
{
cfg->m_metrics_interval_str = opts.stats_interval;
cfg->m_metrics_interval = falco::utils::parse_prometheus_interval(cfg->m_metrics_interval_str);
}
}
}
} }
falco::app::run_result falco::app::actions::load_config(falco::app::state& s) falco::app::run_result falco::app::actions::load_config(falco::app::state& s)
@@ -80,13 +67,15 @@ falco::app::run_result falco::app::actions::load_config(falco::app::state& s)
falco::app::run_result falco::app::actions::require_config_file(falco::app::state& s) falco::app::run_result falco::app::actions::require_config_file(falco::app::state& s)
{ {
#ifndef __EMSCRIPTEN__
if (s.options.conf_filename.empty()) if (s.options.conf_filename.empty())
{ {
#ifndef BUILD_TYPE_RELEASE #ifndef BUILD_TYPE_RELEASE
return run_result::fatal(std::string("You must create a config file at ") + FALCO_SOURCE_CONF_FILE + ", " + FALCO_INSTALL_CONF_FILE + " or by passing -c"); return run_result::fatal(std::string("You must create a config file at ") + FALCO_SOURCE_CONF_FILE + ", " + FALCO_INSTALL_CONF_FILE + " or by passing -c");
#else #else // BUILD_TYPE_RELEASE
return run_result::fatal(std::string("You must create a config file at ") + FALCO_INSTALL_CONF_FILE + " or by passing -c"); return run_result::fatal(std::string("You must create a config file at ") + FALCO_INSTALL_CONF_FILE + " or by passing -c");
#endif #endif // BUILD_TYPE_RELEASE
} }
#endif // __EMSCRIPTEN__
return run_result::ok(); return run_result::ok();
} }

View File

@@ -22,10 +22,10 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s) falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s)
{ {
#ifdef MUSL_OPTIMIZED #if defined(MUSL_OPTIMIZED) or defined(__EMSCRIPTEN__)
if (!s.config->m_plugins.empty()) if (!s.config->m_plugins.empty())
{ {
return run_result::fatal("Can not load/use plugins with musl optimized build"); return run_result::fatal("Loading plugins dynamic libraries is not supported by this Falco build");
} }
#endif #endif
// Initialize the set of loaded event sources. // Initialize the set of loaded event sources.

View File

@@ -0,0 +1,52 @@
/*
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
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 <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "actions.h"
using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::pidfile(falco::app::state& s)
{
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping pidfile creation in dry-run\n");
return run_result::ok();
}
if (!s.options.pidfilename.empty())
{
int64_t self_pid = getpid();
std::ofstream pidfile;
pidfile.open(s.options.pidfilename);
if (!pidfile.good())
{
falco_logger::log(LOG_ERR, "Could not write pid to pidfile " + s.options.pidfilename + ". Exiting.\n");
exit(-1);
}
pidfile << self_pid;
pidfile.close();
}
return run_result::ok();
}

View File

@@ -24,12 +24,6 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::print_plugin_info(falco::app::state& s) falco::app::run_result falco::app::actions::print_plugin_info(falco::app::state& s)
{ {
#ifdef MUSL_OPTIMIZED
if(!s.options.print_plugin_info.empty())
{
return run_result::fatal("Can not load or use plugins with musl optimized build");
}
#else // MUSL_OPTIMIZED
if(!s.options.print_plugin_info.empty()) if(!s.options.print_plugin_info.empty())
{ {
std::unique_ptr<sinsp> inspector(new sinsp()); std::unique_ptr<sinsp> inspector(new sinsp());
@@ -110,7 +104,6 @@ falco::app::run_result falco::app::actions::print_plugin_info(falco::app::state&
} }
return run_result::fatal("can't find plugin and print its info: " + s.options.print_plugin_info); return run_result::fatal("can't find plugin and print its info: " + s.options.print_plugin_info);
} }
#endif // MUSL_OPTIMIZED
return run_result::ok(); return run_result::ok();
} }

View File

@@ -30,13 +30,10 @@ limitations under the License.
#include "helpers.h" #include "helpers.h"
#include "../options.h" #include "../options.h"
#include "../signals.h" #include "../signals.h"
#include "../../semaphore.h" #include "../../falco_semaphore.h"
#include "../../stats_writer.h" #include "../../stats_writer.h"
#include "../../falco_outputs.h" #include "../../falco_outputs.h"
#include "../../event_drops.h" #include "../../event_drops.h"
#ifndef MINIMAL_BUILD
#include "../../webserver.h"
#endif
#include <plugin_manager.h> #include <plugin_manager.h>
@@ -430,15 +427,14 @@ static falco::app::run_result init_stats_writer(
if(std::all_of(config->m_metrics_interval_str.begin(), config->m_metrics_interval_str.end(), ::isdigit)) if(std::all_of(config->m_metrics_interval_str.begin(), config->m_metrics_interval_str.end(), ::isdigit))
{ {
falco_logger::log(LOG_WARNING, "Metrics interval was passed as numeric value without Prometheus time unit, this option will be deprecated in the future"); 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()) if (config->m_metrics_enabled && !sw->has_output())
{ {
falco_logger::log(LOG_WARNING, "Metrics are enabled with no output configured, no snapshot will be collected"); return falco::app::run_result::fatal("Metrics are enabled with no output configured. Please enable at least one output channel");
} }
falco_logger::log(LOG_INFO, "Setting metrics interval to " + config->m_metrics_interval_str + ", equivalent to " + std::to_string(config->m_metrics_interval) + " (ms)\n"); falco_logger::log(LOG_INFO, "Setting metrics interval to " + config->m_metrics_interval_str + ", equivalent to " + std::to_string(config->m_metrics_interval) + " (ms)\n");
auto res = falco::app::run_result::ok(); auto res = falco::app::run_result::ok();
@@ -496,6 +492,13 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
{ {
print_enabled_event_sources(s); print_enabled_event_sources(s);
#ifdef __EMSCRIPTEN__
if(s.enabled_sources.size() > 1)
{
return run_result::fatal("enabling multiple event sources is not supported by this Falco build");
}
#endif
// start event processing for all enabled sources // start event processing for all enabled sources
falco::semaphore termination_sem(s.enabled_sources.size()); falco::semaphore termination_sem(s.enabled_sources.size());
std::vector<live_context> ctxs; std::vector<live_context> ctxs;

View File

@@ -16,7 +16,7 @@ limitations under the License.
#include "actions.h" #include "actions.h"
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "grpc_server.h" #include "grpc_server.h"
#endif #endif
@@ -25,7 +25,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state& s) falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state& s)
{ {
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
// gRPC server // gRPC server
if(s.config->m_grpc_enabled) if(s.config->m_grpc_enabled)
{ {
@@ -56,7 +56,7 @@ falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state&
falco::app::run_result falco::app::actions::stop_grpc_server(falco::app::state& s) falco::app::run_result falco::app::actions::stop_grpc_server(falco::app::state& s)
{ {
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(s.config->m_grpc_enabled) if(s.config->m_grpc_enabled)
{ {
if (s.options.dry_run) if (s.options.dry_run)

View File

@@ -16,7 +16,7 @@ limitations under the License.
#include "actions.h" #include "actions.h"
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "webserver.h" #include "webserver.h"
#endif #endif
@@ -25,7 +25,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s) falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s)
{ {
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(!s.is_capture_mode() && s.config->m_webserver_enabled) if(!s.is_capture_mode() && s.config->m_webserver_enabled)
{ {
if (s.options.dry_run) if (s.options.dry_run)
@@ -55,7 +55,7 @@ falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s
falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& s) falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& s)
{ {
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(!s.is_capture_mode() && s.config->m_webserver_enabled) if(!s.is_capture_mode() && s.config->m_webserver_enabled)
{ {
if (s.options.dry_run) if (s.options.dry_run)

View File

@@ -80,7 +80,7 @@ bool falco::app::run(falco::app::state& s, bool& restart, std::string& errstr)
falco::app::actions::init_outputs, falco::app::actions::init_outputs,
falco::app::actions::create_signal_handlers, falco::app::actions::create_signal_handlers,
falco::app::actions::create_requested_paths, falco::app::actions::create_requested_paths,
falco::app::actions::daemonize, falco::app::actions::pidfile,
falco::app::actions::init_clients, falco::app::actions::init_clients,
falco::app::actions::configure_interesting_sets, falco::app::actions::configure_interesting_sets,
falco::app::actions::configure_syscall_buffer_size, falco::app::actions::configure_syscall_buffer_size,

View File

@@ -36,6 +36,7 @@ options::options()
list_plugins(false), list_plugins(false),
list_syscall_events(false), list_syscall_events(false),
markdown(false), markdown(false),
userspace(false),
modern_bpf(false), modern_bpf(false),
dry_run(false), dry_run(false),
nodriver(false) nodriver(false)
@@ -142,11 +143,6 @@ bool options::parse(int argc, char **argv, std::string &errstr)
return false; return false;
} }
if (daemon && pidfilename == "") {
errstr = std::string("If -d is provided, a pid file must also be provided");
return false;
}
list_fields = m_cmdline_parsed.count("list") > 0 ? true : false; list_fields = m_cmdline_parsed.count("list") > 0 ? true : false;
int open_modes = 0; int open_modes = 0;
@@ -173,64 +169,63 @@ const std::string& options::usage()
void options::define(cxxopts::Options& opts) void options::define(cxxopts::Options& opts)
{ {
opts.add_options() opts.add_options()
("h,help", "Print this page", cxxopts::value(help)->default_value("false")) ("h,help", "Print this help list and exit.", cxxopts::value(help)->default_value("false"))
#ifdef BUILD_TYPE_RELEASE #ifdef BUILD_TYPE_RELEASE
("c", "Configuration file. If not specified uses " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>") ("c", "Configuration file. If not specified uses " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
#else #else
("c", "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>") ("c", "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
#endif #endif
("A", "Monitor all events supported by Falco defined in rules and configs. Please use the -i option to list the events ignored by default without -A. This option affects live captures only. Setting -A can impact performance.", cxxopts::value(all_events)->default_value("false")) ("A", "Monitor all events supported by Falco and defined in rules and configs. Some events are ignored by default when -A is not specified (the -i option lists these events ignored). Using -A can impact performance. This option has no effect when reproducing events from a capture file.", cxxopts::value(all_events)->default_value("false"))
("b,print-base64", "Print data buffers in base64. This is useful for encoding binary data that needs to be used over media designed to consume this format.") ("b,print-base64", "Print data buffers in base64. This is useful for encoding binary data that needs to be used over media designed to consume this format.")
("cri", "Path to CRI socket for container metadata. Use the specified socket to fetch data from a CRI-compatible runtime. If not specified, uses the libs default. This option can be passed multiple times to specify socket to be tried until a successful one is found.", cxxopts::value(cri_socket_paths), "<path>") #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
("d,daemon", "Run as a daemon.", cxxopts::value(daemon)->default_value("false")) ("cri", "Path to CRI socket for container metadata. Use the specified <path> to fetch data from a CRI-compatible runtime. If not specified, built-in defaults for commonly known paths are used. This option can be passed multiple times to specify a list of sockets to be tried until a successful one is found.", cxxopts::value(cri_socket_paths), "<path>")
("disable-cri-async", "Disable asynchronous CRI metadata fetching. This is useful to let the input event wait for the container metadata fetch to finish before moving forward. Async fetching, in some environments leads to empty fields for container metadata when the fetch is not fast enough to be completed asynchronously. This can have a performance penalty on your environment depending on the number of containers and the frequency at which they are created/started/stopped.", cxxopts::value(disable_cri_async)->default_value("false")) ("disable-cri-async", "Turn off asynchronous CRI metadata fetching. This is useful to let the input event wait for the container metadata fetch to finish before moving forward. Async fetching, in some environments leads to empty fields for container metadata when the fetch is not fast enough to be completed asynchronously. This can have a performance penalty on your environment depending on the number of containers and the frequency at which they are created/started/stopped.", cxxopts::value(disable_cri_async)->default_value("false"))
("disable-source", "Disable a specific event source. By default, all loaded sources get enabled. Available sources are 'syscall' and all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. This has no offect when reading events from a trace file. Can not disable all event sources. Can not be mixed with --enable-source.", cxxopts::value(disable_sources), "<event_source>") #endif
("dry-run", "Run Falco without proceesing events. Can be useful for checking that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false")) ("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>")
("D", "Disable any rules with names having the substring <substring>. This option can be passed multiple times. Can not be mixed with -t.", cxxopts::value(disabled_rule_substrings), "<substring>") ("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"))
("e", "Read the events from a trace file <events_file> in .scap format instead of tapping into live.", cxxopts::value(trace_filename), "<events_file>") ("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. If used, all loaded sources get disabled by default and only the ones passed with this option get enabled. Available sources are 'syscall' and all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. This has no offect when reading events from a trace file. Can not be mixed with --disable-source.", cxxopts::value(enable_sources), "<event_source>") ("e", "Reproduce the events by reading from the given <capture_file> instead of opening a live session. Only capture files in .scap format are supported.", cxxopts::value(trace_filename), "<events_file>")
("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 #ifdef HAS_GVISOR
("g,gvisor-config", "Parse events from gVisor using the specified configuration file. A falco-compatible configuration file can be generated with --gvisor-generate-config and can be used for both runsc and Falco.", cxxopts::value(gvisor_config), "<gvisor_config>") ("g,gvisor-config", "Collect 'syscall' events from gVisor using the specified <gvisor_config> file. A Falco-compatible configuration file can be generated with --gvisor-generate-config and utilized for both runsc and Falco.", cxxopts::value(gvisor_config), "<gvisor_config>")
("gvisor-generate-config", "Generate a configuration file that can be used for gVisor.", cxxopts::value<std::string>(gvisor_generate_config_with_socket)->implicit_value("/run/falco/gvisor.sock"), "<socket_path>") ("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>")
("gvisor-root", "gVisor root directory for storage of container state. Equivalent to runsc --root flag.", cxxopts::value(gvisor_root), "<gvisor_root>") ("gvisor-root", "Set gVisor root directory for storage of container state when used in conjunction with --gvisor-config. The <gvisor_root> to be passed is the one usually passed to runsc --root flag.", cxxopts::value(gvisor_root), "<gvisor_root>")
#endif #endif
#ifdef HAS_MODERN_BPF #ifdef HAS_MODERN_BPF
("modern-bpf", "Use BPF modern probe driver to instrument the kernel.", cxxopts::value(modern_bpf)->default_value("false")) ("modern-bpf", "Use the BPF modern probe driver to instrument the kernel and observe 'syscall' events.", cxxopts::value(modern_bpf)->default_value("false"))
#endif #endif
("i", "Print all high volume syscalls that are ignored by default for performance reasons (i.e. without the -A flag) and exit.", cxxopts::value(print_ignored_events)->default_value("false")) ("i", "Print those events that are ignored by default for performance reasons and exit. See -A for more details.", cxxopts::value(print_ignored_events)->default_value("false"))
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
("k,k8s-api", "Enable Kubernetes support by connecting to the API server specified as argument. E.g. \"http://admin:password@127.0.0.1:8080\". The API server can also be specified via the environment variable FALCO_K8S_API.", cxxopts::value(k8s_api), "<url>") ("k,k8s-api", "Enable Kubernetes metadata support by connecting to the given API server <URL>\n(e.g. \"http://admin:password@127.0.0.1:8080\". The API server can also be specified via the environment variable FALCO_K8S_API.", cxxopts::value(k8s_api), "<URL>")
("K,k8s-api-cert", "Use the provided files names to authenticate user and (optionally) verify the K8S API server identity. Each entry must specify full (absolute, or relative to the current directory) path to the respective file. Private key password is optional (needed only if key is password protected). CA certificate is optional. For all files, only PEM file format is supported. Specifying CA certificate only is obsoleted - when single entry is provided for this option, it will be interpreted as the name of a file containing bearer token. Note that the format of this command-line option prohibits use of files whose names contain ':' or '#' characters in the file name.", cxxopts::value(k8s_api_cert), "(<bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>])") ("K,k8s-api-cert", "Use the provided file names to authenticate the user and (optionally) verify the K8S API server identity. Each entry must specify the full (absolute or relative to the current directory) path to the respective file. Passing a private key password is optional (unless the key is password-protected). CA certificate is optional. For all files, only the PEM file format is supported. Specifying the CA certificate only is obsoleted - when a single entry is provided for this option, it will be interpreted as the name of a file containing the bearer token. Note that the format of this command-line option prohibits the use of files whose names contain ':' or '#' characters in the file name. This option has effect only when used in conjunction with -k.", cxxopts::value(k8s_api_cert), "(<bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>])")
("k8s-node", "The node name will be used as a filter when requesting metadata of pods to the API server. Usually, this should be set to the current node on which Falco is running. If empty, no filter is set, which may have a performance penalty on large clusters.", cxxopts::value(k8s_node_name), "<node_name>") ("k8s-node", "Filter Kubernetes metadata for a specified <node_name>. The node name will be used as a filter when requesting metadata of pods to the API server. Usually, this should be set to the current node on which Falco is running. No filter is set if empty, which may have a performance penalty on large clusters. This option has effect only when used in conjunction with -k.", cxxopts::value(k8s_node_name), "<node_name>")
#endif #endif
("L", "Show the name and description of all rules and exit. If json_output is set to true, it prints details about all rules, macros and lists in JSON format", cxxopts::value(describe_all_rules)->default_value("false")) ("L", "Show the name and description of all rules and exit. If json_output is set to true, it prints details about all rules, macros, and lists in JSON format.", cxxopts::value(describe_all_rules)->default_value("false"))
("l", "Show the name and description of the rule with name <rule> and exit. If json_output is set to true, it prints details about the rule in JSON format", cxxopts::value(describe_rule), "<rule>") ("l", "Show the name and description of the rule specified <rule> and exit. If json_output is set to true, it prints details about the rule in JSON format.", cxxopts::value(describe_rule), "<rule>")
("list", "List all defined fields. If <source> is provided, only list those fields for the source <source>. Current values for <source> are \"syscall\" or any source from a configured plugin with event sourcing capability.", cxxopts::value(list_source_fields)->implicit_value(""), "<source>") ("list", "List all defined fields and exit. If <source> is provided, only list those fields for the source <source>. Current values for <source> are \"syscall\" or any source from a configured plugin with event sourcing capability.", cxxopts::value(list_source_fields)->implicit_value(""), "<source>")
("list-syscall-events", "List all defined system call events.", cxxopts::value<bool>(list_syscall_events)) ("list-syscall-events", "List all defined 'syscall' events and exit.", cxxopts::value<bool>(list_syscall_events))
#ifndef MUSL_OPTIMIZED
("list-plugins", "Print info on all loaded plugins and exit.", cxxopts::value(list_plugins)->default_value("false")) ("list-plugins", "Print info on all loaded plugins and exit.", cxxopts::value(list_plugins)->default_value("false"))
("M", "Stop Falco execution after <num_seconds> are passed.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>")
("markdown", "Print output in Markdown format when used in conjunction with --list or --list-syscall-events options. It has no effect when used with other options.", cxxopts::value<bool>(markdown))
("N", "Only print field names when used in conjunction with the --list option. It has no effect when used with other options.", cxxopts::value(names_only)->default_value("false"))
("nodriver", "Do not use a driver to instrument the kernel. If a loaded plugin has event-sourcing capability and can produce system events, it will be used for event collection. Otherwise, no event will be collected.", cxxopts::value(nodriver)->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.\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", "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"))
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
("u,userspace", "[DEPRECATED: this option will be removed in Falco 0.37] Use a userspace driver to collect 'syscall' events. To be used in conjunction with the ptrace(2) based driver (pdig).", cxxopts::value(userspace)->default_value("false"))
#endif #endif
("M", "Stop collecting after <num_seconds> reached.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>") ("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>")
("markdown", "When used with --list/--list-syscall-events, print the content in Markdown format", cxxopts::value<bool>(markdown)) ("v", "Enable verbose output.", cxxopts::value(verbose)->default_value("false"))
("N", "When used with --list, only print field names.", cxxopts::value(names_only)->default_value("false")) ("version", "Print version information and exit.", cxxopts::value(print_version_info)->default_value("false"))
("nodriver", "Do not use a driver to instrument the kernel. If a loaded plugin has event sourcing capability and can produce system events, it will be used to for event collection.", cxxopts::value(nodriver)->default_value("false")) ("page-size", "Print the system page size and exit. This utility may help choose the right syscall ring buffer size.", cxxopts::value(print_page_size)->default_value("false"));
("o,option", "Set the value of option <opt> to <val>. Overrides values in configuration file. <opt> can be identified using its location in configuration file using dot notation. Elements which are entries of lists 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 a single plugin and exit.\nThis includes all descriptivo info 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 name of the plugin or its configured library_path.", cxxopts::value(print_plugin_info), "<plugin_name>")
("p,print", "Add additional information to each falco notification's output.\nWith -pc or -pcontainer will use a container-friendly format.\nWith -pk or -pkubernetes will use a kubernetes-friendly format.\nAdditionally, specifying -pc/-pk will change the interpretation of %container.info in rule output fields.", cxxopts::value(print_additional), "<output_format>")
("P,pidfile", "Write pid Falco's process ID (PID) file to the specified file", cxxopts::value(pidfilename)->default_value("/var/run/falco.pid"), "<pid_file>")
("r", "Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml). This option can be passed multiple times to read from multiple files/directories.", cxxopts::value<std::vector<std::string>>(), "<rules_file>")
("s", "If specified, append statistics related to Falco's reading/processing of events to this file (only useful in live mode).", cxxopts::value(stats_output_file), "<stats_file>")
("stats-interval", "When using -s <stats_file>, write statistics every <msec> ms. This uses signals, and has a minimum threshold of 100 ms. Defaults to 5000 (5 seconds).", cxxopts::value(stats_interval), "<msec>")
("S,snaplen", "Capture the first <len> bytes of each I/O buffer. By default, the first 80 bytes are captured. Use this option with caution, it can have a strong performance impact.", cxxopts::value(snaplen)->default_value("0"), "<len>")
("support", "Print support information including version, rules files used, etc. and exit.", cxxopts::value(print_support)->default_value("false"))
("T", "Disable any rules with a tag=<tag>. This option can be passed multiple times. Can not be mized with -t", cxxopts::value<std::vector<std::string>>(), "<tag>")
("t", "Only run those rules with a tag=<tag>. This option can be passed multiple times. Can not be mixed with -T/-D.", cxxopts::value<std::vector<std::string>>(), "<tag>")
("U,unbuffered", "Turn off output buffering to 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 into a script.", cxxopts::value(unbuffered_outputs)->default_value("false"))
("u,userspace", "Parse events from userspace. To be used in conjunction with the ptrace(2) based driver (pdig)", cxxopts::value(userspace)->default_value("false"))
("V,validate", "Read the contents of the specified rules(s) file and exit. This option can be passed multiple times to validate multiple files.", cxxopts::value(validate_rules_filenames), "<rules_file>")
("v", "Verbose output.", cxxopts::value(verbose)->default_value("false"))
("version", "Print version number.", cxxopts::value(print_version_info)->default_value("false"))
("page-size", "Print the system page size (may help you to choose the right syscall ring-buffer size).", cxxopts::value(print_page_size)->default_value("false"));
opts.set_width(140); opts.set_width(140);

View File

@@ -42,7 +42,6 @@ public:
bool all_events; bool all_events;
sinsp_evt::param_fmt event_buffer_format; sinsp_evt::param_fmt event_buffer_format;
std::vector<std::string> cri_socket_paths; std::vector<std::string> cri_socket_paths;
bool daemon;
bool disable_cri_async; bool disable_cri_async;
std::vector<std::string> disable_sources; std::vector<std::string> disable_sources;
std::vector<std::string> disabled_rule_substrings; std::vector<std::string> disabled_rule_substrings;
@@ -70,8 +69,6 @@ public:
std::string pidfilename; std::string pidfilename;
// Rules list as passed by the user, via cmdline option '-r' // Rules list as passed by the user, via cmdline option '-r'
std::list<std::string> rules_filenames; std::list<std::string> rules_filenames;
std::string stats_output_file;
std::string stats_interval;
uint64_t snaplen; uint64_t snaplen;
bool print_support; bool print_support;
std::set<std::string> disabled_rule_tags; std::set<std::string> disabled_rule_tags;

View File

@@ -31,8 +31,9 @@ limitations under the License.
falco::app::restart_handler::~restart_handler() falco::app::restart_handler::~restart_handler()
{ {
close(m_inotify_fd);
stop(); stop();
close(m_inotify_fd);
m_inotify_fd = -1;
} }
void falco::app::restart_handler::trigger() void falco::app::restart_handler::trigger()
@@ -42,6 +43,7 @@ void falco::app::restart_handler::trigger()
bool falco::app::restart_handler::start(std::string& err) bool falco::app::restart_handler::start(std::string& err)
{ {
#ifdef __linux__
m_inotify_fd = inotify_init(); m_inotify_fd = inotify_init();
if (m_inotify_fd < 0) if (m_inotify_fd < 0)
{ {
@@ -73,16 +75,19 @@ bool falco::app::restart_handler::start(std::string& err)
// launch the watcher thread // launch the watcher thread
m_watcher = std::thread(&falco::app::restart_handler::watcher_loop, this); m_watcher = std::thread(&falco::app::restart_handler::watcher_loop, this);
#endif
return true; return true;
} }
void falco::app::restart_handler::stop() void falco::app::restart_handler::stop()
{ {
#ifdef __linux__
m_stop.store(true, std::memory_order_release); m_stop.store(true, std::memory_order_release);
if (m_watcher.joinable()) if (m_watcher.joinable())
{ {
m_watcher.join(); m_watcher.join();
} }
#endif
} }
void falco::app::restart_handler::watcher_loop() noexcept void falco::app::restart_handler::watcher_loop() noexcept

View File

@@ -22,7 +22,7 @@ limitations under the License.
#include "restart_handler.h" #include "restart_handler.h"
#include "../configuration.h" #include "../configuration.h"
#include "../stats_writer.h" #include "../stats_writer.h"
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "../grpc_server.h" #include "../grpc_server.h"
#include "../webserver.h" #include "../webserver.h"
#endif #endif
@@ -137,7 +137,7 @@ struct state
// Helper responsible for watching of handling hot application restarts // Helper responsible for watching of handling hot application restarts
std::shared_ptr<restart_handler> restarter; std::shared_ptr<restart_handler> restarter;
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
falco::grpc::server grpc_server; falco::grpc::server grpc_server;
std::thread grpc_server_thread; std::thread grpc_server_thread;

View File

@@ -37,8 +37,8 @@ falco_configuration::falco_configuration():
m_json_include_tags_property(true), m_json_include_tags_property(true),
m_notifications_rate(0), m_notifications_rate(0),
m_notifications_max_burst(1000), m_notifications_max_burst(1000),
m_watch_config_files(true),
m_rule_matching(falco_common::rule_matching::FIRST), m_rule_matching(falco_common::rule_matching::FIRST),
m_watch_config_files(true),
m_buffered_outputs(false), m_buffered_outputs(false),
m_time_format_iso_8601(false), m_time_format_iso_8601(false),
m_output_timeout(2000), m_output_timeout(2000),
@@ -195,6 +195,10 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
insecure = config.get_scalar<bool>("http_output.insecure", false); insecure = config.get_scalar<bool>("http_output.insecure", false);
http_output.options["insecure"] = insecure? std::string("true") : std::string("false"); http_output.options["insecure"] = insecure? std::string("true") : std::string("false");
bool echo;
echo = config.get_scalar<bool>("http_output.echo", false);
http_output.options["echo"] = echo? std::string("true") : std::string("false");
std::string ca_cert; std::string ca_cert;
ca_cert = config.get_scalar<std::string>("http_output.ca_cert", ""); ca_cert = config.get_scalar<std::string>("http_output.ca_cert", "");
http_output.options["ca_cert"] = ca_cert; http_output.options["ca_cert"] = ca_cert;
@@ -207,6 +211,18 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
ca_path = config.get_scalar<std::string>("http_output.ca_path", "/etc/ssl/certs"); ca_path = config.get_scalar<std::string>("http_output.ca_path", "/etc/ssl/certs");
http_output.options["ca_path"] = ca_path; http_output.options["ca_path"] = ca_path;
bool mtls;
mtls = config.get_scalar<bool>("http_output.mtls", false);
http_output.options["mtls"] = mtls? std::string("true") : std::string("false");
std::string client_cert;
client_cert = config.get_scalar<std::string>("http_output.client_cert", "/etc/ssl/certs/client.crt");
http_output.options["client_cert"] = client_cert;
std::string client_key;
client_key = config.get_scalar<std::string>("http_output.client_key", "/etc/ssl/certs/client.key");
http_output.options["client_key"] = client_key;
m_outputs.push_back(http_output); m_outputs.push_back(http_output);
} }
@@ -240,9 +256,16 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
config.get_scalar<std::string>("libs_logger.severity", "debug"), config.get_scalar<std::string>("libs_logger.severity", "debug"),
"[libs]: "); "[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); m_output_timeout = config.get_scalar<uint32_t>("output_timeout", 2000);
m_notifications_rate = config.get_scalar<uint32_t>("outputs.rate", 0); m_notifications_rate = config.get_scalar<uint32_t>("outputs.rate", 0);
if(m_notifications_rate != 0)
{
falco_logger::log(LOG_WARNING, "'output.rate' config is deprecated and it will be removed in Falco 0.37\n");
}
m_notifications_max_burst = config.get_scalar<uint32_t>("outputs.max_burst", 1000); m_notifications_max_burst = config.get_scalar<uint32_t>("outputs.max_burst", 1000);
std::string rule_matching = config.get_scalar<std::string>("rule_matching", "first"); std::string rule_matching = config.get_scalar<std::string>("rule_matching", "first");
@@ -260,9 +283,6 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
m_buffered_outputs = config.get_scalar<bool>("buffered_outputs", false); m_buffered_outputs = config.get_scalar<bool>("buffered_outputs", false);
m_time_format_iso_8601 = config.get_scalar<bool>("time_format_iso_8601", false); m_time_format_iso_8601 = config.get_scalar<bool>("time_format_iso_8601", false);
falco_logger::log_stderr = config.get_scalar<bool>("log_stderr", false);
falco_logger::log_syslog = config.get_scalar<bool>("log_syslog", true);
m_webserver_enabled = config.get_scalar<bool>("webserver.enabled", false); m_webserver_enabled = config.get_scalar<bool>("webserver.enabled", false);
m_webserver_threadiness = config.get_scalar<uint32_t>("webserver.threadiness", 0); 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_port = config.get_scalar<uint32_t>("webserver.listen_port", 8765);

View File

@@ -86,6 +86,8 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr<sinsp> inspector, sinsp
delta.n_drops_buffer_dir_file_exit = stats.n_drops_buffer_dir_file_exit - m_last_stats.n_drops_buffer_dir_file_exit; delta.n_drops_buffer_dir_file_exit = stats.n_drops_buffer_dir_file_exit - m_last_stats.n_drops_buffer_dir_file_exit;
delta.n_drops_buffer_other_interest_enter = stats.n_drops_buffer_other_interest_enter - m_last_stats.n_drops_buffer_other_interest_enter; delta.n_drops_buffer_other_interest_enter = stats.n_drops_buffer_other_interest_enter - m_last_stats.n_drops_buffer_other_interest_enter;
delta.n_drops_buffer_other_interest_exit = stats.n_drops_buffer_other_interest_exit - m_last_stats.n_drops_buffer_other_interest_exit; delta.n_drops_buffer_other_interest_exit = stats.n_drops_buffer_other_interest_exit - m_last_stats.n_drops_buffer_other_interest_exit;
delta.n_drops_buffer_close_exit = stats.n_drops_buffer_close_exit - m_last_stats.n_drops_buffer_close_exit;
delta.n_drops_buffer_proc_exit = stats.n_drops_buffer_proc_exit - m_last_stats.n_drops_buffer_proc_exit;
delta.n_drops_scratch_map = stats.n_drops_scratch_map - m_last_stats.n_drops_scratch_map; delta.n_drops_scratch_map = stats.n_drops_scratch_map - m_last_stats.n_drops_scratch_map;
delta.n_drops_pf = stats.n_drops_pf - m_last_stats.n_drops_pf; delta.n_drops_pf = stats.n_drops_pf - m_last_stats.n_drops_pf;
delta.n_drops_bug = stats.n_drops_bug - m_last_stats.n_drops_bug; delta.n_drops_bug = stats.n_drops_bug - m_last_stats.n_drops_bug;
@@ -118,7 +120,7 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr<sinsp> inspector, sinsp
{ {
m_num_actions++; m_num_actions++;
return perform_actions(evt->get_ts(), delta, inspector->check_current_engine(BPF_ENGINE)); return perform_actions(evt->get_ts(), delta, inspector->check_current_engine(BPF_ENGINE) || inspector->check_current_engine(MODERN_BPF_ENGINE));
} }
else else
{ {
@@ -183,6 +185,8 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, scap_stats &delta, bool
*/ */
output_fields["n_drops_buffer_other_interest_enter"] = std::to_string(delta.n_drops_buffer_other_interest_enter); output_fields["n_drops_buffer_other_interest_enter"] = std::to_string(delta.n_drops_buffer_other_interest_enter);
output_fields["n_drops_buffer_other_interest_exit"] = std::to_string(delta.n_drops_buffer_other_interest_exit); output_fields["n_drops_buffer_other_interest_exit"] = std::to_string(delta.n_drops_buffer_other_interest_exit);
output_fields["n_drops_buffer_close_exit"] = std::to_string(delta.n_drops_buffer_close_exit);
output_fields["n_drops_buffer_proc_exit"] = std::to_string(delta.n_drops_buffer_proc_exit);
output_fields["n_drops_scratch_map"] = std::to_string(delta.n_drops_scratch_map); /* Number of kernel side scratch map drops. */ output_fields["n_drops_scratch_map"] = std::to_string(delta.n_drops_scratch_map); /* Number of kernel side scratch map drops. */
output_fields["n_drops_page_faults"] = std::to_string(delta.n_drops_pf); /* Number of kernel side page faults drops (invalid memory access). */ output_fields["n_drops_page_faults"] = std::to_string(delta.n_drops_pf); /* Number of kernel side page faults drops (invalid memory access). */
output_fields["n_drops_bug"] = std::to_string(delta.n_drops_bug); /* Number of kernel side bug drops (invalid condition in the kernel instrumentation). */ output_fields["n_drops_bug"] = std::to_string(delta.n_drops_bug); /* Number of kernel side bug drops (invalid condition in the kernel instrumentation). */

View File

@@ -26,8 +26,7 @@ limitations under the License.
static void display_fatal_err(const std::string &&msg) static void display_fatal_err(const std::string &&msg)
{ {
/** /**
* If stderr logging is not enabled, also log to stderr. When * If stderr logging is not enabled, also log to stderr.
* daemonized this will simply write to /dev/null.
*/ */
if (! falco_logger::log_stderr) if (! falco_logger::log_stderr)
{ {

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include <google/protobuf/util/time_util.h> #include <google/protobuf/util/time_util.h>
#endif #endif
@@ -30,7 +30,7 @@ limitations under the License.
#include "outputs_program.h" #include "outputs_program.h"
#include "outputs_stdout.h" #include "outputs_stdout.h"
#include "outputs_syslog.h" #include "outputs_syslog.h"
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "outputs_http.h" #include "outputs_http.h"
#include "outputs_grpc.h" #include "outputs_grpc.h"
#endif #endif
@@ -64,13 +64,16 @@ falco_outputs::falco_outputs(
{ {
add_output(output); add_output(output);
} }
#ifndef __EMSCRIPTEN__
m_worker_thread = std::thread(&falco_outputs::worker, this); m_worker_thread = std::thread(&falco_outputs::worker, this);
#endif
} }
falco_outputs::~falco_outputs() falco_outputs::~falco_outputs()
{ {
#ifndef __EMSCRIPTEN__
this->stop_worker(); this->stop_worker();
#endif
for(auto o : m_outputs) for(auto o : m_outputs)
{ {
delete o; delete o;
@@ -98,7 +101,7 @@ void falco_outputs::add_output(falco::outputs::config oc)
{ {
oo = new falco::outputs::output_syslog(); oo = new falco::outputs::output_syslog();
} }
#ifndef MINIMAL_BUILD #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
else if(oc.name == "http") else if(oc.name == "http")
{ {
oo = new falco::outputs::output_http(); oo = new falco::outputs::output_http();
@@ -113,9 +116,17 @@ void falco_outputs::add_output(falco::outputs::config oc)
throw falco_exception("Output not supported: " + oc.name); throw falco_exception("Output not supported: " + oc.name);
} }
oo->init(oc, m_buffered, m_hostname, m_json_output); std::string init_err;
if (oo->init(oc, m_buffered, m_hostname, m_json_output, init_err))
{
m_outputs.push_back(oo); m_outputs.push_back(oo);
} }
else
{
falco_logger::log(LOG_ERR, "Failed to init output: " + init_err);
delete(oo);
}
}
void falco_outputs::handle_event(gen_event *evt, std::string &rule, std::string &source, void falco_outputs::handle_event(gen_event *evt, std::string &rule, std::string &source,
falco_common::priority_type priority, std::string &format, std::set<std::string> &tags) falco_common::priority_type priority, std::string &format, std::set<std::string> &tags)
@@ -245,7 +256,9 @@ void falco_outputs::stop_worker()
watchdog<void *> wd; watchdog<void *> wd;
wd.start([&](void *) -> void { wd.start([&](void *) -> void {
falco_logger::log(LOG_NOTICE, "output channels still blocked, discarding all remaining notifications\n"); falco_logger::log(LOG_NOTICE, "output channels still blocked, discarding all remaining notifications\n");
#ifndef __EMSCRIPTEN__
m_queue.clear(); m_queue.clear();
#endif
this->push_ctrl(falco_outputs::ctrl_msg_type::CTRL_MSG_STOP); this->push_ctrl(falco_outputs::ctrl_msg_type::CTRL_MSG_STOP);
}); });
wd.set_timeout(m_timeout, nullptr); wd.set_timeout(m_timeout, nullptr);
@@ -266,11 +279,18 @@ inline void falco_outputs::push_ctrl(ctrl_msg_type cmt)
inline void falco_outputs::push(const ctrl_msg& cmsg) inline void falco_outputs::push(const ctrl_msg& cmsg)
{ {
#ifndef __EMSCRIPTEN__
if (!m_queue.try_push(cmsg)) if (!m_queue.try_push(cmsg))
{ {
fprintf(stderr, "Fatal error: Output queue reached maximum capacity. Exiting.\n"); fprintf(stderr, "Fatal error: Output queue reached maximum capacity. Exiting.\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#else
for (auto o : m_outputs)
{
process_msg(o, cmsg);
}
#endif
} }
// todo(leogr,leodido): this function is not supposed to throw exceptions, and with "noexcept", // todo(leogr,leodido): this function is not supposed to throw exceptions, and with "noexcept",
@@ -289,12 +309,27 @@ void falco_outputs::worker() noexcept
do do
{ {
// Block until a message becomes available. // Block until a message becomes available.
#ifndef __EMSCRIPTEN__
m_queue.pop(cmsg); m_queue.pop(cmsg);
#endif
for(const auto o : m_outputs) for(auto o : m_outputs)
{ {
wd.set_timeout(timeout, o->get_name()); wd.set_timeout(timeout, o->get_name());
try try
{
process_msg(o, cmsg);
}
catch(const std::exception &e)
{
falco_logger::log(LOG_ERR, o->get_name() + ": " + std::string(e.what()) + "\n");
}
}
wd.cancel_timeout();
} while(cmsg.type != ctrl_msg_type::CTRL_MSG_STOP);
}
inline void falco_outputs::process_msg(falco::outputs::abstract_output* o, const ctrl_msg& cmsg)
{ {
switch(cmsg.type) switch(cmsg.type)
{ {
@@ -312,11 +347,3 @@ void falco_outputs::worker() noexcept
falco_logger::log(LOG_DEBUG, "Outputs worker received an unknown message type\n"); falco_logger::log(LOG_DEBUG, "Outputs worker received an unknown message type\n");
} }
} }
catch(const std::exception &e)
{
falco_logger::log(LOG_ERR, o->get_name() + ": " + std::string(e.what()) + "\n");
}
}
wd.cancel_timeout();
} while(cmsg.type != ctrl_msg_type::CTRL_MSG_STOP);
}

View File

@@ -24,7 +24,9 @@ limitations under the License.
#include "falco_engine.h" #include "falco_engine.h"
#include "outputs.h" #include "outputs.h"
#include "formats.h" #include "formats.h"
#ifndef __EMSCRIPTEN__
#include "tbb/concurrent_queue.h" #include "tbb/concurrent_queue.h"
#endif
/*! /*!
\brief This class acts as the primary interface between a program and the \brief This class acts as the primary interface between a program and the
@@ -105,9 +107,10 @@ private:
ctrl_msg_type type; ctrl_msg_type type;
}; };
#ifndef __EMSCRIPTEN__
typedef tbb::concurrent_bounded_queue<ctrl_msg> falco_outputs_cbq; typedef tbb::concurrent_bounded_queue<ctrl_msg> falco_outputs_cbq;
falco_outputs_cbq m_queue; falco_outputs_cbq m_queue;
#endif
std::thread m_worker_thread; std::thread m_worker_thread;
inline void push(const ctrl_msg& cmsg); inline void push(const ctrl_msg& cmsg);
@@ -115,4 +118,5 @@ private:
void worker() noexcept; void worker() noexcept;
void stop_worker(); void stop_worker();
void add_output(falco::outputs::config oc); void add_output(falco::outputs::config oc);
inline void process_msg(falco::outputs::abstract_output* o, const ctrl_msg& cmsg);
}; };

View File

@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
#include <memory>
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>

View File

@@ -62,14 +62,17 @@ struct message
class abstract_output class abstract_output
{ {
public: public:
virtual ~abstract_output() {} virtual ~abstract_output() = default;
void init(const config& oc, bool buffered, const std::string& hostname, bool json_output) virtual bool init(const config& oc, bool buffered, const std::string& hostname, bool json_output, std::string &err)
{ {
m_oc = oc; m_oc = oc;
m_buffered = buffered; m_buffered = buffered;
m_hostname = hostname; m_hostname = hostname;
m_json_output = json_output; m_json_output = json_output;
err = "";
return true;
} }
// Return the output's name as per its configuration. // Return the output's name as per its configuration.

View File

@@ -18,26 +18,40 @@ limitations under the License.
#include "logger.h" #include "logger.h"
#include "banned.h" // This raises a compilation error when certain functions are used #include "banned.h" // This raises a compilation error when certain functions are used
void falco::outputs::output_http::output(const message *msg) #define CHECK_RES(fn) res = res == CURLE_OK ? fn : res
{
CURL *curl = NULL;
CURLcode res = CURLE_FAILED_INIT;
struct curl_slist *slist1;
slist1 = NULL;
curl = curl_easy_init(); static size_t noop_write_callback(void *contents, size_t size, size_t nmemb, void *userp)
if(curl)
{ {
// We don't want to echo anything. Just return size of bytes ignored
return size * nmemb;
}
bool falco::outputs::output_http::init(const config& oc, bool buffered, const std::string& hostname, bool json_output, std::string &err)
{
if (!falco::outputs::abstract_output::init(oc, buffered, hostname, json_output, err)) {
return false;
}
m_curl = nullptr;
m_http_headers = nullptr;
CURLcode res = CURLE_FAILED_INIT;
m_curl = curl_easy_init();
if(!m_curl)
{
falco_logger::log(LOG_ERR, "libcurl failed to initialize the handle: " + std::string(curl_easy_strerror(res)));
return false;
}
if(m_json_output) if(m_json_output)
{ {
slist1 = curl_slist_append(slist1, "Content-Type: application/json"); m_http_headers = curl_slist_append(m_http_headers, "Content-Type: application/json");
} else {
slist1 = curl_slist_append(slist1, "Content-Type: text/plain");
} }
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1); else
if(res == CURLE_OK)
{ {
m_http_headers = curl_slist_append(m_http_headers, "Content-Type: text/plain");
}
res = curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_http_headers);
// if the URL is quoted the quotes should be removed to satisfy libcurl expected format // if the URL is quoted the quotes should be removed to satisfy libcurl expected format
std::string unquotedUrl = m_oc.options["url"]; std::string unquotedUrl = m_oc.options["url"];
if (!unquotedUrl.empty() && ( if (!unquotedUrl.empty() && (
@@ -47,62 +61,64 @@ void falco::outputs::output_http::output(const message *msg)
{ {
unquotedUrl = libsinsp::filter::unescape_str(unquotedUrl); unquotedUrl = libsinsp::filter::unescape_str(unquotedUrl);
} }
res = curl_easy_setopt(curl, CURLOPT_URL, unquotedUrl.c_str()); CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_URL, unquotedUrl.c_str()));
}
if(res == CURLE_OK) CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_USERAGENT, m_oc.options["user_agent"].c_str()));
{ CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, -1L));
res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg->msg.c_str());
}
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_USERAGENT, m_oc.options["user_agent"].c_str());
}
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
}
if(res == CURLE_OK)
{
if(m_oc.options["insecure"] == std::string("true")) if(m_oc.options["insecure"] == std::string("true"))
{ {
res = curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER, 0L); CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L));
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 0L));
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
}
}
} }
if(res == CURLE_OK) if(m_oc.options["mtls"] == std::string("true"))
{ {
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSLCERT, m_oc.options["client_cert"].c_str()));
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSLKEY, m_oc.options["client_key"].c_str()));
}
if (!m_oc.options["ca_cert"].empty()) if (!m_oc.options["ca_cert"].empty())
{ {
res = curl_easy_setopt(curl, CURLOPT_CAINFO, m_oc.options["ca_cert"].c_str()); CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_CAINFO, m_oc.options["ca_cert"].c_str()));
}else if(!m_oc.options["ca_bundle"].empty())
{
res = curl_easy_setopt(curl, CURLOPT_CAINFO, m_oc.options["ca_bundle"].c_str());
}else{
res = curl_easy_setopt(curl, CURLOPT_CAPATH, m_oc.options["ca_path"].c_str());
} }
else if(!m_oc.options["ca_bundle"].empty())
{
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_CAINFO, m_oc.options["ca_bundle"].c_str()));
}
else
{
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_CAPATH, m_oc.options["ca_path"].c_str()));
} }
if(res == CURLE_OK) if(m_oc.options["echo"] == std::string("false"))
{ {
res = curl_easy_perform(curl); // If echo==true, libcurl defaults to fwrite to stdout, ie: echoing
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, noop_write_callback));
} }
if(res != CURLE_OK) if(res != CURLE_OK)
{ {
falco_logger::log(LOG_ERR, "libcurl error: " + std::string(curl_easy_strerror(res))); err = "libcurl error: " + std::string(curl_easy_strerror(res));
return false;
} }
curl_easy_cleanup(curl); return true;
curl = NULL; }
curl_slist_free_all(slist1);
slist1 = NULL; void falco::outputs::output_http::output(const message *msg)
{
CURLcode res = curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, msg->msg.c_str());
CHECK_RES(curl_easy_perform(m_curl));
if(res != CURLE_OK)
{
falco_logger::log(LOG_ERR, "libcurl failed to perform call: " + std::string(curl_easy_strerror(res)));
} }
} }
void falco::outputs::output_http::cleanup()
{
curl_easy_cleanup(m_curl);
m_curl = nullptr;
curl_slist_free_all(m_http_headers);
m_http_headers = nullptr;
}

View File

@@ -25,7 +25,13 @@ namespace outputs
class output_http : public abstract_output class output_http : public abstract_output
{ {
void output(const message *msg); bool init(const config& oc, bool buffered, const std::string& hostname, bool json_output, std::string &err) override;
void output(const message *msg) override;
void cleanup() override;
private:
CURL *m_curl;
struct curl_slist *m_http_headers;
}; };
} // namespace outputs } // namespace outputs

View File

@@ -32,6 +32,7 @@ limitations under the License.
// overflows here. Threads calling stats_writer::handle() will just // overflows here. Threads calling stats_writer::handle() will just
// check that this value changed since their last observation. // check that this value changed since their last observation.
static std::atomic<stats_writer::ticker_t> s_timer((stats_writer::ticker_t) 0); static std::atomic<stats_writer::ticker_t> s_timer((stats_writer::ticker_t) 0);
static timer_t s_timerid;
static void timer_handler(int signum) static void timer_handler(int signum)
{ {
@@ -51,25 +52,29 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err)
return false; return false;
} }
timer_t timerid;
struct sigevent sev = {}; struct sigevent sev = {};
/* Create the timer */ /* Create the timer */
sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGALRM; sev.sigev_signo = SIGALRM;
sev.sigev_value.sival_ptr = &timerid; sev.sigev_value.sival_ptr = &s_timerid;
if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) == -1) { #ifndef __EMSCRIPTEN__
// delete any previously set timer
timer_delete(s_timerid);
if (timer_create(CLOCK_MONOTONIC, &sev, &s_timerid) == -1) {
err = std::string("Could not create periodic timer: ") + strerror(errno); err = std::string("Could not create periodic timer: ") + strerror(errno);
return false; return false;
} }
#endif
timer.it_value.tv_sec = interval_msec / 1000; timer.it_value.tv_sec = interval_msec / 1000;
timer.it_value.tv_nsec = (interval_msec % 1000) * 1000 * 1000; timer.it_value.tv_nsec = (interval_msec % 1000) * 1000 * 1000;
timer.it_interval = timer.it_value; timer.it_interval = timer.it_value;
if (timer_settime(timerid, 0, &timer, NULL) == -1) { #ifndef __EMSCRIPTEN__
if (timer_settime(s_timerid, 0, &timer, NULL) == -1) {
err = std::string("Could not set up periodic timer: ") + strerror(errno); err = std::string("Could not set up periodic timer: ") + strerror(errno);
return false; return false;
} }
#endif
return true; return true;
} }
@@ -102,7 +107,9 @@ stats_writer::stats_writer(
if (m_initialized) if (m_initialized)
{ {
#ifndef __EMSCRIPTEN__
m_worker = std::thread(&stats_writer::worker, this); m_worker = std::thread(&stats_writer::worker, this);
#endif
} }
} }
@@ -110,11 +117,17 @@ stats_writer::~stats_writer()
{ {
if (m_initialized) if (m_initialized)
{ {
#ifndef __EMSCRIPTEN__
stop_worker(); stop_worker();
#endif
if (!m_config->m_metrics_output_file.empty()) if (!m_config->m_metrics_output_file.empty())
{ {
m_file_output.close(); m_file_output.close();
} }
// delete timerID and reset timer
#ifndef __EMSCRIPTEN__
timer_delete(s_timerid);
#endif
} }
} }
@@ -131,11 +144,13 @@ void stats_writer::stop_worker()
inline void stats_writer::push(const stats_writer::msg& m) inline void stats_writer::push(const stats_writer::msg& m)
{ {
#ifndef __EMSCRIPTEN__
if (!m_queue.try_push(m)) if (!m_queue.try_push(m))
{ {
fprintf(stderr, "Fatal error: Stats queue reached maximum capacity. Exiting.\n"); fprintf(stderr, "Fatal error: Stats queue reached maximum capacity. Exiting.\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#endif
} }
void stats_writer::worker() noexcept void stats_writer::worker() noexcept
@@ -151,7 +166,9 @@ void stats_writer::worker() noexcept
while(true) while(true)
{ {
// blocks until a message becomes availables // blocks until a message becomes availables
#ifndef __EMSCRIPTEN__
m_queue.pop(m); m_queue.pop(m);
#endif
if (m.stop) if (m.stop)
{ {
return; return;
@@ -247,7 +264,7 @@ void stats_writer::collector::get_metrics_output_fields_additional(
const scap_agent_info* agent_info = inspector->get_agent_info(); const scap_agent_info* agent_info = inspector->get_agent_info();
const scap_machine_info* machine_info = inspector->get_machine_info(); const scap_machine_info* machine_info = inspector->get_machine_info();
#ifndef MINIMAL_BUILD #if !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__)
/* Resource utilization, CPU and memory usage etc. */ /* Resource utilization, CPU and memory usage etc. */
uint32_t nstats = 0; uint32_t nstats = 0;
int32_t rc = 0; int32_t rc = 0;

View File

@@ -22,7 +22,9 @@ limitations under the License.
#include <sinsp.h> #include <sinsp.h>
#ifndef __EMSCRIPTEN__
#include "tbb/concurrent_queue.h" #include "tbb/concurrent_queue.h"
#endif
#include "falco_outputs.h" #include "falco_outputs.h"
#include "configuration.h" #include "configuration.h"
@@ -143,7 +145,9 @@ private:
uint64_t m_total_samples; uint64_t m_total_samples;
std::thread m_worker; std::thread m_worker;
std::ofstream m_file_output; std::ofstream m_file_output;
#ifndef __EMSCRIPTEN__
tbb::concurrent_bounded_queue<stats_writer::msg> m_queue; tbb::concurrent_bounded_queue<stats_writer::msg> m_queue;
#endif
std::shared_ptr<falco_outputs> m_outputs; std::shared_ptr<falco_outputs> m_outputs;
std::shared_ptr<const falco_configuration> m_config; std::shared_ptr<const falco_configuration> m_config;