Compare commits

..

44 Commits

Author SHA1 Message Date
Federico Di Pierro
1b62b5ccd1 new(docs): add changelog for 0.36.1 + 0.36.2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-10-27 11:45:46 +02:00
Federico Di Pierro
cc858f082f update(cmake): bumped libs to 0.13.4 tag.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-10-27 10:19:46 +02:00
Federico Di Pierro
2996c120c4 update(cmake): bumped libs to 0.13.3.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-10-25 10:05:39 +02:00
Andrea Terzolo
9eb611609a chore: bump libs to the latest tag 0.13.2
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-10-16 15:52:10 +02:00
Andrea Terzolo
f23b0c1a20 chore: bump libs to 0.13.2-rc1 tag
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-10-13 18:53:50 +02:00
Melissa Kilby
7b28b7acec feat(userspace): remove experimental outputs queue recovery strategies
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-10-13 18:53:50 +02:00
Melissa Kilby
aa4899c1e5 cleanup(userspace/falco): reset s_timerid_exists at stats_writer teardown
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-10-13 18:53:50 +02:00
Melissa Kilby
d454c8a1f4 chore: apply codespell fixes
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-10-13 18:53:50 +02:00
Melissa Kilby
0b48da30ca cleanup(userspace/falco): add more comments around timer_delete workaround
Co-authored-by: Federico Di Pierro <nierro92@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-10-13 18:53:50 +02:00
Melissa Kilby
0b761ff1da fix(userspace/falco): timer_delete() workaround due to bug in older GLIBC
Workaround for older GLIBC versions (< 2.35), where calling timer_delete()
with an invalid timer ID not returned by timer_create() causes a segfault because of
a bug in GLIBC (https://sourceware.org/bugzilla/show_bug.cgi?id=28257).

Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-10-13 18:53:50 +02:00
Luca Guerra
ee56a5c4e4 update(changelog): clarify rules, update with latest sync
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-25 19:13:05 +02:00
Luca Guerra
18e340bca8 new(docs): add changelog for 0.36.0
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-25 19:13:05 +02:00
Federico Di Pierro
0abef91f5d chore(cmake): bumped libs to 0.13.1.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-25 15:35:04 +02:00
dependabot[bot]
41c304a902 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `69c9be8` to `77ba57a`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](69c9be89d7...77ba57ab2c)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-25 15:35:04 +02:00
Andrea Terzolo
fa9c616e7f chore: bump submodule testing to 62edc65
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-25 15:35:04 +02:00
Luca Guerra
bff920d07f update(gha): add version for rn2md
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-25 15:35:04 +02:00
dependabot[bot]
df7159554c build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `6d3fcf0` to `69c9be8`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](6d3fcf0467...69c9be89d7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-25 15:35:04 +02:00
Federico Di Pierro
a6403606e5 update(cmake): bumped falcoctl to 0.6.2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-25 15:35:04 +02:00
Federico Di Pierro
cff980e8b8 chore: automatically attach release author to release body.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-25 15:35:04 +02:00
Federico Di Pierro
22344069ed chore(ci): added permissions to release-body job.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-25 15:35:04 +02:00
Federico Di Pierro
90f7e07182 chore(ci): only run release-body for latest releases, and properly override release name.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-25 15:35:04 +02:00
Federico Di Pierro
f89480ab3a new(ci): autogenerate release body.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-25 15:35:04 +02:00
Andrea Terzolo
e9d2771d72 fix(dockerfile): remove useless CMD
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 17:48:48 +02:00
Andrea Terzolo
bfabaadab6 chore: bump libs to the latest tag
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 17:48:48 +02:00
Andrea Terzolo
882e71a67c docs: add a warning for metrics
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 17:48:48 +02:00
Andrea Terzolo
45c55ae4e1 chore: bump to the latest libs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 17:48:48 +02:00
Luca Guerra
80d20bff28 update(falco): bundle rules 2.0.0
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-21 17:48:48 +02:00
Leonardo Grasso
db6b15f42c update: add SPDX license identifier
See https://github.com/falcosecurity/evolution/issues/318

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-21 17:48:48 +02:00
dependabot[bot]
38832d99e7 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `bea364e` to `6d3fcf0`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](bea364ef41...6d3fcf0467)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-21 17:48:48 +02:00
Federico Di Pierro
ac9af5427b update(cmake): bumped plugins to latest stable versions.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-21 17:48:48 +02:00
Andrea Terzolo
60f1b09e17 chore: bump to latest libs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 17:48:48 +02:00
dependabot[bot]
7f33ededa6 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `ee5fb38` to `bea364e`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](ee5fb38eba...bea364ef41)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-21 17:48:48 +02:00
Luca Guerra
c65718f7bc update(build): update falcoctl to 0.6.1
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-21 17:48:48 +02:00
dependabot[bot]
3c1928dff4 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `43580b4` to `ee5fb38`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](43580b4ceb...ee5fb38eba)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-21 17:48:48 +02:00
Federico Di Pierro
9f0cd50b6e update(cmake): bumped libs to 0.13.0-rc2 and driver to 6.0.1+driver.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-14 16:07:27 +02:00
Luca Guerra
393825295e fix(docker): get the driver loader legacy from the right directory
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-14 16:07:27 +02:00
Luca Guerra
7c7e54d1bb fix(build): set the right bucket and version for driver legacy
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-14 16:07:27 +02:00
Andrea Terzolo
803b5eea06 cleanup: thrown exceptions and avoid multiple logs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-14 16:07:27 +02:00
dependabot[bot]
78f32026f2 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `c6e01fa` to `43580b4`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](c6e01fa7a5...43580b4ceb)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-14 16:07:27 +02:00
dependabot[bot]
f989fdba52 build(deps): Bump submodules/falcosecurity-testing
Bumps [submodules/falcosecurity-testing](https://github.com/falcosecurity/testing) from `76d1743` to `30c3643`.
- [Commits](76d1743a0a...30c36439fc)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-14 16:07:27 +02:00
Luca Guerra
9e3e73c033 update(docs): add driver-loader-legacy to readme and fix bad c&p
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-14 16:07:27 +02:00
Jason Dellaluce
95e0465309 fix(userspace/falco): clearing full output queue
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-14 16:07:27 +02:00
dependabot[bot]
5d49ea77c0 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `d31dbc2` to `c6e01fa`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](d31dbc26ea...c6e01fa7a5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-14 16:07:27 +02:00
Leonardo Grasso
4479de5b9e docs: add LICENSE file
This commit creates a copy of https://github.com/falcosecurity/falco/blob/master/COPYING (which is kept for historical reasons) to address the recommendation reported by https://github.com/falcosecurity/evolution/issues/317

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-14 16:07:27 +02:00
115 changed files with 3310 additions and 2678 deletions

View File

@@ -1,5 +1,5 @@
[![LIBS](https://img.shields.io/badge/LIBS-LIBSVER-yellow)](https://github.com/falcosecurity/libs/releases/tag/LIBSVER)
[![DRIVER](https://img.shields.io/badge/DRIVER-DRIVERVER-yellow)](https://github.com/falcosecurity/libs/releases/tag/DRIVERVER)
![LIBS](https://img.shields.io/badge/LIBS-LIBSVER-yellow)
![DRIVER](https://img.shields.io/badge/DRIVER-DRIVERVER-yellow)
| Packages | Download |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |

View File

@@ -64,7 +64,7 @@ jobs:
needs: [build-dev]
steps:
- name: Checkout PR head ref
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
@@ -89,7 +89,7 @@ jobs:
needs: [build-dev]
steps:
- name: Checkout base ref
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.base_ref }}
@@ -97,10 +97,7 @@ jobs:
- name: Check Engine version
run: |
base_hash=$(grep CHECKSUM "./userspace/engine/falco_engine_version.h" | awk '{print $3}' | sed -e 's/"//g')
base_engine_ver_major=$(grep ENGINE_VERSION_MAJOR "./userspace/engine/falco_engine_version.h" | head -n 1 | awk '{print $3}' | sed -e 's/(//g' -e 's/)//g')
base_engine_ver_minor=$(grep ENGINE_VERSION_MINOR "./userspace/engine/falco_engine_version.h" | head -n 1 | awk '{print $3}' | sed -e 's/(//g' -e 's/)//g')
base_engine_ver_patch=$(grep ENGINE_VERSION_PATCH "./userspace/engine/falco_engine_version.h" | head -n 1 | awk '{print $3}' | sed -e 's/(//g' -e 's/)//g')
base_engine_ver="${base_engine_ver_major}.${base_engine_ver_minor}.${base_engine_ver_patch}"
base_engine_ver=$(grep ENGINE_VERSION "./userspace/engine/falco_engine_version.h" | awk '{print $3}' | sed -e 's/(//g' -e 's/)//g')
cur_hash=$(echo "${{ needs.build-dev.outputs.cmdout }}" | cut -d ' ' -f 2)
cur_engine_ver=$(echo "${{ needs.build-dev.outputs.cmdout }}" | cut -d ' ' -f 1)

View File

@@ -36,13 +36,13 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
with:
fetch-depth: 0
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -72,4 +72,4 @@ jobs:
popd
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
uses: github/codeql-action/analyze@v2

View File

@@ -5,8 +5,8 @@ jobs:
codespell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: codespell-project/actions-codespell@94259cd8be02ad2903ba34a22d9c13de21a74461 # v2.0
- uses: actions/checkout@v2
- uses: codespell-project/actions-codespell@master
with:
skip: .git
ignore_words_file: .codespellignore

View File

@@ -15,8 +15,8 @@ jobs:
outputs:
engine_version_changed: ${{ steps.filter.outputs.engine_version }}
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
- uses: actions/checkout@v2
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
@@ -31,7 +31,7 @@ jobs:
if: needs.paths-filter.outputs.engine_version_changed == 'false'
steps:
- name: Check driver Falco engine version
uses: mshick/add-pr-comment@7c0890544fb33b0bdd2e59467fbacb62e028a096 # v2.8.1
uses: mshick/add-pr-comment@v2
with:
message: |
This PR may bring feature or behavior changes in the Falco engine and may require the engine version to be bumped.

View File

@@ -1,26 +0,0 @@
name: Insecure API check
on:
pull_request:
branches:
- master
- 'release/**'
- 'maintainers/**'
jobs:
insecure-api:
name: check-insecure-api
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep:1.41.0@sha256:85956fbe795a0e8a3825d5252f175887c0e0c6ce7a766a07062c0fb68415cd67
steps:
- name: Checkout Falco ⤵️
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Scan PR for insecure API usage 🕵️
run: |
semgrep scan \
--error \
--metrics=off \
--baseline-commit ${{ github.event.pull_request.base.sha }} \
--config=./semgrep

View File

@@ -131,7 +131,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v4
- name: Extract LIBS and DRIVER versions
run: |
@@ -147,7 +147,7 @@ jobs:
sed -i s/FALCOVER/${{ github.event.release.tag_name }}/g release-body.md
- name: Generate release notes
uses: leodido/rn2md@0669e5f3b21492c11c2db43cd6e267566f5880f3
uses: leodido/rn2md@1a17f0e75758c15128a5146e8af5ca3a47209b3f
with:
milestone: ${{ github.event.release.tag_name }}
output: ./notes.md
@@ -161,7 +161,7 @@ jobs:
echo "#### Release Manager @${{ github.event.release.author.login }}" >> release-body.md
- name: Release
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15
uses: softprops/action-gh-release@v1
with:
body_path: ./release-body.md
tag_name: ${{ github.event.release.tag_name }}

View File

@@ -37,7 +37,7 @@ jobs:
cmdout: ${{ steps.run_cmd.outputs.out }}
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ inputs.git_ref }}

View File

@@ -32,10 +32,10 @@ jobs:
TARGETARCH: ${{ (inputs.arch == 'aarch64' && 'arm64') || 'amd64' }}
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
uses: docker/setup-buildx-action@v2
- name: Build no-driver image
run: |
@@ -87,7 +87,7 @@ jobs:
docker save docker.io/falcosecurity/falco-driver-loader-legacy:${{ inputs.arch }}-${{ inputs.tag }} --output /tmp/falco-driver-loader-legacy-${{ inputs.arch }}.tar
- name: Upload images tarballs
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@v3
with:
name: falco-images
path: /tmp/falco-*.tar

View File

@@ -23,7 +23,7 @@ jobs:
dnf install -y bpftool ca-certificates cmake make automake gcc gcc-c++ kernel-devel clang git pkg-config autoconf automake libbpf-devel
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
- name: Build modern BPF skeleton
run: |
@@ -32,7 +32,7 @@ jobs:
make ProbeSkeleton -j6
- name: Upload skeleton
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@v3
with:
name: bpf_probe_${{ inputs.arch }}.skel.h
path: skeleton-build/skel_dir/bpf_probe.skel.h
@@ -53,11 +53,10 @@ jobs:
yum install -y wget git make m4 rpm-build perl-IPC-Cmd
- name: Checkout
# It is not possible to upgrade the checkout action to versions >= v4.0.0 because of incompatibilities with centos 7's libc.
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
uses: actions/checkout@v3
- name: Download skeleton
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v3
with:
name: bpf_probe_${{ inputs.arch }}.skel.h
path: /tmp
@@ -98,21 +97,21 @@ jobs:
make package
- name: Upload Falco tar.gz package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@v3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}.tar.gz
path: |
${{ github.workspace }}/build/falco-*.tar.gz
- name: Upload Falco deb package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@v3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}.deb
path: |
${{ github.workspace }}/build/falco-*.deb
- name: Upload Falco rpm package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@v3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}.rpm
path: |
@@ -130,7 +129,7 @@ jobs:
apk add g++ gcc cmake make git bash perl linux-headers autoconf automake m4 libtool elfutils-dev libelf-static patch binutils bpftool clang
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
with:
fetch-depth: 0
@@ -155,7 +154,7 @@ jobs:
mv falco-${{ inputs.version }}-x86_64.tar.gz falco-${{ inputs.version }}-static-x86_64.tar.gz
- name: Upload Falco static package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@v3
with:
name: falco-${{ inputs.version }}-static-x86_64.tar.gz
path: |
@@ -172,12 +171,12 @@ jobs:
sudo DEBIAN_FRONTEND=noninteractive apt install cmake build-essential git emscripten -y
- name: Select node version
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
uses: actions/setup-node@v3
with:
node-version: 14
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
with:
fetch-depth: 0
@@ -211,74 +210,8 @@ jobs:
emmake make -j6 package
- name: Upload Falco WASM package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@v3
with:
name: falco-${{ inputs.version }}-wasm.tar.gz
path: |
${{ github.workspace }}/build/falco-${{ inputs.version }}-wasm.tar.gz
build-win32-package:
if: ${{ inputs.arch == 'x86_64' }}
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Prepare project
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DMINIMAL_BUILD=On -DUSE_BUNDLED_DEPS=On -DBUILD_FALCO_UNIT_TESTS=On -DFALCO_VERSION=${{ inputs.version }} ..
- name: Build project
run: |
cmake --build build --target package --config Release
- name: Run unit Tests
run: |
build/unit_tests/Release/falco_unit_tests.exe
- name: Upload Falco win32 installer
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-installer-${{ inputs.version }}-win32.exe
path: build/falco-*.exe
- name: Upload Falco win32 package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-win32.exe
path: |
${{ github.workspace }}/build/userspace/falco/Release/falco.exe
build-macos-package:
if: ${{ inputs.arch == 'x86_64' }}
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Prepare project
run: |
mkdir build
cd build
cmake -DMINIMAL_BUILD=On -DUSE_BUNDLED_DEPS=On -DBUILD_FALCO_UNIT_TESTS=On -DFALCO_VERSION=${{ inputs.version }} ..
- name: Build project
run: |
cmake --build build --target package
- name: Run unit Tests
run: |
sudo build/unit_tests/falco_unit_tests
- name: Upload Falco macos package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-macos
path: |
${{ github.workspace }}/build/userspace/falco/falco

View File

@@ -19,7 +19,7 @@ jobs:
version: ${{ steps.store_version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
with:
fetch-depth: 0

View File

@@ -26,10 +26,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
uses: docker/setup-buildx-action@v2
- name: Download images tarballs
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v3
with:
name: falco-images
path: /tmp/falco-images
@@ -39,13 +39,13 @@ jobs:
for img in /tmp/falco-images/falco-*.tar; do docker load --input $img; done
- name: Login to Docker Hub
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_SECRET }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: "arn:aws:iam::292999226676:role/github_actions-falco-ecr"
aws-region: us-east-1 # The region must be set to us-east-1 in order to access ECR Public.
@@ -57,7 +57,7 @@ jobs:
registry-type: public
- name: Setup Crane
uses: imjasonh/setup-crane@00c9e93efa4e1138c9a7a5c594acd6c75a2fbf0c # v0.3
uses: imjasonh/setup-crane@v0.3
with:
version: v0.15.1
@@ -76,14 +76,14 @@ jobs:
docker push docker.io/falcosecurity/falco-driver-loader-legacy:x86_64-${{ inputs.tag }}
- name: Create no-driver manifest on Docker Hub
uses: Noelware/docker-manifest-action@8e337e3cb9656abfcf20146b99706fd88716e942 # v0.4.0
uses: Noelware/docker-manifest-action@0.3.1
with:
inputs: docker.io/falcosecurity/falco-no-driver:${{ inputs.tag }}
images: docker.io/falcosecurity/falco-no-driver:aarch64-${{ inputs.tag }},docker.io/falcosecurity/falco-no-driver:x86_64-${{ inputs.tag }}
push: true
- name: Create distroless manifest on Docker Hub
uses: Noelware/docker-manifest-action@8e337e3cb9656abfcf20146b99706fd88716e942 # v0.4.0
uses: Noelware/docker-manifest-action@0.3.1
with:
inputs: docker.io/falcosecurity/falco-distroless:${{ inputs.tag }}
images: docker.io/falcosecurity/falco-distroless:aarch64-${{ inputs.tag }},docker.io/falcosecurity/falco-distroless:x86_64-${{ inputs.tag }}
@@ -94,21 +94,21 @@ jobs:
crane copy docker.io/falcosecurity/falco-no-driver:${{ inputs.tag }} docker.io/falcosecurity/falco:${{ inputs.tag }}-slim
- name: Create falco manifest on Docker Hub
uses: Noelware/docker-manifest-action@8e337e3cb9656abfcf20146b99706fd88716e942 # v0.4.0
uses: Noelware/docker-manifest-action@0.3.1
with:
inputs: docker.io/falcosecurity/falco:${{ inputs.tag }}
images: docker.io/falcosecurity/falco:aarch64-${{ inputs.tag }},docker.io/falcosecurity/falco:x86_64-${{ inputs.tag }}
push: true
- name: Create falco-driver-loader manifest on Docker Hub
uses: Noelware/docker-manifest-action@8e337e3cb9656abfcf20146b99706fd88716e942 # v0.4.0
uses: Noelware/docker-manifest-action@0.3.1
with:
inputs: docker.io/falcosecurity/falco-driver-loader:${{ inputs.tag }}
images: docker.io/falcosecurity/falco-driver-loader:aarch64-${{ inputs.tag }},docker.io/falcosecurity/falco-driver-loader:x86_64-${{ inputs.tag }}
push: true
- name: Create falco-driver-loader-legacy manifest on Docker Hub
uses: Noelware/docker-manifest-action@8e337e3cb9656abfcf20146b99706fd88716e942 # v0.4.0
uses: Noelware/docker-manifest-action@0.3.1
with:
inputs: docker.io/falcosecurity/falco-driver-loader-legacy:${{ inputs.tag }}
images: docker.io/falcosecurity/falco-driver-loader-legacy:aarch64-${{ inputs.tag }},docker.io/falcosecurity/falco-driver-loader-legacy:x86_64-${{ inputs.tag }}
@@ -116,7 +116,6 @@ jobs:
- name: Get Digests for images
id: digests
# We could probably use the docker-manifest-action output instead of recomputing those with crane
run: |
echo "falco-no-driver=$(crane digest docker.io/falcosecurity/falco-no-driver:${{ inputs.tag }})" >> $GITHUB_OUTPUT
echo "falco-distroless=$(crane digest docker.io/falcosecurity/falco-distroless:${{ inputs.tag }})" >> $GITHUB_OUTPUT
@@ -152,7 +151,7 @@ jobs:
- name: Setup Cosign
if: inputs.sign
uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2
uses: sigstore/cosign-installer@main
with:
cosign-release: v2.0.2

View File

@@ -23,64 +23,77 @@ env:
jobs:
publish-packages:
runs-on: ubuntu-latest
container: docker.io/library/fedora:38
container: docker.io/centos:7
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
- name: Install dependencies
run: |
dnf install rpm-sign expect which createrepo gpg python python-pip -y
pip install awscli==1.29.60
yum install epel-release -y
yum update -y
yum install rpm-sign expect which createrepo gpg python python-pip -y
pip install awscli==1.19.47
# Configure AWS role; see https://github.com/falcosecurity/test-infra/pull/1102
# Note: master CI can only push dev packages as we have 2 different roles for master and release.
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: "arn:aws:iam::292999226676:role/github_actions-falco${{ inputs.bucket_suffix }}-s3"
aws-region: ${{ env.AWS_S3_REGION }}
- name: Download RPM x86_64
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v3
with:
name: falco-${{ inputs.version }}-x86_64.rpm
path: /tmp/falco-build-rpm
- name: Download RPM aarch64
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v3
with:
name: falco-${{ inputs.version }}-aarch64.rpm
path: /tmp/falco-build-rpm
- name: Download binary x86_64
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v3
with:
name: falco-${{ inputs.version }}-x86_64.tar.gz
path: /tmp/falco-build-bin
- name: Download binary aarch64
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v3
with:
name: falco-${{ inputs.version }}-aarch64.tar.gz
path: /tmp/falco-build-bin
- name: Download static binary x86_64
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v3
with:
name: falco-${{ inputs.version }}-static-x86_64.tar.gz
path: /tmp/falco-build-bin-static
- name: Import gpg key
- name: Import gpg key
env:
GPG_KEY: ${{ secrets.GPG_KEY }}
run: printenv GPG_KEY | gpg --import -
- name: Sign rpms
run: |
rpmsign --define '_gpg_name Falcosecurity Package Signing' --addsign /tmp/falco-build-rpm/falco-*.rpm
echo "%_signature gpg" > ~/.rpmmacros
echo "%_gpg_name Falcosecurity Package Signing" >> ~/.rpmmacros
echo "%__gpg_sign_cmd %{__gpg} --force-v3-sigs --batch --no-armor --passphrase-fd 3 --no-secmem-warning -u \"%{_gpg_name}\" -sb --digest-algo sha256 %{__plaintext_filename}'" >> ~/.rpmmacros
cat > ~/sign <<EOF
#!/usr/bin/expect -f
spawn rpmsign --addsign {*}\$argv
expect -exact "Enter pass phrase: "
send -- "\n"
expect eof
EOF
chmod +x ~/sign
~/sign /tmp/falco-build-rpm/falco-*.rpm
rpm --qf %{SIGPGP:pgpsig} -qp /tmp/falco-build-rpm/falco-*.rpm | grep SHA256
- name: Publish rpm
run: |
./scripts/publish-rpm -f /tmp/falco-build-rpm/falco-${{ inputs.version }}-x86_64.rpm -f /tmp/falco-build-rpm/falco-${{ inputs.version }}-aarch64.rpm -r rpm${{ inputs.bucket_suffix }}
@@ -99,7 +112,7 @@ jobs:
container: docker.io/debian:stable
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
- name: Install dependencies
run: |
@@ -109,19 +122,19 @@ jobs:
# Configure AWS role; see https://github.com/falcosecurity/test-infra/pull/1102
# Note: master CI can only push dev packages as we have 2 different roles for master and release.
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: "arn:aws:iam::292999226676:role/github_actions-falco${{ inputs.bucket_suffix }}-s3"
aws-region: ${{ env.AWS_S3_REGION }}
- name: Download deb x86_64
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v3
with:
name: falco-${{ inputs.version }}-x86_64.deb
path: /tmp/falco-build-deb
- name: Download deb aarch64
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v3
with:
name: falco-${{ inputs.version }}-aarch64.deb
path: /tmp/falco-build-deb

View File

@@ -22,18 +22,18 @@ jobs:
runs-on: ${{ (inputs.arch == 'aarch64' && fromJSON('[ "self-hosted", "linux", "ARM64" ]')) || 'ubuntu-latest' }}
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: 'true'
- name: Setup Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
uses: actions/setup-go@v3
with:
go-version: '>=1.17.0'
- name: Download binary
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v3
with:
name: falco-${{ inputs.version }}${{ inputs.static && '-static' || '' }}-${{ inputs.arch }}.tar.gz
@@ -84,7 +84,7 @@ jobs:
- name: Test Summary
if: always() # run this even if previous step fails
uses: test-summary/action@62bc5c68de2a6a0d02039763b8c754569df99e3f # v2.1
uses: test-summary/action@v2
with:
paths: "submodules/falcosecurity-testing/report.xml"
show: "fail"

View File

@@ -1,79 +0,0 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
# Weekly on Mondays at 00:00.
- cron: '0 0 * * 1'
# The OSSF recommendation encourages to enable branch protection rules trigger
# to update the scorecard
# (https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection)
# but due to our GitHub org management this check is triggered too often and is
# therefore disabled.
# branch_protection_rule:
push:
branches: [ "master" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: "Checkout code"
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
with:
sarif_file: results.sarif

View File

@@ -7,7 +7,7 @@ jobs:
steps:
- name: Checkout ⤵️
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
@@ -25,7 +25,7 @@ jobs:
make -j4 cppcheck_htmlreport
- name: Upload reports ⬆️
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@v3
with:
name: static-analysis-reports
path: ./build/static-analysis-reports

View File

@@ -72,8 +72,6 @@ This is a list of production adopters of Falco (in alphabetical order):
* [Thales Group](https://www.thalesgroup.com) Thales is a global technology leader with more than 81,000 employees on five continents. The Thales Group is investing in digital and “deep tech” innovations Big Data, artificial intelligence, connectivity, cybersecurity and quantum technology to build a future we can all trust. In the past few years, the Cloud-Native paradigms and its frameworks and tools have challenged the way applications and services are developed, delivered, and instantiated. All sorts of services are container-based workloads managed by higher level layers of orchestration such as the Kubernetes environment. Thales is committed to develop Cloud-Native services and to provide its customers with security features that ensure their applications and services are protected against cyber threats. Falco is a framework that can help Thales' products and services reach the level of trust, security and safety our clients need.
* [Thought Machine](https://www.thoughtmachine.net) Thought Machine builds Vault Core and Vault Payments: cloud-native core and payments technology enabling banks and fintechs to remain competitive and flourish into the future. Vault Core and Vault Payments are the foundation layer of a bank's technology stack. They can run any bank, any product, and any payment set. Thought Machine uses Falco to perform cloud agnostic real time detections of suspicious container behaviour.
* [Vinted](https://vinted.com/) Vinted uses Falco to continuously monitor container activities, identifying security threats, and ensuring compliance. The container-native approach, rule-based real-time threat detection, community support, extensibility, and compliance capabilities are the main factors why we chose it to enhance Vinted Kubernetes security. Falco Sidekick is used to send critical and warning severity alerts to our incident management solution (RTIR).
* [Xenit AB](https://xenit.se/contact/) Xenit is a growth company with services within cloud and digital transformation. We provide an open-source Kubernetes framework that we leverage to help our customers get their applications to production as quickly and as securely as possible. We use Falco's detection capabilities to identify anomalous behaviour within our clusters in both Azure and AWS.
@@ -88,8 +86,6 @@ This is a list of production adopters of Falco (in alphabetical order):
* [StackRox](https://stackrox.io) is the industrys first Kubernetes-native security platform enabling organizations to build, deploy, and run cloud-native applications securely. The platform works with Kubernetes environments and integrates with DevOps and security tools, enabling teams to operationalize and secure their supply chain, infrastructure, and workloads. StackRox aims to harness containerized applications development speed while giving operations and security teams greater context and risk profiling. StackRox leverages cloud-native principles and declarative artifacts to automate DevSecOps best practices.
* [Wireshark](https://www.wireshark.org) is the world's most powerful and popular network protocol analyzer. The Wireshark team is combining Wireshark's features and Falco libs to create Logray, a cloud and system log analyzer with advanced filtering, capture, and scripting capabilities.
## Adding a name
If you would like to add your name to this file, submit a pull request with your change.

View File

@@ -6,7 +6,6 @@ Released on 2023-10-27
NO CHANGES IN FALCO, ALL CHANGES IN LIBS.
## v0.36.1
Released on 2023-10-16
@@ -24,7 +23,7 @@ Released on 2023-10-16
## v0.36.0
Released on 2023-09-26
Released on 2023-09-25
### Breaking Changes

View File

@@ -21,11 +21,7 @@ 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(BUILD_FALCO_UNIT_TESTS "Build falco unit tests" OFF)
if(WIN32)
set(CPACK_GENERATOR "NSIS") # this needs NSIS installed, and available
elseif (APPLE)
set(CPACK_GENERATOR "DragNDrop")
elseif(EMSCRIPTEN)
if(EMSCRIPTEN)
set(USE_BUNDLED_DEPS ON CACHE BOOL "" FORCE)
set(BUILD_DRIVER OFF CACHE BOOL "" FORCE)
set(ENABLE_DKMS OFF CACHE BOOL "" FORCE)
@@ -57,6 +53,9 @@ if (${EP_UPDATE_DISCONNECTED})
PROPERTY EP_UPDATE_DISCONNECTED TRUE)
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
# Elapsed time
# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time") # TODO(fntlnz, leodido): add a flag to enable this
@@ -84,7 +83,56 @@ else()
set(FALCO_TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR})
endif()
include(CompilerFlags)
if(NOT FALCO_EXTRA_DEBUG_FLAGS)
set(FALCO_EXTRA_DEBUG_FLAGS "-D_DEBUG")
endif()
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE)
if(CMAKE_BUILD_TYPE STREQUAL "debug")
set(KBUILD_FLAGS "${FALCO_EXTRA_DEBUG_FLAGS} ${FALCO_EXTRA_FEATURE_FLAGS}")
else()
set(CMAKE_BUILD_TYPE "release")
set(KBUILD_FLAGS "${FALCO_EXTRA_FEATURE_FLAGS}")
add_definitions(-DBUILD_TYPE_RELEASE)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
if(MINIMAL_BUILD)
set(MINIMAL_BUILD_FLAGS "-DMINIMAL_BUILD")
endif()
if(MUSL_OPTIMIZED_BUILD)
set(MUSL_FLAGS "-static -Os -fPIE -pie")
add_definitions(-DMUSL_OPTIMIZED)
endif()
# explicitly set hardening flags
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(FALCO_SECURITY_FLAGS "")
if(NOT EMSCRIPTEN)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -Wl,-z,relro,-z,now -fstack-protector-strong")
endif()
if(CMAKE_BUILD_TYPE STREQUAL "release")
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -D_FORTIFY_SOURCE=2")
endif()
set(CMAKE_COMMON_FLAGS "${FALCO_SECURITY_FLAGS} -Wall -ggdb ${FALCO_EXTRA_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}")
if(BUILD_WARNINGS_AS_ERRORS)
set(CMAKE_SUPPRESSED_WARNINGS
"-Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable -Wno-missing-field-initializers -Wno-sign-compare -Wno-type-limits -Wno-implicit-fallthrough -Wno-format-truncation -Wno-stringop-truncation -Wno-stringop-overflow -Wno-restrict"
)
set(CMAKE_COMMON_FLAGS "${CMAKE_COMMON_FLAGS} -Wextra -Werror ${CMAKE_SUPPRESSED_WARNINGS}")
endif()
set(CMAKE_C_FLAGS "${CMAKE_COMMON_FLAGS}")
set(CMAKE_CXX_FLAGS "-std=c++17 ${CMAKE_COMMON_FLAGS} -Wno-class-memaccess")
set(CMAKE_C_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
set(PACKAGE_NAME "falco")
set(DRIVER_NAME "falco")
@@ -116,6 +164,9 @@ include(falcosecurity-libs)
# compute FALCO_VERSION (depends on libs)
include(falco-version)
# jq
include(jq)
# nlohmann-json
include(njson)
@@ -141,8 +192,8 @@ if (NOT EMSCRIPTEN)
include(tbb)
endif()
include(zlib)
if (NOT MINIMAL_BUILD)
include(zlib)
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN)
include(cares)
include(protobuf)
@@ -152,16 +203,7 @@ if (NOT MINIMAL_BUILD)
endif()
# Installation
if(WIN32)
set(FALCO_INSTALL_CONF_FILE "%PROGRAMFILES%/${PACKAGE_NAME}-${FALCO_VERSION}/etc/falco/falco.yaml")
install(FILES falco.yaml DESTINATION etc/falco/ COMPONENT "${FALCO_COMPONENT_NAME}")
elseif(APPLE)
set(FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml")
install(FILES falco.yaml DESTINATION etc/falco/ COMPONENT "${FALCO_COMPONENT_NAME}")
else()
set(FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml")
install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
endif()
install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
if(NOT MINIMAL_BUILD)
# Coverage

View File

@@ -30,10 +30,6 @@ else()
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}")
endif()
if(WIN32)
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
endif()
# Built packages will include only the following components
set(CPACK_INSTALL_CMAKE_PROJECTS
"${CMAKE_CURRENT_BINARY_DIR};${FALCO_COMPONENT_NAME};${FALCO_COMPONENT_NAME};/"

View File

@@ -1,101 +0,0 @@
# SPDX-License-Identifier: Apache-2.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.
#
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
if(NOT FALCO_EXTRA_DEBUG_FLAGS)
set(FALCO_EXTRA_DEBUG_FLAGS "-D_DEBUG")
endif()
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE)
if(CMAKE_BUILD_TYPE STREQUAL "debug")
set(KBUILD_FLAGS "${FALCO_EXTRA_DEBUG_FLAGS} ${FALCO_EXTRA_FEATURE_FLAGS}")
else()
set(CMAKE_BUILD_TYPE "release")
set(KBUILD_FLAGS "${FALCO_EXTRA_FEATURE_FLAGS}")
add_definitions(-DBUILD_TYPE_RELEASE)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
if(MINIMAL_BUILD)
set(MINIMAL_BUILD_FLAGS "-DMINIMAL_BUILD")
endif()
if(MUSL_OPTIMIZED_BUILD)
set(MUSL_FLAGS "-static -Os -fPIE -pie")
add_definitions(-DMUSL_OPTIMIZED)
endif()
# explicitly set hardening flags
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(FALCO_SECURITY_FLAGS "")
if(LINUX)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -Wl,-z,relro,-z,now -fstack-protector-strong")
endif()
if(NOT MSVC)
if(CMAKE_BUILD_TYPE STREQUAL "release")
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -D_FORTIFY_SOURCE=2")
endif()
set(CMAKE_COMMON_FLAGS "${FALCO_SECURITY_FLAGS} -Wall -ggdb ${FALCO_EXTRA_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}")
if(BUILD_WARNINGS_AS_ERRORS)
set(CMAKE_SUPPRESSED_WARNINGS
"-Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable -Wno-missing-field-initializers -Wno-sign-compare -Wno-type-limits -Wno-implicit-fallthrough -Wno-format-truncation -Wno-stringop-truncation -Wno-stringop-overflow -Wno-restrict"
)
set(CMAKE_COMMON_FLAGS "${CMAKE_COMMON_FLAGS} -Wextra -Werror ${CMAKE_SUPPRESSED_WARNINGS}")
endif()
set(CMAKE_C_FLAGS "${CMAKE_COMMON_FLAGS}")
set(CMAKE_CXX_FLAGS "-std=c++17 ${CMAKE_COMMON_FLAGS} -Wno-class-memaccess")
set(CMAKE_C_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
else() # MSVC
set(MINIMAL_BUILD ON)
# The WIN32_LEAN_AND_MEAN define avoids possible macro pollution
# when a libsinsp consumer includes the windows.h header.
# See: https://stackoverflow.com/a/28380820
add_compile_definitions(
_HAS_STD_BYTE=0
_CRT_SECURE_NO_WARNINGS
WIN32
MINIMAL_BUILD
WIN32_LEAN_AND_MEAN
)
set(FALCOSECURITY_LIBS_COMMON_FLAGS "/EHsc /W3 /Zi /std:c++17")
set(FALCOSECURITY_LIBS_DEBUG_FLAGS "/MTd /Od")
set(FALCOSECURITY_LIBS_RELEASE_FLAGS "/MT")
set(CMAKE_C_FLAGS "${FALCOSECURITY_LIBS_COMMON_FLAGS}")
set(CMAKE_CXX_FLAGS "${FALCOSECURITY_LIBS_COMMON_FLAGS}")
set(CMAKE_C_FLAGS_DEBUG "${FALCOSECURITY_LIBS_DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${FALCOSECURITY_LIBS_DEBUG_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "${FALCOSECURITY_LIBS_RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${FALCOSECURITY_LIBS_RELEASE_FLAGS}")
endif()

View File

@@ -34,8 +34,8 @@ else()
# In case you want to test against another driver version (or branch, or commit) just pass the variable -
# ie., `cmake -DDRIVER_VERSION=dev ..`
if(NOT DRIVER_VERSION)
set(DRIVER_VERSION "7cbc03a535ead9d530f7b77ffd68766d5e22da74")
set(DRIVER_CHECKSUM "SHA256=94d110ad1738cce2635fd15d41701bea5e061fd9a5a4be3f2ee8ec7a28fe50cc")
set(DRIVER_VERSION "6.0.1+driver")
set(DRIVER_CHECKSUM "SHA256=2b4412b5053c8ed5bd1a9de745faa16ec0210dc65dc858af65951d4c8d22207c")
endif()
# cd /path/to/build && cmake /path/to/source

View File

@@ -35,8 +35,8 @@ else()
# In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable -
# ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "7cbc03a535ead9d530f7b77ffd68766d5e22da74")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=94d110ad1738cce2635fd15d41701bea5e061fd9a5a4be3f2ee8ec7a28fe50cc")
set(FALCOSECURITY_LIBS_VERSION "0.13.4")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=6b4a5c56422588b6ccaa53c976a9fbbcdb8d7918720c1b46207afe7ca46e8c29")
endif()
# cd /path/to/build && cmake /path/to/source
@@ -88,8 +88,6 @@ set(USE_BUNDLED_B64 ON CACHE BOOL "")
set(USE_BUNDLED_JSONCPP ON CACHE BOOL "")
set(USE_BUNDLED_VALIJSON ON CACHE BOOL "")
set(USE_BUNDLED_RE2 ON CACHE BOOL "")
set(USE_BUNDLED_UTHASH ON CACHE BOOL "")
set(USE_BUNDLED_TINYDIR ON CACHE BOOL "")
list(APPEND CMAKE_MODULE_PATH "${FALCOSECURITY_LIBS_SOURCE_DIR}/cmake/modules")
@@ -97,15 +95,12 @@ include(CheckSymbolExists)
check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY)
if(HAVE_STRLCPY)
message(STATUS "Existing strlcpy and strlcat found, will *not* use local definition by setting -DHAVE_STRLCPY and -DHAVE_STRLCAT.")
message(STATUS "Existing strlcpy found, will *not* use local definition by setting -DHAVE_STRLCPY.")
add_definitions(-DHAVE_STRLCPY)
add_definitions(-DHAVE_STRLCAT)
else()
message(STATUS "No strlcpy and strlcat found, will use local definition")
message(STATUS "No strlcpy found, will use local definition")
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
include(driver)
endif()
include(driver)
include(libscap)
include(libsinsp)

View File

@@ -34,11 +34,7 @@ set(FALCOSECURITY_RULES_LOCAL_PATH "${PROJECT_BINARY_DIR}/falcosecurity-rules-lo
file(WRITE "${FALCOSECURITY_RULES_LOCAL_PATH}" "# Your custom rules!\n")
if(NOT DEFINED FALCO_ETC_DIR)
set(FALCO_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falco")
endif()
if(WIN32 OR APPLE)
set(FALCO_ETC_DIR "etc/falco")
set(FALCO_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falco")
endif()
if(NOT DEFINED FALCO_RULES_DEST_FILENAME)

View File

@@ -24,18 +24,13 @@ if(NOT USE_BUNDLED_DEPS)
else()
set(YAMLCPP_SRC "${PROJECT_BINARY_DIR}/yamlcpp-prefix/src/yamlcpp")
message(STATUS "Using bundled yaml-cpp in '${YAMLCPP_SRC}'")
if(NOT WIN32)
set(YAMLCPP_LIB "${YAMLCPP_SRC}/libyaml-cpp.a")
else()
set(YAMLCPP_LIB "${YAMLCPP_SRC}/${CMAKE_BUILD_TYPE}/yaml-cpp.lib")
endif()
set(YAMLCPP_LIB "${YAMLCPP_SRC}/libyaml-cpp.a")
set(YAMLCPP_INCLUDE_DIR "${YAMLCPP_SRC}/include")
ExternalProject_Add(
yamlcpp
URL "https://github.com/jbeder/yaml-cpp/archive/yaml-cpp-0.7.0.tar.gz"
URL_HASH "SHA256=43e6a9fcb146ad871515f0d0873947e5d497a1c9c60c58cb102a97b47208b7c3"
URL "https://github.com/jbeder/yaml-cpp/archive/yaml-cpp-0.6.2.tar.gz"
URL_HASH "SHA256=e4d8560e163c3d875fd5d9e5542b5fd5bec810febdcba61481fe5fc4e6b1fd05"
BUILD_BYPRODUCTS ${YAMLCPP_LIB}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DYAML_MSVC_SHARED_RT=Off -DYAML_BUILD_SHARED_LIBS=Off -DYAML_CPP_BUILD_TESTS=Off -DYAML_CPP_BUILD_TOOLS=OFF -DYAML_CPP_BUILD_CONTRIB=OFF -DCMAKE_DEBUG_POSTFIX=''
BUILD_IN_SOURCE 1
INSTALL_COMMAND "")
endif()

View File

@@ -27,8 +27,6 @@
# (Falco environment variables)
# Falco rules files
# rules_file
# Falco engine
# engine
# Falco plugins
# load_plugins
# plugins
@@ -65,10 +63,13 @@
# syscall_event_drops
# metrics
# Falco performance tuning (advanced)
# syscall_buf_size_preset [DEPRECATED]
# syscall_drop_failed_exit [DEPRECATED]
# syscall_buf_size_preset
# syscall_drop_failed_exit
# base_syscalls
# modern_bpf.cpus_for_each_syscall_buffer [DEPRECATED]
# modern_bpf.cpus_for_each_syscall_buffer
# Falco cloud orchestration systems integration
# metadata_download
# (Guidance for Kubernetes container engine command-line args settings)
################################
@@ -96,7 +97,7 @@
# - "HOST_ROOT": Specifies the prefix to the underlying host `/proc` filesystem
# when deploying Falco over a container with read-only host mounts instead of
# directly on the host. Defaults to "/host".
# - "FALCO_BPF_PROBE": DEPRECATED. Specify a custom path to the BPF object code file (`bpf`
# - "FALCO_BPF_PROBE": Specify a custom path to the BPF object code file (`bpf`
# driver). This is not needed for the modern_bpf driver.
# - "FALCO_HOSTNAME": Customize the hostname output field logged by Falco by
# setting the "FALCO_HOSTNAME" environment variable.
@@ -147,196 +148,6 @@ rules_file:
- /etc/falco/falco_rules.local.yaml
- /etc/falco/rules.d
################
# Falco engine #
################
# [Stable] `engine`
#
# --- [Description]
#
# Falco supports different engines to generate events.
# Choose the appropriate engine kind based on your system's configuration and requirements.
#
# Available engines:
# - `kmod`: Kernel Module (Kernel Module)
# - `ebpf`: eBPF (eBPF probe)
# - `modern_ebpf`: Modern eBPF (CO-RE eBPF probe)
# - `gvisor`: gVisor (gVisor sandbox)
# - `replay`: Replay a scap trace file
# - `none`: No event producer loaded, useful to run with plugins.
#
# Only one engine can be specified in the `kind` key.
# Moreover, for each engine multiple options might be available,
# grouped under engine-specific configuration keys.
# Some of them deserve an in-depth description:
#
################### `buf_size_preset`
#
# --- [Description]
#
# The syscall buffer index determines the size of the shared space between Falco
# and its drivers. This shared space serves as a temporary storage for syscall
# events, allowing them to be transferred from the kernel to the userspace
# efficiently. The buffer size for each online CPU is determined by the buffer
# index, and each CPU has its own dedicated buffer. Adjusting this index allows
# you to control the overall size of the syscall buffers.
#
# --- [Usage]
#
# The index 0 is reserved, and each subsequent index corresponds to an
# increasing size in bytes. For example, index 1 corresponds to a size of 1 MB,
# index 2 corresponds to 2 MB, and so on:
#
# [(*), 1 MB, 2 MB, 4 MB, 8 MB, 16 MB, 32 MB, 64 MB, 128 MB, 256 MB, 512 MB]
# ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
# | | | | | | | | | | |
# 0 1 2 3 4 5 6 7 8 9 10
#
#
# The buffer dimensions in bytes are determined by the following requirements:
# (1) a power of 2.
# (2) a multiple of your system_page_dimension.
# (3) greater than `2 * (system_page_dimension).
#
# The buffer size constraints may limit the usability of certain indexes. Let's
# consider an example to illustrate this:
#
# If your system has a page size of 1 MB, the first available buffer size would
# be 4 MB because 2 MB is exactly equal to 2 * (system_page_size), which is not
# sufficient as we require more than 2 * (system_page_size). In this example, it
# is evident that if the page size is 1 MB, the first index that can be used is 3.
#
# However, in most cases, these constraints do not pose a limitation, and all
# indexes from 1 to 10 can be used. You can check your system's page size using
# the Falco `--page-size` command-line option.
#
# --- [Suggestions]
#
# The buffer size was previously fixed at 8 MB (index 4). You now have the
# option to adjust the size based on your needs. Increasing the size, such as to
# 16 MB (index 5), can reduce syscall drops in heavy production systems, but may
# impact performance. Decreasing the size can speed up the system but may
# increase syscall drops. It's important to note that the buffer size is mapped
# twice in the process' virtual memory, so a buffer of 8 MB will result in a 16
# MB area in virtual memory. Use this parameter with caution and only modify it
# if the default size is not suitable for your use case.
#
################### `drop_failed_exit`
#
# --- [Description]
#
# Enabling this option in Falco allows it to drop failed system call exit events
# in the kernel drivers before pushing them onto the ring buffer. This
# optimization can result in lower CPU usage and more efficient utilization of
# the ring buffer, potentially reducing the number of event losses. However, it
# is important to note that enabling this option also means sacrificing some
# visibility into the system.
#
################### `cpus_for_each_buffer` (modern_ebpf only)
#
# --- [Description]
#
# The modern_bpf driver in Falco utilizes the new BPF ring buffer, which has a
# different memory footprint compared to the current BPF driver that uses the
# perf buffer. The Falco core maintainers have discussed the differences and
# their implications, particularly in Kubernetes environments where limits need
# to be carefully set to avoid interference with the Falco daemonset deployment
# from the OOM killer. Based on guidance received from the kernel mailing list,
# it is recommended to assign multiple CPUs to one buffer instead of allocating
# a buffer for each CPU individually. This helps optimize resource allocation
# and prevent potential issues related to memory usage.
#
# This is an index that controls how many CPUs you want to assign to a single
# syscall buffer (ring buffer). By default, for modern_bpf every syscall buffer
# is associated to 2 CPUs, so the mapping is 1:2. The modern BPF probe allows
# you to choose different mappings, for example, changing the value to `1`
# results in a 1:1 mapping and would mean one syscall buffer for each CPU (this
# is the default for the `bpf` driver).
#
# --- [Usage]
#
# You can choose an index from 0 to MAX_NUMBER_ONLINE_CPUs to set the dimension
# of the syscall buffers. The value 0 represents a single buffer shared among
# all online CPUs. It serves as a flexible option when the exact number of
# online CPUs is unknown. Here's an example to illustrate this:
#
# Consider a system with 7 online CPUs:
#
# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU)
#
# - `1` means a syscall buffer for each CPU so 7 buffers
#
# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU)
# | | | | | | |
# BUFFERs 0 1 2 3 4 5 6
#
# - `2` (Default value) means a syscall buffer for each CPU pair, so 4 buffers
#
# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU)
# | | | | | | |
# BUFFERs 0 0 1 1 2 2 3
#
# Please note that in this example, there are 4 buffers in total. Three of the
# buffers are associated with pairs of CPUs, while the last buffer is mapped to
# a single CPU. This arrangement is necessary because we have an odd number of
# CPUs.
#
# - `0` or `MAX_NUMBER_ONLINE_CPUs` mean a syscall buffer shared between all
# CPUs, so 1 buffer
#
# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU)
# | | | | | | |
# BUFFERs 0 0 0 0 0 0 0
#
# Moreover, you have the option to combine this parameter with
# `buf_size_preset` index. For instance, you can create a large shared
# syscall buffer of 512 MB (using buf_size_preset=10) that is
# allocated among all the online CPUs.
#
# --- [Suggestions]
#
# The default choice of index 2 (one syscall buffer for each CPU pair) was made
# because the modern bpf probe utilizes a different memory allocation strategy
# compared to the other two drivers (bpf and kernel module). However, you have
# the flexibility to experiment and find the optimal configuration for your
# system.
#
# When considering a fixed buf_size_preset and a fixed buffer dimension:
# - Increasing this configs value results in lower number of buffers and you can
# speed up your system and reduce memory usage
# - However, using too few buffers may increase contention in the kernel,
# leading to a slowdown.
#
# If you have low event throughputs and minimal drops, reducing the number of
# buffers (higher `cpus_for_each_buffer`) can lower the memory footprint.
#
engine:
kind: kmod
kmod:
buf_size_preset: 4
drop_failed_exit: false
ebpf:
# path to the elf file to load.
probe: /root/.falco/falco-bpf.o
buf_size_preset: 4
drop_failed_exit: false
modern_ebpf:
cpus_for_each_buffer: 2
buf_size_preset: 4
drop_failed_exit: false
replay:
# path to the capture file to replay (eg: /path/to/file.scap)
capture_file: ""
gvisor:
# A Falco-compatible configuration file can be generated with
# '--gvisor-generate-config' and utilized for both runsc and Falco.
config: ""
# 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.
root: ""
#################
# Falco plugins #
#################
@@ -359,10 +170,11 @@ engine:
#
# Please note that if your intention is to enrich Falco syscall logs with fields
# such as `k8s.ns.name`, `k8s.pod.name`, and `k8s.pod.*`, you do not need to use
# the `k8saudit` plugin. This information is automatically extracted from
# the container runtime socket. The `k8saudit` plugin is specifically designed
# to integrate with Kubernetes audit logs and is not required for basic enrichment
# of syscall logs with Kubernetes-related fields.
# the `k8saudit` plugin nor the `-k`/`-K` Kubernetes metadata enrichment. This
# information is automatically extracted from the container runtime socket. The
# `k8saudit` plugin is specifically designed to integrate with Kubernetes audit
# logs and is not required for basic enrichment of syscall logs with
# Kubernetes-related fields.
#
# --- [Usage]
#
@@ -461,6 +273,34 @@ json_include_tags_property: true
# output mechanism. By default, buffering is disabled (false).
buffered_outputs: false
# [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
# 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.
# The following options control the mechanism:
# - rate: the number of tokens (i.e. right to send a notification) gained per
# second. When 0, the throttling mechanism is disabled. Defaults to 0.
# - max_burst: the maximum number of tokens outstanding. Defaults to 1000.
#
# For example, setting the rate to 1 allows Falco to send up to 1000
# notifications initially, followed by 1 notification per second. The burst
# capacity is fully restored after 1000 seconds of no activity.
#
# Throttling can be useful in various scenarios, such as preventing notification
# floods, managing system load, controlling event processing, or complying with
# rate limits imposed by external systems or APIs. It allows for better resource
# utilization, avoids overwhelming downstream systems, and helps maintain a
# balanced and controlled flow of notifications.
#
# With the default settings, the throttling mechanism is disabled.
outputs:
rate: 0
max_burst: 1000
# [Experimental] `rule_matching`
#
# The `rule_matching` configuration key's values are:
@@ -680,8 +520,6 @@ webserver:
# the appropriate number of threads based on the number of online cores in the system.
threadiness: 0
listen_port: 8765
# Can be an IPV4 or IPV6 address, defaults to IPV4
listen_address: 0.0.0.0
k8s_healthz_endpoint: /healthz
ssl_enabled: false
ssl_certificate: /etc/falco/falco.pem
@@ -961,15 +799,12 @@ metrics:
convert_memory_to_mb: true
include_empty_values: false
#######################################
# Falco performance tuning (advanced) #
#######################################
# [DEPRECATED] `syscall_buf_size_preset`
#
# Deprecated in favor of engine.{kmod,ebpf,modern_ebpf}.buf_size_preset.
# This config is evaluated only if the default `engine` config block is not changed,
# otherwise it is ignored.
# [Stable] `syscall_buf_size_preset`
#
# --- [Description]
#
@@ -1021,14 +856,10 @@ metrics:
# if the default size is not suitable for your use case.
syscall_buf_size_preset: 4
# [DEPRECATED] `syscall_drop_failed_exit`
#
# Deprecated in favor of engine.{kmod,ebpf,modern_ebpf}.drop_failed_exit.
# This config is evaluated only if the default `engine` config block is not changed,
# otherwise it is ignored.
# [Experimental] `syscall_drop_failed_exit`
#
# Enabling this option in Falco allows it to drop failed system call exit events
# in the kernel drivers before pushing them onto the ring buffer. This
# in the kernel driver before pushing them onto the ring buffer. This
# optimization can result in lower CPU usage and more efficient utilization of
# the ring buffer, potentially reducing the number of event losses. However, it
# is important to note that enabling this option also means sacrificing some
@@ -1150,11 +981,7 @@ base_syscalls:
custom_set: []
repair: false
# [DEPRECATED] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only
#
# Deprecated in favor of engine.modern_ebpf.cpus_for_each_buffer.
# This config is evaluated only if the default `engine` config block is not changed,
# otherwise it is ignored.
# [Stable] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only
#
# --- [Description]
#
@@ -1234,6 +1061,35 @@ base_syscalls:
modern_bpf:
cpus_for_each_syscall_buffer: 2
#################################################
# Falco cloud orchestration systems integration #
#################################################
# [Stable] `metadata_download`
#
# When connected to an orchestrator like Kubernetes, Falco has the capability to
# collect metadata and enrich system call events with contextual data. The
# parameters mentioned here control the downloading process of this metadata.
#
# Please note that support for Mesos is deprecated, so these parameters
# currently apply only to Kubernetes. When using Falco with Kubernetes, you can
# enable this functionality by using the `-k` or `-K` command-line flag.
#
# However, it's worth mentioning that for important Kubernetes metadata fields
# such as namespace or pod name, these fields are automatically extracted from
# the container runtime, providing the necessary enrichment for common use cases
# of syscall-based threat detection.
#
# In summary, the `-k` flag is typically not required for most scenarios involving
# Kubernetes workload owner enrichment. The `-k` flag is primarily used when
# additional metadata is required beyond the standard fields, catering to more
# specific use cases, see https://falco.org/docs/reference/rules/supported-fields/#field-class-k8s.
metadata_download:
max_mb: 100
chunk_wait_us: 1000
watch_freq_sec: 1
# [Stable] Guidance for Kubernetes container engine command-line args settings
#
# Modern cloud environments, particularly Kubernetes, heavily rely on

View File

@@ -1,44 +0,0 @@
# MIT License
#
# Copyright (c) 2022 raptor
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
rules:
- id: raptor-insecure-api-gets
metadata:
author: Marco Ivaldi <raptor@0xdeadbeef.info>
references:
- https://cwe.mitre.org/data/definitions/242
- https://cwe.mitre.org/data/definitions/120
confidence: HIGH
message: >-
The program calls a function that can never be guaranteed to work
safely.
Certain functions behave in dangerous ways regardless of how they are
used. Functions in this category were often implemented without
taking security concerns into account. The gets() function is unsafe
because it does not perform bounds checking on the size of its input.
An attacker can easily send arbitrarily-sized input to gets() and
overflow the destination buffer.
severity: ERROR
languages:
- c
- cpp
pattern: gets(...)

View File

@@ -1,57 +0,0 @@
# MIT License
#
# Copyright (c) 2022 raptor
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
rules:
- id: raptor-insecure-api-sprintf-vsprintf
metadata:
author: Marco Ivaldi <raptor@0xdeadbeef.info>
references:
- https://cwe.mitre.org/data/definitions/676
- https://cwe.mitre.org/data/definitions/120
- https://cwe.mitre.org/data/definitions/787
- https://g.co/kgs/PCHQjJ
confidence: HIGH
message: >-
The program invokes a potentially dangerous function that could
introduce a vulnerability if it is used incorrectly, but the function
can also be used safely.
A buffer overflow condition exists when a program attempts to put
more data in a buffer than it can hold, or when a program attempts to
put data in a memory area outside of the boundaries of a buffer. The
simplest type of error, and the most common cause of buffer
overflows, is the classic case in which the program copies the buffer
without restricting how much is copied. Other variants exist, but the
existence of a classic overflow strongly suggests that the programmer
is not considering even the most basic of security protections.
severity: ERROR
languages:
- c
- cpp
patterns:
- pattern-either:
- pattern: sprintf($BUF, $FMT, ...)
- pattern: vsprintf($BUF, $FMT, ...)
# swprintf() and vswprintf() should have a size parameter
- metavariable-regex:
metavariable: $FMT
# NOTE: some format string modifiers are not handled
regex: '(".*%l?s.*"|".*%S.*"|[a-zA-Z_][a-zA-Z0-9_]*)'

View File

@@ -1,59 +0,0 @@
# MIT License
#
# Copyright (c) 2022 raptor
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
rules:
- id: raptor-insecure-api-strcpy-stpcpy-strcat
metadata:
author: Marco Ivaldi <raptor@0xdeadbeef.info>
references:
- https://cwe.mitre.org/data/definitions/676
- https://cwe.mitre.org/data/definitions/120
- https://cwe.mitre.org/data/definitions/787
- https://g.co/kgs/PCHQjJ
confidence: HIGH
message: >-
The program invokes a potentially dangerous function that could
introduce a vulnerability if it is used incorrectly, but the function
can also be used safely.
A buffer overflow condition exists when a program attempts to put
more data in a buffer than it can hold, or when a program attempts to
put data in a memory area outside of the boundaries of a buffer. The
simplest type of error, and the most common cause of buffer
overflows, is the classic case in which the program copies the buffer
without restricting how much is copied. Other variants exist, but the
existence of a classic overflow strongly suggests that the programmer
is not considering even the most basic of security protections.
In the Falco codebase you can use the safer alternative strlcpy().
severity: ERROR
languages:
- c
- cpp
patterns:
- pattern-either:
- pattern: strcpy(...)
- pattern: stpcpy(...)
- pattern: strcat(...)
- pattern: wcscpy(...)
- pattern: wcpcpy(...)
- pattern: wcscat(...)
- pattern-not: $FUN($BUF, "...", ...)

View File

@@ -1,18 +0,0 @@
rules:
- id: falco-insecure-api-strn
metadata:
references:
- https://cwe.mitre.org/data/definitions/120
confidence: HIGH
message: >-
The libc function strncpy and strncat are not used in the Falco codebase as they are error prone.
Read more: https://www.cisa.gov/uscert/bsi/articles/knowledge/coding-practices/strncpy-and-strncat .
In the Falco codebase you can use the safer alternatives strlcpy() and strlcat().
severity: ERROR
languages:
- c
- cpp
patterns:
- pattern-either:
- pattern: strncpy(...)
- pattern: strncat(...)

View File

@@ -27,18 +27,10 @@ FetchContent_MakeAvailable(googletest)
file(GLOB_RECURSE ENGINE_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/engine/*.cpp)
file(GLOB_RECURSE FALCO_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/falco/*.cpp)
# Create a libscap_test_var.h file with some variables used by our tests
# for example the kmod path or the bpf path.
configure_file (
"${CMAKE_CURRENT_SOURCE_DIR}/falco_test_var.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/falco_test_var.h"
)
set(FALCO_UNIT_TESTS_SOURCES
"${ENGINE_TESTS}"
falco/test_configuration.cpp
falco/app/actions/test_select_event_sources.cpp
falco/app/actions/test_load_config.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
@@ -53,7 +45,6 @@ set(FALCO_UNIT_TESTS_INCLUDES
${CMAKE_SOURCE_DIR}/userspace
${CMAKE_BINARY_DIR}/userspace/falco # we need it to include indirectly `config_falco.h` file
${CMAKE_SOURCE_DIR}/userspace/engine # we need it to include indirectly `falco_common.h` file
"${CMAKE_CURRENT_BINARY_DIR}" # we need it to include `falco_test_var.h`
)
set(FALCO_UNIT_TESTS_DEPENDENCIES

View File

@@ -72,22 +72,3 @@ TEST(FalcoUtils, parse_prometheus_interval)
*/
ASSERT_EQ(falco::utils::parse_prometheus_interval("200"), 0UL);
}
TEST(FalcoUtils, decode_url)
{
ASSERT_EQ(
falco::utils::decode_uri("https://www.example.com?key1=value+1&key2=value%40%21%242&key3=value%253", true),
"https://www.example.com?key1=value 1&key2=value@!$2&key3=value%3");
ASSERT_EQ(
falco::utils::decode_uri("https://download.falco.org/?prefix=driver/3.0.1%2Bdriver/x86_64/", true),
"https://download.falco.org/?prefix=driver/3.0.1+driver/x86_64/");
ASSERT_EQ(
falco::utils::decode_uri("https://example.com/hello%20world", true),
"https://example.com/hello world");
ASSERT_EQ(
falco::utils::decode_uri("https://example.com/helloworld", true),
"https://example.com/helloworld");
}

View File

@@ -23,9 +23,9 @@ limitations under the License.
#define RULESET_2 2
/* Helpers methods */
static std::shared_ptr<gen_event_filter_factory> create_factory(filter_check_list& list)
static std::shared_ptr<gen_event_filter_factory> create_factory()
{
std::shared_ptr<gen_event_filter_factory> ret(new sinsp_filter_factory(NULL, list));
std::shared_ptr<gen_event_filter_factory> ret(new sinsp_filter_factory(NULL));
return ret;
}
@@ -53,8 +53,7 @@ static std::shared_ptr<gen_event_filter> create_filter(
TEST(Ruleset, enable_disable_rules_using_names)
{
sinsp_filter_check_list filterlist;
auto f = create_factory(filterlist);
auto f = create_factory();
auto r = create_ruleset(f);
auto ast = create_ast(f);
auto filter = create_filter(f, ast);
@@ -120,8 +119,7 @@ TEST(Ruleset, enable_disable_rules_using_names)
TEST(Ruleset, enable_disable_rules_using_tags)
{
sinsp_filter_check_list filterlist;
auto f = create_factory(filterlist);
auto f = create_factory();
auto r = create_ruleset(f);
auto ast = create_ast(f);
auto filter = create_filter(f, ast);

View File

@@ -19,5 +19,5 @@ limitations under the License.
#include <falco/app/state.h>
#include <falco/app/actions/actions.h>
#define EXPECT_ACTION_OK(r) { auto result = r; EXPECT_TRUE(result.success); EXPECT_TRUE(result.proceed); EXPECT_EQ(result.errstr, ""); }
#define EXPECT_ACTION_FAIL(r) { auto result = r; EXPECT_FALSE(result.success); EXPECT_FALSE(result.proceed); EXPECT_NE(result.errstr, ""); }
#define EXPECT_ACTION_OK(r) { EXPECT_TRUE(r.success); EXPECT_TRUE(r.proceed); EXPECT_EQ(r.errstr, ""); }
#define EXPECT_ACTION_FAIL(r) { EXPECT_FALSE(r.success); EXPECT_FALSE(r.proceed); EXPECT_NE(r.errstr, ""); }

View File

@@ -77,12 +77,11 @@ static std::shared_ptr<falco_engine> mock_engine_from_filters(const strset_t& fi
}
// create a falco engine and load the ruleset
sinsp_filter_check_list filterlist;
std::shared_ptr<falco_engine> res(new falco_engine());
auto filter_factory = std::shared_ptr<gen_event_filter_factory>(
new sinsp_filter_factory(nullptr, filterlist));
new sinsp_filter_factory(nullptr));
auto formatter_factory = std::shared_ptr<gen_event_formatter_factory>(
new sinsp_evt_formatter_factory(nullptr, filterlist));
new sinsp_evt_formatter_factory(nullptr));
res->add_source(s_sample_source, filter_factory, formatter_factory);
res->load_rules(dummy_rules, "dummy_rules.yaml");
res->enable_rule("", true, s_sample_ruleset);

View File

@@ -27,30 +27,30 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs)
FAIL() << "cannot get the number of online CPUs from the system\n";
}
// not modern ebpf engine, we do nothing
// not modern bpf engine, we do nothing
{
falco::app::state s;
s.config->m_engine_mode = engine_kind_t::MODERN_EBPF;
s.options.modern_bpf = false;
EXPECT_ACTION_OK(action(s));
}
// modern ebpf engine, with an invalid number of CPUs
// modern bpf engine, with an invalid number of CPUs
// default `m_cpus_for_each_syscall_buffer` to online CPU number
{
falco::app::state s;
s.config->m_engine_mode = engine_kind_t::MODERN_EBPF;
s.config->m_modern_ebpf.m_cpus_for_each_buffer = online_cpus + 1;
s.options.modern_bpf = true;
s.config->m_cpus_for_each_syscall_buffer = online_cpus + 1;
EXPECT_ACTION_OK(action(s));
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, online_cpus);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, online_cpus);
}
// modern ebpf engine, with a valid number of CPUs
// modern bpf engine, with an valid number of CPUs
// we don't modify `m_cpus_for_each_syscall_buffer`
{
falco::app::state s;
s.config->m_engine_mode = engine_kind_t::MODERN_EBPF;
s.config->m_modern_ebpf.m_cpus_for_each_buffer = online_cpus - 1;
s.options.modern_bpf = true;
s.config->m_cpus_for_each_syscall_buffer = online_cpus - 1;
EXPECT_ACTION_OK(action(s));
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, online_cpus - 1);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, online_cpus - 1);
}
}

View File

@@ -1,196 +0,0 @@
// SPDX-License-Identifier: Apache-2.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 ASSERTd by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "app_action_helpers.h"
#include "falco_test_var.h"
#ifndef __EMSCRIPTEN__
TEST(ActionLoadConfig, check_engine_config_is_correctly_parsed)
{
falco::app::state s = {};
s.options.conf_filename = NEW_ENGINE_CONFIG_CHANGED;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD);
// Check that kmod params are the ones specified in the config
EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 2);
EXPECT_FALSE(s.config->m_kmod.m_drop_failed_exit);
// Check that all other engine params are empty
EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty());
EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit);
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit);
EXPECT_TRUE(s.config->m_replay.m_capture_file.empty());
EXPECT_TRUE(s.config->m_gvisor.m_config.empty());
EXPECT_TRUE(s.config->m_gvisor.m_root.empty());
// Check that deprecated configs are always set since
EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 7);
EXPECT_TRUE(s.config->m_syscall_drop_failed_exit);
}
// Equal to the one above but checks that the command line options are not parsed
TEST(ActionLoadConfig, check_command_line_options_are_not_used)
{
falco::app::state s;
s.options.modern_bpf = true;
s.options.conf_filename = NEW_ENGINE_CONFIG_CHANGED;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD);
// Check that kmod params are the ones specified in the config
EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 2);
EXPECT_FALSE(s.config->m_kmod.m_drop_failed_exit);
// Check that all other engine params are empty
EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty());
EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit);
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit);
EXPECT_TRUE(s.config->m_replay.m_capture_file.empty());
EXPECT_TRUE(s.config->m_gvisor.m_config.empty());
EXPECT_TRUE(s.config->m_gvisor.m_root.empty());
// Check that deprecated configs are always set since
EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 7);
EXPECT_TRUE(s.config->m_syscall_drop_failed_exit);
}
TEST(ActionLoadConfig, check_kmod_with_syscall_configs)
{
falco::app::state s;
s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD);
// Kmod params should be populated with the syscall configs
// since the `engine` block is untouched.
EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 6);
EXPECT_TRUE(s.config->m_kmod.m_drop_failed_exit);
// Check that all other engine params are empty
EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty());
EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit);
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit);
EXPECT_TRUE(s.config->m_replay.m_capture_file.empty());
EXPECT_TRUE(s.config->m_gvisor.m_config.empty());
EXPECT_TRUE(s.config->m_gvisor.m_root.empty());
// Check that deprecated configs are populated
EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 3);
EXPECT_TRUE(s.config->m_syscall_drop_failed_exit);
}
TEST(ActionLoadConfig, check_override_command_line_modern)
{
falco::app::state s;
// The command line options should be correctly applied since the
// config is unchanged
s.options.modern_bpf = true;
s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
EXPECT_TRUE(s.is_modern_ebpf());
// Check that the modern ebpf engine uses the default syscall configs
// and not the ones in the `engine` block
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 3);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 6);
EXPECT_TRUE(s.config->m_modern_ebpf.m_drop_failed_exit);
// Kmod params should be always populated since the kmod is the default
EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 6);
EXPECT_TRUE(s.config->m_kmod.m_drop_failed_exit);
// Check that all other engine params are empty
EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty());
EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit);
EXPECT_TRUE(s.config->m_replay.m_capture_file.empty());
EXPECT_TRUE(s.config->m_gvisor.m_config.empty());
EXPECT_TRUE(s.config->m_gvisor.m_root.empty());
// Check that deprecated configs are populated
EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 3);
EXPECT_TRUE(s.config->m_syscall_drop_failed_exit);
}
TEST(ActionLoadConfig, check_override_command_line_gvisor)
{
falco::app::state s;
// The command line options should be correctly applied since the
// config is unchanged
s.options.gvisor_config = "config";
s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
EXPECT_TRUE(s.is_gvisor());
EXPECT_EQ(s.config->m_gvisor.m_config, "config");
EXPECT_TRUE(s.config->m_gvisor.m_root.empty());
// Kmod params should be always populated since the kmod is the default
EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 6);
EXPECT_TRUE(s.config->m_kmod.m_drop_failed_exit);
// Check that all other engine params are empty
EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty());
EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit);
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit);
EXPECT_TRUE(s.config->m_replay.m_capture_file.empty());
// Check that deprecated configs are populated
EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 3);
EXPECT_TRUE(s.config->m_syscall_drop_failed_exit);
}
#endif

View File

@@ -30,7 +30,7 @@ TEST(ActionSelectEventSources, pre_post_conditions)
// ignore source selection in capture mode
{
falco::app::state s;
s.config->m_engine_mode = engine_kind_t::REPLAY;
s.options.trace_filename = "some_capture_file.scap";
EXPECT_TRUE(s.is_capture_mode());
EXPECT_ACTION_OK(action(s));
}

View File

@@ -1,52 +0,0 @@
# SPDX-License-Identifier: Apache-2.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.
#
################
# Falco engine #
################
engine:
kind: kmod
kmod:
buf_size_preset: 2 # changed default value
drop_failed_exit: false
ebpf:
probe: /path/to/probe.o
buf_size_preset: 4
drop_failed_exit: false
modern_ebpf:
cpus_for_each_buffer: 2
buf_size_preset: 4
drop_failed_exit: false
replay:
capture_file: /path/to/file.scap
gvisor:
config: /path/to/gvisor_config.yaml
root: ""
#######################################
# Falco performance tuning (advanced) #
#######################################
# These configs should be ignored since we have changed the `engine` config
syscall_buf_size_preset: 6
syscall_drop_failed_exit: true
modern_bpf:
cpus_for_each_syscall_buffer: 7

View File

@@ -1,53 +0,0 @@
# SPDX-License-Identifier: Apache-2.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.
#
################
# Falco engine #
################
# Unchanged
engine:
kind: kmod
kmod:
buf_size_preset: 4
drop_failed_exit: false
ebpf:
probe: /path/to/probe.o
buf_size_preset: 4
drop_failed_exit: false
modern_ebpf:
cpus_for_each_buffer: 2
buf_size_preset: 4
drop_failed_exit: false
replay:
capture_file: /path/to/file.scap
gvisor:
config: /path/to/gvisor_config.yaml
root: ""
#######################################
# Falco performance tuning (advanced) #
#######################################
# The `engine` config is unchanged so these configs are used
syscall_buf_size_preset: 6
syscall_drop_failed_exit: true
modern_bpf:
cpus_for_each_syscall_buffer: 3

View File

@@ -18,12 +18,6 @@ limitations under the License.
#include <gtest/gtest.h>
#include <falco/configuration.h>
#ifdef _WIN32
#define SET_ENV_VAR(env_var_name, env_var_value) _putenv_s(env_var_name, env_var_value)
#else
#define SET_ENV_VAR(env_var_name, env_var_value) setenv(env_var_name, env_var_value, 1)
#endif
static std::string sample_yaml =
"base_value:\n"
" id: 1\n"
@@ -115,7 +109,7 @@ TEST(Configuration, configuration_environment_variables)
std::string env_var_value = "envVarValue";
std::string env_var_name = "ENV_VAR";
std::string default_value = "default";
SET_ENV_VAR(env_var_name.c_str(), env_var_value.c_str());
setenv(env_var_name.c_str(), env_var_value.c_str(), 1);
yaml_helper conf;
std::string sample_yaml =
@@ -178,85 +172,5 @@ TEST(Configuration, configuration_environment_variables)
ASSERT_EQ(base_value_2_list_2, "$UNSED_XX_X_X_VAR"); // Does not follow the `${VAR}` format, so should be treated as a regular string
/* Clear the set environment variable after testing */
SET_ENV_VAR(env_var_name.c_str(), env_var_value.c_str());
}
TEST(Configuration, configuration_webserver_ip)
{
falco_configuration falco_config;
std::vector<std::string> valid_addresses = {"127.0.0.1",
"1.127.0.1",
"1.1.127.1",
"1.1.1.127",
"::",
"::1",
"1200:0000:AB00:1234:0000:2552:7777:1313",
"1200::AB00:1234:0000:2552:7777:1313",
"1200:0000:AB00:1234::2552:7777:1313",
"21DA:D3:0:2F3B:2AA:FF:FE28:9C5A",
"FE80:0000:0000:0000:0202:B3FF:FE1E:8329",
"0.0.0.0",
"9.255.255.255",
"11.0.0.0",
"126.255.255.255",
"129.0.0.0",
"169.253.255.255",
"169.255.0.0",
"172.15.255.255",
"172.32.0.0",
"191.0.1.255",
"192.88.98.255",
"192.88.100.0",
"192.167.255.255",
"192.169.0.0",
"198.17.255.255",
"223.255.255.255"};
for (const std::string &address: valid_addresses) {
std::string option = "webserver.listen_address=";
option.append(address);
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back(option);
EXPECT_NO_THROW(falco_config.init(cmdline_config_options));
ASSERT_EQ(falco_config.m_webserver_listen_address, address);
}
std::vector<std::string> invalid_addresses = {"327.0.0.1",
"1.327.0.1",
"1.1.327.1",
"1.1.1.327",
"12 7.0.0.1",
"127. 0.0.1",
"127.0. 0.1",
"127.0.0. 1",
"!27.0.0.1",
"1200: 0000:AB00:1234:0000:2552:7777:1313",
"1200:0000: AB00:1234:0000:2552:7777:1313",
"1200:0000:AB00: 1234:0000:2552:7777:1313",
"1200:0000:AB00:1234: 0000:2552:7777:1313",
"1200:0000:AB00:1234:0000: 2552:7777:1313",
"1200:0000:AB00:1234:0000:2552: 7777:1313",
"1200:0000:AB00:1234:0000:2552:7777: 1313",
"1200:0000:AB00:1234:0000:2552:7777:131G",
"1200:0000:AB00:1234:0000:2552:77Z7:1313",
"1200:0000:AB00:1234:0000:2G52:7777:1313",
"1200:0000:AB00:1234:0O00:2552:7777:1313",
"1200:0000:AB00:H234:0000:2552:7777:1313",
"1200:0000:IB00:1234:0000:2552:7777:1313",
"1200:0O00:AB00:1234:0000:2552:7777:1313",
"12O0:0000:AB00:1234:0000:2552:7777:1313",};
for (const std::string &address: invalid_addresses) {
std::string option = "webserver.listen_address=";
option.append(address);
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back(option);
EXPECT_ANY_THROW(falco_config.init(cmdline_config_options));
}
unsetenv(env_var_name.c_str());
}

View File

@@ -1,4 +0,0 @@
#pragma once
#define NEW_ENGINE_CONFIG_CHANGED "${CMAKE_SOURCE_DIR}/unit_tests/falco/test_configs/new_engine_config_changed.yaml"
#define NEW_ENGINE_CONFIG_UNCHANGED "${CMAKE_SOURCE_DIR}/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml"

View File

@@ -16,6 +16,7 @@ set(FALCO_ENGINE_SOURCE_FILES
falco_engine.cpp
falco_load_result.cpp
falco_utils.cpp
json_evt.cpp
evttype_index_ruleset.cpp
formats.cpp
filter_details_resolver.cpp
@@ -35,7 +36,8 @@ endif()
add_dependencies(falco_engine yamlcpp njson)
target_include_directories(
if(MINIMAL_BUILD)
target_include_directories(
falco_engine
PUBLIC
"${NJSON_INCLUDE}"
@@ -44,5 +46,16 @@ target_include_directories(
"${LIBSINSP_INCLUDE_DIRS}"
"${YAMLCPP_INCLUDE_DIR}"
"${PROJECT_BINARY_DIR}/userspace/engine")
else()
target_include_directories(
falco_engine
PUBLIC
"${NJSON_INCLUDE}"
"${TBB_INCLUDE_DIR}"
"${LIBSCAP_INCLUDE_DIRS}"
"${LIBSINSP_INCLUDE_DIRS}"
"${YAMLCPP_INCLUDE_DIR}"
"${PROJECT_BINARY_DIR}/userspace/engine")
endif()
target_link_libraries(falco_engine "${FALCO_SINSP_LIBRARY}" "${YAMLCPP_LIB}")

48
userspace/engine/banned.h Normal file
View File

@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.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.
*/
#pragma once
// BAN macro defines `function` as an invalid token that says using
// the function is banned. This throws a compile time error when the
// function is used.
#define BAN(function) using_##function##_is_banned
// BAN_ALTERNATIVE is same as BAN but the message also provides an alternative
// function that the user could use instead of the banned function.
#define BAN_ALTERNATIVE(function, alternative) using_##function##_is_banned__use_##alternative##_instead
#undef strcpy
#define strcpy(a, b) BAN(strcpy)
#undef vsprintf
#define vsprintf(a, b, c) BAN_ALTERNATIVE(vsprintf, vsnprintf)
#undef sprintf
#define sprintf(a, b, ...) BAN_ALTERNATIVE(sprintf, snprintf)
#undef strcat
#define strcat(a, b) BAN(strcat)
#undef strncpy
#define strncpy(a, b, c) BAN(strncpy)
#undef swprintf
#define swprintf(a, b, c, ...) BAN_ALTERNATIVE(swprintf, snprintf)
#undef vswprintf
#define vswprintf(a, b, c, d) BAN_ALTERNATIVE(vswprintf, vsnprintf)

View File

@@ -16,6 +16,7 @@ limitations under the License.
*/
#include "evttype_index_ruleset.h"
#include "banned.h" // This raises a compilation error when certain functions are used
#include <algorithm>

View File

@@ -44,7 +44,9 @@ limitations under the License.
#include "formats.h"
#include "utils.h"
#include "banned.h" // This raises a compilation error when certain functions are used
#include "evttype_index_ruleset.h"
#include "filter_details_resolver.h"
const std::string falco_engine::s_default_ruleset = "falco-default-ruleset";
@@ -74,9 +76,9 @@ falco_engine::~falco_engine()
m_sources.clear();
}
sinsp_version falco_engine::engine_version()
uint32_t falco_engine::engine_version()
{
return sinsp_version(FALCO_ENGINE_VERSION);
return (uint32_t) FALCO_ENGINE_VERSION;
}
const falco_source* falco_engine::find_source(const std::string& name) const
@@ -189,60 +191,22 @@ void falco_engine::load_rules(const std::string &rules_content, bool verbose, bo
std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_content, const std::string &name)
{
rule_loader::configuration cfg(rules_content, m_sources, name);
cfg.min_priority = m_min_priority;
cfg.output_extra = m_extra;
cfg.replace_output_container_info = m_replace_container_info;
cfg.default_ruleset_id = m_default_ruleset_id;
// read rules YAML file and collect its definitions
rule_loader::reader reader;
if (reader.read(cfg, m_rule_collector))
{
// compile the definitions (resolve macro/list refs, exceptions, ...)
m_last_compile_output = std::make_unique<rule_loader::compiler::compile_output>();
rule_loader::compiler().compile(cfg, m_rule_collector, *m_last_compile_output.get());
// clear the rules known by the engine and each ruleset
m_rules.clear();
{
for (auto &src : m_sources)
{
src.ruleset = src.ruleset_factory->new_ruleset();
}
// add rules to the engine and the rulesets
for (const auto& rule : m_last_compile_output->rules)
{
// skip the rule if below the minimum priority
if (rule.priority > m_min_priority)
{
continue;
}
auto info = m_rule_collector.rules().at(rule.name);
if (!info)
{
// this is just defensive, it should never happen
throw falco_exception("can't find internal rule info at name: " + name);
}
// the rule is ok, we can add it to the engine and the rulesets
// note: the compiler should guarantee that the rule's condition
// is a valid sinsp filter
auto source = find_source(rule.source);
std::shared_ptr<gen_event_filter> filter(
sinsp_filter_compiler(source->filter_factory, rule.condition.get()).compile());
auto rule_id = m_rules.insert(rule, rule.name);
m_rules.at(rule_id)->id = rule_id;
source->ruleset->add(rule, filter, rule.condition);
// By default rules are enabled/disabled for the default ruleset
if(info->enabled)
{
source->ruleset->enable(rule.name, true, m_default_ruleset_id);
}
else
{
source->ruleset->disable(rule.name, true, m_default_ruleset_id);
}
}
rule_loader::compiler compiler;
m_rules.clear();
compiler.compile(cfg, m_rule_collector, m_rules);
}
if (cfg.res->successful())
@@ -505,25 +469,8 @@ std::size_t falco_engine::add_source(const std::string &source,
return m_sources.insert(src, source);
}
template <typename T> inline Json::Value sequence_to_json_array(const T& seq)
void falco_engine::describe_rule(std::string *rule, bool json) const
{
Json::Value ret = Json::arrayValue;
for (auto it = seq.begin(); it != seq.end(); it++)
{
ret.append(*it);
}
return ret;
}
void falco_engine::describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins, bool json) const
{
// use previously-loaded collector definitions and the compiled
// output of rules, macros, and lists.
if (m_last_compile_output == nullptr)
{
throw falco_exception("rules most be loaded before describing them");
}
if(!json)
{
static const char *rule_fmt = "%-50s %s\n";
@@ -551,9 +498,10 @@ void falco_engine::describe_rule(std::string *rule, const std::vector<std::share
return;
}
// use collected and compiled info to print a json output
std::unique_ptr<sinsp> insp(new sinsp());
Json::FastWriter writer;
std::string json_str;
if(!rule)
{
// In this case we build json information about
@@ -562,7 +510,7 @@ void falco_engine::describe_rule(std::string *rule, const std::vector<std::share
// Store required engine version
auto required_engine_version = m_rule_collector.required_engine_version();
output["required_engine_version"] = required_engine_version.version.as_string();
output["required_engine_version"] = std::to_string(required_engine_version.version);
// Store required plugin versions
Json::Value plugin_versions = Json::arrayValue;
@@ -589,33 +537,33 @@ void falco_engine::describe_rule(std::string *rule, const std::vector<std::share
// Store information about rules
Json::Value rules_array = Json::arrayValue;
for(const auto& r : m_last_compile_output->rules)
for(const auto& r : m_rules)
{
auto info = m_rule_collector.rules().at(r.name);
auto ri = m_rule_collector.rules().at(r.name);
Json::Value rule;
get_json_details(rule, r, *info, plugins);
get_json_details(r, *ri, insp.get(), rule);
// Append to rule array
rules_array.append(rule);
}
output["rules"] = rules_array;
// Store information about macros
Json::Value macros_array = Json::arrayValue;
for(const auto &m : m_last_compile_output->macros)
Json::Value macros_array;
for(const auto &m : m_rule_collector.macros())
{
auto info = m_rule_collector.macros().at(m.name);
Json::Value macro;
get_json_details(macro, m, *info, plugins);
get_json_details(m, macro);
macros_array.append(macro);
}
output["macros"] = macros_array;
// Store information about lists
Json::Value lists_array = Json::arrayValue;
for(const auto &l : m_last_compile_output->lists)
for(const auto &l : m_rule_collector.lists())
{
auto info = m_rule_collector.lists().at(l.name);
Json::Value list;
get_json_details(list, l, *info, plugins);
get_json_details(l, list);
lists_array.append(list);
}
output["lists"] = lists_array;
@@ -632,73 +580,68 @@ void falco_engine::describe_rule(std::string *rule, const std::vector<std::share
}
auto r = m_rules.at(ri->name);
Json::Value rule;
get_json_details(rule, *r, *ri, plugins);
get_json_details(*r, *ri, insp.get(), rule);
json_str = writer.write(rule);
}
fprintf(stdout, "%s", json_str.c_str());
}
void falco_engine::get_json_details(
Json::Value &out,
const falco_rule &r,
const rule_loader::rule_info &info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
void falco_engine::get_json_details(const falco_rule &r,
const rule_loader::rule_info &ri,
sinsp *insp,
Json::Value &rule) const
{
Json::Value rule_info;
// Fill general rule information
rule_info["name"] = r.name;
rule_info["condition"] = info.cond;
rule_info["condition"] = ri.cond;
rule_info["priority"] = format_priority(r.priority, false);
rule_info["output"] = info.output;
rule_info["output"] = r.output;
rule_info["description"] = r.description;
rule_info["enabled"] = info.enabled;
rule_info["enabled"] = ri.enabled;
rule_info["source"] = r.source;
rule_info["tags"] = sequence_to_json_array(info.tags);
out["info"] = rule_info;
Json::Value tags = Json::arrayValue;
for(const auto &t : ri.tags)
{
tags.append(t);
}
rule_info["tags"] = tags;
rule["info"] = rule_info;
// Parse rule condition and build the non-compiled AST
// Assumption: no error because rules have already been loaded.
auto ast = libsinsp::filter::parser(info.cond).parse();
// get details related to the condition's filter
filter_details details;
filter_details compiled_details;
// Parse rule condition and build the AST
// Assumption: no exception because rules have already been loaded.
auto ast = libsinsp::filter::parser(ri.cond).parse();
Json::Value json_details;
for(const auto &m : m_rule_collector.macros())
{
details.known_macros.insert(m.name);
compiled_details.known_macros.insert(m.name);
}
for(const auto &l : m_rule_collector.lists())
{
details.known_lists.insert(l.name);
compiled_details.known_lists.insert(l.name);
}
filter_details_resolver().run(ast.get(), details);
filter_details_resolver().run(r.condition.get(), compiled_details);
out["details"]["macros"] = sequence_to_json_array(details.macros);
out["details"]["lists"] = sequence_to_json_array(details.lists);
out["details"]["condition_operators"] = sequence_to_json_array(compiled_details.operators);
out["details"]["condition_fields"] = sequence_to_json_array(compiled_details.fields);
get_json_details(ast.get(), json_details);
rule["details"] = json_details;
// Get fields from output string
auto fmt = create_formatter(r.source, r.output);
std::vector<std::string> out_fields;
fmt->get_field_names(out_fields);
out["details"]["output_fields"] = sequence_to_json_array(out_fields);
Json::Value outputFields = Json::arrayValue;
for(const auto &of : out_fields)
{
outputFields.append(of);
}
rule["details"]["output_fields"] = outputFields;
// Get fields from exceptions
out["details"]["exception_fields"] = sequence_to_json_array(r.exception_fields);
Json::Value exception_fields = Json::arrayValue;
for(const auto &f : r.exception_fields)
{
exception_fields.append(f);
}
rule["details"]["exception_fields"] = exception_fields;
// Get names and operators from exceptions
std::unordered_set<std::string> exception_names;
std::unordered_set<std::string> exception_operators;
for(const auto &e : info.exceptions)
Json::Value exception_names = Json::arrayValue;
Json::Value exception_operators = Json::arrayValue;
for(const auto &e : ri.exceptions)
{
exception_names.insert(e.name);
exception_names.append(e.name);
if(e.comps.is_list)
{
for(const auto& c : e.comps.items)
@@ -708,237 +651,141 @@ void falco_engine::get_json_details(
// considering max two levels of lists
for(const auto& i : c.items)
{
exception_operators.insert(i.item);
exception_operators.append(i.item);
}
}
else
{
exception_operators.insert(c.item);
exception_operators.append(c.item);
}
}
}
else
{
exception_operators.insert(e.comps.item);
exception_operators.append(e.comps.item);
}
}
out["details"]["exception_names"] = sequence_to_json_array(exception_names);
out["details"]["exception_operators"] = sequence_to_json_array(exception_operators);
rule["details"]["exceptions"] = exception_names;
rule["details"]["exception_operators"] = exception_operators;
// Store event types
Json::Value events;
get_json_evt_types(events, info.source, r.condition.get());
out["details"]["events"] = events;
// Store compiled condition and output
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(r.condition.get());
out["details"]["output_compiled"] = r.output;
// Compute the plugins that are actually used by this rule. This is involves:
// - The rule's event source, that can be implemented by a plugin
// - The fields used in the rule's condition, output, and exceptions
// - The evt types used in the rule's condition checks, that can potentially
// match plugin-provided async events
Json::Value used_plugins;
// note: making a union of conditions's and output's fields
// note: the condition's AST accounts for all the resolved refs and exceptions
compiled_details.fields.insert(out_fields.begin(), out_fields.end());
get_json_used_plugins(used_plugins, info.source, compiled_details.evtnames, compiled_details.fields, plugins);
out["details"]["plugins"] = used_plugins;
if(ri.source == falco_common::syscall_source)
{
// Store event types
Json::Value events;
get_json_evt_types(ast.get(), events);
rule["details"]["events"] = events;
}
}
void falco_engine::get_json_details(
Json::Value& out,
const falco_macro& m,
const rule_loader::macro_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
void falco_engine::get_json_details(const rule_loader::macro_info& m,
Json::Value& macro) const
{
Json::Value macro_info;
macro_info["name"] = m.name;
macro_info["condition"] = info.cond;
out["info"] = macro_info;
macro_info["condition"] = m.cond;
macro["info"] = macro_info;
// Parse the macro condition and build the non-compiled AST
// Assumption: no exception because rules have already been loaded.
auto ast = libsinsp::filter::parser(info.cond).parse();
auto ast = libsinsp::filter::parser(m.cond).parse();
// get details related to the condition's filter
filter_details details;
filter_details compiled_details;
Json::Value json_details;
for(const auto &m : m_rule_collector.macros())
{
details.known_macros.insert(m.name);
compiled_details.known_macros.insert(m.name);
}
for(const auto &l : m_rule_collector.lists())
{
details.known_lists.insert(l.name);
compiled_details.known_lists.insert(l.name);
}
filter_details_resolver().run(ast.get(), details);
filter_details_resolver().run(m.condition.get(), compiled_details);
out["details"]["used"] = m.used;
out["details"]["macros"] = sequence_to_json_array(details.macros);
out["details"]["lists"] = sequence_to_json_array(details.lists);
out["details"]["condition_operators"] = sequence_to_json_array(compiled_details.operators);
out["details"]["condition_fields"] = sequence_to_json_array(compiled_details.fields);
get_json_details(ast.get(), json_details);
macro["details"] = json_details;
// Store event types
Json::Value events;
get_json_evt_types(events, "", m.condition.get());
out["details"]["events"] = events;
// Store compiled condition
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(m.condition.get());
// Compute the plugins that are actually used by this macro.
// Note: macros have no specific source, we need to set an empty list of used
// plugins because we can't be certain about their actual usage. For example,
// if a macro uses a plugin's field, we can't be sure which plugin actually
// is used until we resolve the macro ref in a rule providing a source for
// disambiguation.
out["details"]["plugins"] = Json::arrayValue;
get_json_evt_types(ast.get(), events);
macro["details"]["events"] = events;
}
void falco_engine::get_json_details(
Json::Value& out,
const falco_list& l,
const rule_loader::list_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
void falco_engine::get_json_details(const rule_loader::list_info& l,
Json::Value& list) const
{
Json::Value list_info;
list_info["name"] = l.name;
// note: the syntactic definitions still has the list refs unresolved
Json::Value items = Json::arrayValue;
std::unordered_set<std::string> lists;
for(const auto &i : info.items)
Json::Value lists = Json::arrayValue;
for(const auto &i : l.items)
{
// if an item is present in the syntactic def of a list, but not
// on the compiled_items of the same list, then we can assume it
// being a resolved list ref
if(std::find(l.items.begin(), l.items.end(), i) == l.items.end())
if(m_rule_collector.lists().at(i) != nullptr)
{
lists.insert(i);
lists.append(i);
continue;
}
items.append(i);
}
list_info["items"] = items;
out["info"] = list_info;
out["details"]["used"] = l.used;
out["details"]["lists"] = sequence_to_json_array(lists);
out["details"]["items_compiled"] = sequence_to_json_array(l.items);
out["details"]["plugins"] = Json::arrayValue; // always empty
list["info"] = list_info;
list["details"]["lists"] = lists;
}
void falco_engine::get_json_evt_types(
Json::Value& out,
const std::string& source,
libsinsp::filter::ast::expr* ast) const
void falco_engine::get_json_details(libsinsp::filter::ast::expr* ast,
Json::Value& output) const
{
// note: this duplicates part of the logic of evttype_index_ruleset,
// not good but it's our best option for now
if (source.empty() || source == falco_common::syscall_source)
filter_details details;
for(const auto &m : m_rule_collector.macros())
{
auto evtcodes = libsinsp::filter::ast::ppm_event_codes(ast);
evtcodes.insert(ppm_event_code::PPME_ASYNCEVENT_E);
auto syscodes = libsinsp::filter::ast::ppm_sc_codes(ast);
auto syscodes_to_evt_names = libsinsp::events::sc_set_to_event_names(syscodes);
auto evtcodes_to_evt_names = libsinsp::events::event_set_to_names(evtcodes, false);
out = sequence_to_json_array(unordered_set_union(syscodes_to_evt_names, evtcodes_to_evt_names));
details.known_macros.insert(m.name);
}
else
for(const auto &l : m_rule_collector.lists())
{
out = sequence_to_json_array(libsinsp::events::event_set_to_names(
{ppm_event_code::PPME_PLUGINEVENT_E, ppm_event_code::PPME_ASYNCEVENT_E}));
details.known_lists.insert(l.name);
}
// Resolve the AST details
filter_details_resolver resolver;
resolver.run(ast, details);
Json::Value macros = Json::arrayValue;
for(const auto &m : details.macros)
{
macros.append(m);
}
output["macros"] = macros;
Json::Value operators = Json::arrayValue;
for(const auto &o : details.operators)
{
operators.append(o);
}
output["operators"] = operators;
Json::Value condition_fields = Json::arrayValue;
for(const auto &f : details.fields)
{
condition_fields.append(f);
}
output["condition_fields"] = condition_fields;
Json::Value lists = Json::arrayValue;
for(const auto &l : details.lists)
{
lists.append(l);
}
output["lists"] = lists;
details.reset();
}
void falco_engine::get_json_used_plugins(
Json::Value& out,
const std::string& source,
const std::unordered_set<std::string>& evtnames,
const std::unordered_set<std::string>& fields,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
void falco_engine::get_json_evt_types(libsinsp::filter::ast::expr* ast,
Json::Value& output) const
{
// note: condition and output fields may have an argument, so
// we need to isolate the field names
std::unordered_set<std::string> fieldnames;
for (auto f: fields)
output = Json::arrayValue;
auto evtcodes = libsinsp::filter::ast::ppm_event_codes(ast);
auto syscodes = libsinsp::filter::ast::ppm_sc_codes(ast);
auto syscodes_to_evt_names = libsinsp::events::sc_set_to_event_names(syscodes);
auto evtcodes_to_evt_names = libsinsp::events::event_set_to_names(evtcodes, false);
for (const auto& n : unordered_set_union(syscodes_to_evt_names, evtcodes_to_evt_names))
{
auto argpos = f.find('[');
if (argpos != std::string::npos)
{
f = f.substr(0, argpos);
}
fieldnames.insert(f);
output.append(n);
}
std::unordered_set<std::string> used_plugins;
for (const auto& p : plugins)
{
bool used = false;
if (p->caps() & CAP_SOURCING)
{
// The rule's source is implemented by a plugin with event
// sourcing capability.
// Note: if Falco loads two plugins implementing the same source,
// they will both be included in the list.
if (!used && p->event_source() == source)
{
used_plugins.insert(p->name());
used = true;
}
}
if (!used && p->caps() & CAP_EXTRACTION)
{
// The rule uses a field implemented by a plugin with field
// extraction capability that is compatible with the rule's source.
// Note: here we're assuming that Falco will prevent loading
// plugins implementing fields with the same name for the same
// event source (implemented in init_inspectors app action).
if (sinsp_plugin::is_source_compatible(p->extract_event_sources(), source))
{
for (const auto &f : p->fields())
{
if (!used && fieldnames.find(f.m_name) != fieldnames.end())
{
used_plugins.insert(p->name());
used = true;
break;
}
}
}
}
if (!used && p->caps() & CAP_ASYNC)
{
// The rule matches an event type implemented by a plugin with
// async events capability that is compatible with the rule's source.
// Note: if Falco loads two plugins implementing async events with
// the same name, they will both be included in the list.
if (sinsp_plugin::is_source_compatible(p->async_event_sources(), source))
{
for (const auto &n : p->async_event_names())
{
if (!used && evtnames.find(n) != evtnames.end())
{
used_plugins.insert(p->name());
used = true;
break;
}
}
}
}
}
out = sequence_to_json_array(used_plugins);
}
void falco_engine::print_stats() const
{
std::string out;
@@ -1002,14 +849,14 @@ static bool check_plugin_requirement_alternatives(
{
sinsp_version req_version(req.version);
sinsp_version plugin_version(plugin.version);
if(!plugin_version.is_valid())
if(!plugin_version.m_valid)
{
err = "Plugin '" + plugin.name
+ "' has invalid version string '"
+ plugin.version + "'";
return false;
}
if (!plugin_version.compatible_with(req_version))
if (!plugin_version.check(req_version))
{
err = "Plugin '" + plugin.name
+ "' version '" + plugin.version

View File

@@ -39,8 +39,6 @@ limitations under the License.
#include "falco_source.h"
#include "falco_load_result.h"
#include "filter_details_resolver.h"
#include "rule_loader_reader.h"
#include "rule_loader_compiler.h"
//
// This class acts as the primary interface between a program and the
@@ -58,16 +56,7 @@ public:
// and rules file format it supports. This version will change
// any time the code that handles rules files, expression
// fields, etc, changes.
static sinsp_version engine_version();
// Engine version used to be represented as a simple progressive
// number. With the new semver schema, the number now represents
// the semver minor number. This function converts the legacy version
// number to the new semver schema.
static inline sinsp_version get_implicit_version(uint32_t minor)
{
return rule_loader::reader::get_implicit_engine_version(minor);
}
static uint32_t engine_version();
// Print to stdout (using printf) a description of each field supported by this engine.
// If source is non-empty, only fields for the provided source are printed.
@@ -136,7 +125,7 @@ public:
// Print details on the given rule. If rule is NULL, print
// details on all rules.
//
void describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins, bool json) const;
void describe_rule(std::string *rule, bool json) const;
//
// Print statistics on how many events matched each rule.
@@ -314,31 +303,18 @@ private:
inline bool should_drop_evt() const;
// Retrieve json details from rules, macros, lists
void get_json_details(
Json::Value& out,
const falco_rule& r,
const rule_loader::rule_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_details(
Json::Value& out,
const falco_macro& m,
const rule_loader::macro_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_details(
Json::Value& out,
const falco_list& l,
const rule_loader::list_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_evt_types(
Json::Value& out,
const std::string& source,
libsinsp::filter::ast::expr* ast) const;
void get_json_used_plugins(
Json::Value& out,
const std::string& source,
const std::unordered_set<std::string>& evttypes,
const std::unordered_set<std::string>& fields,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_details(const falco_rule& r,
const rule_loader::rule_info& ri,
sinsp* insp,
Json::Value& rule) const;
void get_json_details(const rule_loader::macro_info& m,
Json::Value& macro) const;
void get_json_details(const rule_loader::list_info& l,
Json::Value& list) const;
void get_json_details(libsinsp::filter::ast::expr* ast,
Json::Value& output) const;
void get_json_evt_types(libsinsp::filter::ast::expr* ast,
Json::Value& output) const;
rule_loader::collector m_rule_collector;
indexed_vector<falco_rule> m_rules;
@@ -348,8 +324,6 @@ private:
std::map<std::string, uint16_t> m_known_rulesets;
falco_common::priority_type m_min_priority;
std::unique_ptr<rule_loader::compiler::compile_output> m_last_compile_output;
//
// Here's how the sampling ratio and multiplier influence
// whether or not an event is dropped in

View File

@@ -15,18 +15,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#define __FALCO_ENGINE_STRINGIFY1(str) #str
#define __FALCO_ENGINE_STRINGIFY(str) __FALCO_ENGINE_STRINGIFY1(str)
// The version of this Falco engine
#define FALCO_ENGINE_VERSION_MAJOR 0
#define FALCO_ENGINE_VERSION_MINOR 27
#define FALCO_ENGINE_VERSION_PATCH 0
#define FALCO_ENGINE_VERSION \
__FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_MAJOR) "." \
__FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_MINOR) "." \
__FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_PATCH)
// The version of this Falco engine.
#define FALCO_ENGINE_VERSION (26)
// This is the result of running the following command:
// FALCO="falco -c ./falco.yaml"
@@ -34,4 +24,4 @@ limitations under the License.
// It represents the fields supported by this version of Falco,
// the event types, and the underlying driverevent schema. It's used to
// detetect changes in engine version in our CI jobs.
#define FALCO_ENGINE_CHECKSUM "dbc34e88ab420320994d85f155dee6baff2dd018aacc00e249f897edc8b1e0f4"
#define FALCO_ENGINE_CHECKSUM "98c6e665031b95c666a9ab02d5470e7008e8636bf02f4cc410912005b90dff5c"

View File

@@ -21,46 +21,6 @@ limitations under the License.
#include <string>
#include "falco_common.h"
#include <filter/ast.h>
/*!
\brief Represents a list in the Falco Engine.
The rule ID must be unique across all the lists loaded in the engine.
*/
struct falco_list
{
falco_list(): used(false), id(0) { }
falco_list(falco_list&&) = default;
falco_list& operator = (falco_list&&) = default;
falco_list(const falco_list&) = default;
falco_list& operator = (const falco_list&) = default;
~falco_list() = default;
bool used;
std::size_t id;
std::string name;
std::vector<std::string> items;
};
/*!
\brief Represents a macro in the Falco Engine.
The rule ID must be unique across all the macros loaded in the engine.
*/
struct falco_macro
{
falco_macro(): used(false), id(0) { }
falco_macro(falco_macro&&) = default;
falco_macro& operator = (falco_macro&&) = default;
falco_macro(const falco_macro&) = default;
falco_macro& operator = (const falco_macro&) = default;
~falco_macro() = default;
bool used;
std::size_t id;
std::string name;
std::shared_ptr<libsinsp::filter::ast::expr> condition;
};
/*!
\brief Represents a rule in the Falco Engine.
The rule ID must be unique across all the rules loaded in the engine.
@@ -72,7 +32,6 @@ struct falco_rule
falco_rule& operator = (falco_rule&&) = default;
falco_rule(const falco_rule&) = default;
falco_rule& operator = (const falco_rule&) = default;
~falco_rule() = default;
std::size_t id;
std::string source;
@@ -82,5 +41,4 @@ struct falco_rule
std::set<std::string> tags;
std::set<std::string> exception_fields;
falco_common::priority_type priority;
std::shared_ptr<libsinsp::filter::ast::expr> condition;
};

View File

@@ -20,9 +20,9 @@ limitations under the License.
#include <cstring>
#include <iomanip>
#include "falco_common.h"
#include "falco_utils.h"
#include "utils.h"
#include "banned.h" // This raises a compilation error when certain functions are used
#include <re2/re2.h>
@@ -160,81 +160,6 @@ void readfile(const std::string& filename, std::string& data)
return;
}
// URI-decodes the given string by replacing percent-encoded
// characters with the actual character. Returns the decoded string.
//
// When plus_as_space is true, non-encoded plus signs in the query are decoded as spaces.
// (http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1)
std::string decode_uri(const std::string& str, bool plus_as_space)
{
std::string decoded_str;
bool in_query = false;
std::string::const_iterator it = str.begin();
std::string::const_iterator end = str.end();
while(it != end)
{
char c = *it++;
if(c == '?')
{
in_query = true;
}
// spaces may be encoded as plus signs in the query
if(in_query && plus_as_space && c == '+')
{
c = ' ';
}
else if(c == '%')
{
if (it == end)
{
throw falco_exception("URI encoding: no hex digit following percent sign in " + str);
}
char hi = *it++;
if (it == end)
{
throw falco_exception("URI encoding: two hex digits must follow percent sign in " + str);
}
char lo = *it++;
if (hi >= '0' && hi <= '9')
{
c = hi - '0';
}
else if (hi >= 'A' && hi <= 'F')
{
c = hi - 'A' + 10;
}
else if (hi >= 'a' && hi <= 'f')
{
c = hi - 'a' + 10;
}
else
{
throw falco_exception("URI encoding: not a hex digit found in " + str);
}
c *= 16;
if (lo >= '0' && lo <= '9')
{
c += lo - '0';
}
else if (lo >= 'A' && lo <= 'F')
{
c += lo - 'A' + 10;
}
else if (lo >= 'a' && lo <= 'f')
{
c += lo - 'a' + 10;
}
else
{
throw falco_exception("URI encoding: not a hex digit");
}
}
decoded_str += c;
}
return decoded_str;
}
namespace network
{
bool is_unix_scheme(const std::string& url)

View File

@@ -52,8 +52,6 @@ void readfile(const std::string& filename, std::string& data);
uint32_t hardware_concurrency();
std::string decode_uri(const std::string& str, bool plus_as_space);
namespace network
{
static const std::string UNIX_SCHEME("unix://");

View File

@@ -19,36 +19,22 @@ limitations under the License.
using namespace libsinsp::filter;
std::string get_field_name(const std::string& name, const std::string& arg)
{
std::string fld = name;
if (!arg.empty())
{
fld += "[" + arg + "]";
}
return fld;
}
void filter_details::reset()
{
fields.clear();
macros.clear();
operators.clear();
lists.clear();
evtnames.clear();
}
void filter_details_resolver::run(ast::expr* filter, filter_details& details)
{
visitor v(details);
// note: we may have ASTs composed on only one macro ref
v.m_expect_macro = true;
filter->accept(&v);
}
void filter_details_resolver::visitor::visit(ast::and_expr* e)
{
m_expect_macro = false;
for(size_t i = 0; i < e->children.size(); i++)
{
m_expect_macro = true;
@@ -59,7 +45,6 @@ void filter_details_resolver::visitor::visit(ast::and_expr* e)
void filter_details_resolver::visitor::visit(ast::or_expr* e)
{
m_expect_macro = false;
for(size_t i = 0; i < e->children.size(); i++)
{
m_expect_macro = true;
@@ -85,50 +70,35 @@ void filter_details_resolver::visitor::visit(ast::list_expr* e)
}
}
}
if (m_expect_evtname)
{
for(const auto& item : e->values)
{
if(m_details.known_lists.find(item) == m_details.known_lists.end())
{
m_details.evtnames.insert(item);
}
}
}
}
void filter_details_resolver::visitor::visit(ast::binary_check_expr* e)
{
m_expect_macro = false;
m_details.fields.insert(get_field_name(e->field, e->arg));
m_details.fields.insert(e->field);
m_details.operators.insert(e->op);
m_expect_list = true;
m_expect_evtname = e->field == "evt.type" || e->field == "evt.asynctype";
e->value->accept(this);
m_expect_evtname = false;
m_expect_list = false;
}
void filter_details_resolver::visitor::visit(ast::unary_check_expr* e)
{
m_expect_macro = false;
m_details.fields.insert(get_field_name(e->field, e->arg));
m_details.fields.insert(e->field);
m_details.operators.insert(e->op);
}
void filter_details_resolver::visitor::visit(ast::value_expr* e)
{
if (m_expect_macro)
if(m_expect_macro)
{
if(m_details.known_macros.find(e->value) != m_details.known_macros.end())
auto it = m_details.known_macros.find(e->value);
if(it == m_details.known_macros.end())
{
m_details.macros.insert(e->value);
return;
}
// todo(jasondellaluce): should we throw an error if we
// encounter an unknown macro?
}
else if (m_expect_evtname)
{
m_details.evtnames.insert(e->value);
m_details.macros.insert(e->value);
}
}

View File

@@ -33,7 +33,6 @@ struct filter_details
std::unordered_set<std::string> macros;
std::unordered_set<std::string> operators;
std::unordered_set<std::string> lists;
std::unordered_set<std::string> evtnames;
void reset();
};
@@ -60,8 +59,7 @@ private:
visitor(filter_details& details) :
m_details(details),
m_expect_list(false),
m_expect_macro(false),
m_expect_evtname(false) {}
m_expect_macro(false) {}
visitor(visitor&&) = default;
visitor& operator = (visitor&&) = default;
visitor(const visitor&) = delete;
@@ -78,6 +76,5 @@ private:
filter_details& m_details;
bool m_expect_list;
bool m_expect_macro;
bool m_expect_evtname;
};
};

View File

@@ -19,6 +19,7 @@ limitations under the License.
#include "formats.h"
#include "falco_engine.h"
#include "banned.h" // This raises a compilation error when certain functions are used
falco_formats::falco_formats(std::shared_ptr<const falco_engine> engine,
bool json_include_output_property,

File diff suppressed because it is too large Load Diff

512
userspace/engine/json_evt.h Normal file
View File

@@ -0,0 +1,512 @@
// SPDX-License-Identifier: Apache-2.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.
*/
#pragma once
#include <memory>
#include <list>
#include <map>
#include <string>
#include <vector>
#include <set>
#include <utility>
#include <nlohmann/json.hpp>
#include "falco_common.h"
#include "prefix_search.h"
#include <sinsp.h>
class json_event : public gen_event
{
public:
json_event();
virtual ~json_event();
void set_jevt(nlohmann::json &evt, uint64_t ts);
const nlohmann::json &jevt();
uint64_t get_ts() const;
inline uint16_t get_source() const
{
return ESRC_K8S_AUDIT;
}
inline uint16_t get_type() const
{
// All k8s audit events have the single tag "1". - see falco_engine::process_k8s_audit_event
return ppm_event_code::PPME_PLUGINEVENT_E;
}
protected:
nlohmann::json m_jevt;
uint64_t m_event_ts;
};
namespace falco_k8s_audit {
//
// Given a raw json object, return a list of k8s audit event
// objects that represent the object. This method handles
// things such as EventList splitting.
//
// Returns true if the json object was recognized as a k8s
// audit event(s), false otherwise.
//
bool parse_k8s_audit_json(nlohmann::json &j, std::list<json_event> &evts, bool top=true);
};
// A class representing an extracted value or a value on the rhs of a
// filter_check. This intentionally doesn't use the same types as
// ppm_events_public.h to take advantage of actual classes instead of
// lower-level pointers pointing to syscall events and to allow for
// efficient set comparisons.
class json_event_value
{
public:
enum param_type {
JT_STRING,
JT_INT64,
JT_INT64_PAIR
};
json_event_value();
json_event_value(const std::string &val);
json_event_value(int64_t val);
virtual ~json_event_value();
param_type ptype() const;
std::string as_string() const;
bool operator==(const json_event_value &val) const;
bool operator!=(const json_event_value &val) const;
bool operator<(const json_event_value &val) const;
bool operator>(const json_event_value &val) const;
// Only meaningful for string types
bool startswith(const json_event_value &val) const;
bool contains(const json_event_value &val) const;
private:
param_type m_type;
static bool parse_as_pair_int64(std::pair<int64_t,int64_t> &pairval, const std::string &val);
static bool parse_as_int64(int64_t &intval, const std::string &val);
// The number of possible types is small so far, so sticking
// with separate vars
std::string m_stringval;
int64_t m_intval;
std::pair<int64_t,int64_t> m_pairval;
};
class json_event_filter_check : public gen_event_filter_check
{
public:
static std::string no_value;
enum index_mode
{
IDX_REQUIRED,
IDX_ALLOWED,
IDX_NONE
};
static std::vector<std::string> s_index_mode_strs;
enum index_type
{
IDX_KEY,
IDX_NUMERIC
};
static std::vector<std::string> s_index_type_strs;
// A struct describing a single filtercheck field ("ka.user")
struct field_info
{
std::string m_name;
std::string m_desc;
index_mode m_idx_mode;
index_type m_idx_type;
bool m_uses_paths;
// The variants allow for brace-initialization either
// with just the name/desc or additionally with index
// information
field_info();
field_info(std::string name, std::string desc);
field_info(std::string name, std::string desc, index_mode mode);
field_info(std::string name, std::string desc, index_mode mode, index_type itype);
field_info(std::string name, std::string desc, index_mode mode, index_type itype, bool uses_paths);
virtual ~field_info();
};
// A struct describing a group of filtercheck fields ("ka")
struct check_info
{
std::string m_name;
std::string m_shortdesc;
std::string m_desc;
std::list<field_info> m_fields;
};
json_event_filter_check();
virtual ~json_event_filter_check() = 0;
virtual int32_t parse_field_name(const char *str, bool alloc_state, bool needed_for_filtering);
void add_filter_value(const char *str, uint32_t len, uint32_t i = 0);
bool compare(gen_event *evt);
// This is adapted to support the new extract() method signature that
// supports extracting list of values, however json_evt was implemented
// to support this feature in the first place through the
// extracted_values_t structure. As such, for now this is only used for
// signature compliance, and always pushes a single value. The value pushed
// in the vector is a a const extracted_values_t* that points to the
// internal m_evalues. This is a temporary workaround to sync with the
// latest falcosecurity/libs development without re-designing the whole K8S
// support, which will eventually be refactored as a plugin in the future anyway.
bool extract(gen_event *evt, std::vector<extract_value_t>& values, bool sanitize_strings = true) final;
const std::string &field();
const std::string &idx();
// The combined size of the field, index, and surrounding
// brackets (e.g. ka.image[foo])
size_t parsed_size();
virtual const check_info &get_info() const = 0;
//
// Allocate a new check of the same type. Must be overridden.
//
virtual json_event_filter_check *allocate_new() = 0;
// Subclasses or extraction functions can call this method to add each extracted value.
void add_extracted_value(const std::string &val);
void add_extracted_value_num(int64_t val);
// After calling extract, you can call extracted_values to get
// the values extracted from an event.
typedef std::vector<json_event_value> values_t;
const values_t &extracted_values();
protected:
// Subclasses can override this method, calling
// add_extracted_value to add extracted values.
virtual bool extract_values(json_event *jevt);
static std::string json_as_string(const nlohmann::json &j);
// Subclasses can define field names that act as aliases for
// specific json pointer expressions e.g. ka.user ==
// jevt.value[/user/username]. This struct represents one of
// those aliases.
// An alias might define an alternative function to extract
// values instead of using a json pointer. An example is
// ka.uri.param, which parses the query string to extract
// key=value parameters.
typedef std::function<bool (const nlohmann::json &, json_event_filter_check &jchk)> extract_t;
struct alias
{
// The variants allow for brace-initialization either
// with just the pointer list or with a custom
// extraction function.
alias();
alias(std::list<nlohmann::json::json_pointer> ptrs);
alias(extract_t extract);
virtual ~alias();
// A json pointer used to extract a referenced value
// from a json object. The pointers are applied in
// order. After applying a pointer, if the resulting
// object is an array, each array member is considered
// for subsequent json pointers.
//
// This allows for "plucking" items out of an array
// selected by an earlier json pointer.
std::list<nlohmann::json::json_pointer> m_jptrs;
extract_t m_extract;
};
// This map defines the aliases defined by this filter check
// class.
//
// The version of parse_field_name in this base class will
// check a field specification against all the aliases.
virtual const std::unordered_map<std::string, alias> &get_aliases() const = 0;
//check_info m_info;
// The actual field name parsed in parse_field_name.
std::string m_field;
// The field name itself might include an index component
// e.g. ka.value[idx]. This holds the index.
std::string m_idx;
private:
typedef std::set<json_event_value> values_set_t;
typedef std::pair<values_t, values_set_t> extracted_values_t;
// The default extraction function uses the list of pointers
// in m_jptrs. Iterates over array elements between pointers if
// found.
bool def_extract(const nlohmann::json &j,
const std::list<nlohmann::json::json_pointer> &ptrs,
std::list<nlohmann::json::json_pointer>::iterator it);
// The actual json pointer value to use to extract from
// events. See alias struct for usage.
std::list<nlohmann::json::json_pointer> m_jptrs;
// The extraction function to use. May not be defined, in which
// case the default function is used.
extract_t m_extract;
// All values specified on the right hand side of the operator
// e.g. "ka.ns in ("one","two","three"), m_values has ("one",
// "two", "three")
values_set_t m_values;
// All values extracted from the object by the field e.g. for
// a field ka.req.container.image returns all container images
// for all pods within a request.
extracted_values_t m_evalues;
// If true, this filtercheck works on paths, which enables
// some extra bookkeeping to allow for path prefix searches.
bool m_uses_paths = false;
path_prefix_search m_prefix_search;
};
class jevt_filter_check : public json_event_filter_check
{
public:
jevt_filter_check();
virtual ~jevt_filter_check();
int32_t parse_field_name(const char* str, bool alloc_state, bool needed_for_filtering) final;
json_event_filter_check *allocate_new() override;
const check_info &get_info() const override;
protected:
bool extract_values(json_event *jevt) final;
const std::unordered_map<std::string, alias> &get_aliases() const override
{
static std::unordered_map<std::string, alias> a;
return a;
};
private:
// When the field is jevt_value, a json pointer representing
// the index in m_idx
nlohmann::json::json_pointer m_idx_ptr;
static std::string s_jevt_time_field;
static std::string s_jevt_time_iso_8601_field;
static std::string s_jevt_rawtime_field;
static std::string s_jevt_obj_field;
static std::string s_jevt_value_field;
};
class k8s_audit_filter_check : public json_event_filter_check
{
public:
k8s_audit_filter_check();
virtual ~k8s_audit_filter_check();
json_event_filter_check *allocate_new() override;
const check_info &get_info() const override;
const std::unordered_map<std::string, alias> &get_aliases() const override;
// Extract all images/image repositories from the provided containers
static bool extract_images(const nlohmann::json &j,
json_event_filter_check &jchk);
// Extract all query parameters
static bool extract_query_param(const nlohmann::json &j,
json_event_filter_check &jchk);
// Extract some property from the set of rules in the request object
static bool extract_rule_attrs(const nlohmann::json &j,
json_event_filter_check &jchk);
// Determine if the provided path matches any volumes host path.
static bool check_volumes_hostpath(const nlohmann::json &j,
json_event_filter_check &jchk);
// Extract the volume types from volumes in the request object
static bool extract_volume_types(const nlohmann::json &j,
json_event_filter_check &jchk);
// Extract all hostPort values from containers in the request object
static bool extract_host_port(const nlohmann::json &j,
json_event_filter_check &jchk);
// Using both the pod and container security contexts, extract
// the uid/gid that will be used for each container.
static bool extract_effective_run_as(const nlohmann::json &j,
json_event_filter_check &jchk);
// These are only used for compatibility with older rules files
// Always return the string "N/A"
static bool always_return_na(const nlohmann::json &j,
json_event_filter_check &jchk);
// Return true if any container has privileged=true
static bool extract_any_privileged(const nlohmann::json &j,
json_event_filter_check &jchk);
};
class json_event_filter : public sinsp_filter
{
public:
json_event_filter();
virtual ~json_event_filter();
std::string m_rule;
uint32_t m_rule_idx;
std::set<std::string> m_tags;
};
class json_event_filter_factory : public gen_event_filter_factory
{
public:
json_event_filter_factory();
virtual ~json_event_filter_factory();
// Create a new filter
gen_event_filter *new_filter();
// Create a new filter_check
gen_event_filter_check *new_filtercheck(const char *fldname);
// All defined field names
std::list<gen_event_filter_factory::filter_fieldclass_info> get_fields();
private:
std::list<std::shared_ptr<json_event_filter_check>> m_defined_checks;
std::list<json_event_filter_check::check_info> m_info;
};
class json_event_formatter : public gen_event_formatter
{
public:
json_event_formatter(std::shared_ptr<gen_event_filter_factory> factory);
virtual ~json_event_formatter();
void set_format(output_format of, const std::string &format) override;
bool tostring(gen_event *evt, std::string &output) override;
bool tostring_withformat(gen_event *evt, std::string &output, gen_event_formatter::output_format of) override;
bool get_field_values(gen_event *evt, std::map<std::string, std::string> &fields) override;
void get_field_names(std::vector<std::string> &fields) override
{
throw falco_exception("json_event_formatter::get_field_names operation not supported");
}
output_format get_output_format() override;
std::string tojson(json_event *ev);
// Split the format string into a list of tuples, broken at
// output fields, where each tuple is either a block of text
// from the original format string, or a field value/pair from
// the original format string.
//
// For example, given a format string "some output
// (%proc.name)", this will fill in resolved with 3 tuples:
// - ["", "some output ("]
// - ["proc.name", "nginx"]
// - ["", ")"]
//
// This can be used either to return a resolved output string
// or a map of field name/value pairs.
void resolve_format(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved);
private:
void parse_format();
// A format token is either a combination of a filtercheck
// name (ka.value) and filtercheck object as key, or an empty
// key and a NULL filtercheck object, combined with a value (
//
// For example, given a format string:
// "The value is %ka.value today"
// The tokens would be:
// [("The value is ", NULL), ("ka.value", <an object>), " today", NULL)]
struct fmt_token
{
std::string text;
std::shared_ptr<json_event_filter_check> check;
};
gen_event_formatter::output_format m_output_format;
// The original format string
std::string m_format;
// The chunks that make up the format string, in order, broken
// up between text chunks and filterchecks.
std::list<fmt_token> m_tokens;
// All the filterchecks required to resolve tokens in the format string
std::shared_ptr<gen_event_filter_factory> m_json_factory;
};
class json_event_formatter_factory : public gen_event_formatter_factory
{
public:
json_event_formatter_factory(std::shared_ptr<gen_event_filter_factory> factory);
virtual ~json_event_formatter_factory();
void set_output_format(gen_event_formatter::output_format of) override;
std::shared_ptr<gen_event_formatter> create_formatter(const std::string &format) override;
protected:
// Maps from output string to formatter
std::map<std::string, std::shared_ptr<gen_event_formatter>> m_formatters;
gen_event_formatter::output_format m_output_format;
// All the filterchecks required to resolve tokens in the format string
std::shared_ptr<gen_event_filter_factory> m_json_factory;
};

View File

@@ -517,7 +517,7 @@ const nlohmann::json& rule_loader::result::as_json(const rules_contents_t& conte
}
rule_loader::engine_version_info::engine_version_info(context &ctx)
: ctx(ctx)
: ctx(ctx), version(0)
{
}
@@ -532,12 +532,12 @@ rule_loader::plugin_version_info::plugin_version_info(context &ctx)
}
rule_loader::list_info::list_info(context &ctx)
: ctx(ctx), index(0), visibility(0)
: ctx(ctx), used(false), index(0), visibility(0)
{
}
rule_loader::macro_info::macro_info(context &ctx)
: ctx(ctx), cond_ctx(ctx), index(0), visibility(0)
: ctx(ctx), cond_ctx(ctx), used(false), index(0), visibility(0)
{
}

View File

@@ -24,7 +24,6 @@ limitations under the License.
#include "falco_source.h"
#include "falco_load_result.h"
#include "indexed_vector.h"
#include "version.h"
namespace rule_loader
{
@@ -274,7 +273,8 @@ namespace rule_loader
const indexed_vector<falco_source>& srcs,
const std::string& name)
: content(cont), sources(srcs), name(name),
output_extra(), replace_output_container_info(false)
default_ruleset_id(0), replace_output_container_info(false),
min_priority(falco_common::PRIORITY_DEBUG)
{
res.reset(new result(name));
}
@@ -283,15 +283,14 @@ namespace rule_loader
configuration(const configuration&) = delete;
configuration& operator = (const configuration&) = delete;
// inputs
const std::string& content;
const indexed_vector<falco_source>& sources;
std::string name;
std::string output_extra;
bool replace_output_container_info;
// outputs
std::unique_ptr<result> res;
std::string output_extra;
uint16_t default_ruleset_id;
bool replace_output_container_info;
falco_common::priority_type min_priority;
};
/*!
@@ -299,7 +298,7 @@ namespace rule_loader
*/
struct engine_version_info
{
engine_version_info() : ctx("no-filename-given"), version("0.0.0") { };
engine_version_info() : ctx("no-filename-given"), version(0) { };
engine_version_info(context &ctx);
~engine_version_info() = default;
engine_version_info(engine_version_info&&) = default;
@@ -308,7 +307,7 @@ namespace rule_loader
engine_version_info& operator = (const engine_version_info&) = default;
context ctx;
sinsp_version version;
uint32_t version;
};
/*!
@@ -360,6 +359,7 @@ namespace rule_loader
list_info& operator = (const list_info&) = default;
context ctx;
bool used;
size_t index;
size_t visibility;
std::string name;
@@ -380,10 +380,12 @@ namespace rule_loader
context ctx;
context cond_ctx;
bool used;
size_t index;
size_t visibility;
std::string name;
std::string cond;
std::shared_ptr<libsinsp::filter::ast::expr> cond_ast;
};
/*!

View File

@@ -146,11 +146,9 @@ const indexed_vector<rule_loader::rule_info>& rule_loader::collector::rules() co
void rule_loader::collector::define(configuration& cfg, engine_version_info& info)
{
auto v = falco_engine::engine_version();
THROW(!v.compatible_with(info.version), "Rules require engine version "
+ info.version.as_string() + ", but engine version is " + v.as_string(),
THROW(v < info.version, "Rules require engine version "
+ std::to_string(info.version) + ", but engine version is " + std::to_string(v),
info.ctx);
// Store max required_engine_version
if(m_required_engine_version.version < info.version)
{
m_required_engine_version = info;
@@ -163,7 +161,7 @@ void rule_loader::collector::define(configuration& cfg, plugin_version_info& inf
for (const auto& req : info.alternatives)
{
sinsp_version plugin_version(req.version);
THROW(!plugin_version.is_valid(),
THROW(!plugin_version.m_valid,
"Invalid required version '" + req.version
+ "' for plugin '" + req.name + "'",
info.ctx);

View File

@@ -160,30 +160,8 @@ static void build_rule_exception_infos(
}
}
static inline rule_loader::list_info* list_info_from_name(
const rule_loader::collector& c, const std::string& name)
{
auto ret = c.lists().at(name);
if (!ret)
{
throw falco_exception("can't find internal list info at name: " + name);
}
return ret;
}
static inline rule_loader::macro_info* macro_info_from_name(
const rule_loader::collector& c, const std::string& name)
{
auto ret = c.macros().at(name);
if (!ret)
{
throw falco_exception("can't find internal macro info at name: " + name);
}
return ret;
}
// todo(jasondellaluce): this breaks string escaping in lists
static bool resolve_list(std::string& cnd, const falco_list& list)
static bool resolve_list(std::string& cnd, const rule_loader::list_info& list)
{
static std::string blanks = " \t\n\r";
static std::string delims = blanks + "(),=";
@@ -254,20 +232,18 @@ static bool resolve_list(std::string& cnd, const falco_list& list)
}
static void resolve_macros(
const indexed_vector<rule_loader::macro_info>& infos,
indexed_vector<falco_macro>& macros,
indexed_vector<rule_loader::macro_info>& macros,
std::shared_ptr<ast::expr>& ast,
const std::string& condition,
uint32_t visibility,
const rule_loader::context &ctx)
{
filter_macro_resolver macro_resolver;
for (auto &m : infos)
for (auto &m : macros)
{
if (m.index < visibility)
{
auto macro = macros.at(m.name);
macro_resolver.set_macro(m.name, macro->condition);
macro_resolver.set_macro(m.name, m.cond_ast);
}
}
macro_resolver.run(ast);
@@ -296,7 +272,7 @@ static void resolve_macros(
// note: there is no visibility order between filter conditions and lists
static std::shared_ptr<ast::expr> parse_condition(
std::string condition,
indexed_vector<falco_list>& lists,
indexed_vector<rule_loader::list_info>& lists,
const rule_loader::context &ctx)
{
for (auto &l : lists)
@@ -343,14 +319,13 @@ static void apply_output_substitutions(
void rule_loader::compiler::compile_list_infos(
configuration& cfg,
const collector& col,
indexed_vector<falco_list>& out) const
indexed_vector<list_info>& out) const
{
std::string tmp;
std::vector<std::string> used;
for (auto &list : col.lists())
{
falco_list v;
v.name = list.name;
list_info v = list;
v.items.clear();
for (auto &item : list.items)
{
@@ -372,8 +347,7 @@ void rule_loader::compiler::compile_list_infos(
}
}
v.used = false;
auto list_id = out.insert(v, v.name);
out.at(list_id)->id = list_id;
out.insert(v, v.name);
}
for (auto &v : used)
{
@@ -385,23 +359,20 @@ void rule_loader::compiler::compile_list_infos(
void rule_loader::compiler::compile_macros_infos(
configuration& cfg,
const collector& col,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& out) const
indexed_vector<list_info>& lists,
indexed_vector<macro_info>& out) const
{
for (auto &m : col.macros())
{
falco_macro entry;
entry.name = m.name;
entry.condition = parse_condition(m.cond, lists, m.cond_ctx);
macro_info entry = m;
entry.cond_ast = parse_condition(m.cond, lists, m.cond_ctx);
entry.used = false;
auto macro_id = out.insert(entry, m.name);
out.at(macro_id)->id = macro_id;
out.insert(entry, m.name);
}
for (auto &m : out)
{
auto info = macro_info_from_name(col, m.name);
resolve_macros(col.macros(), out, m.condition, info->cond, info->visibility, info->ctx);
resolve_macros(out, m.cond_ast, m.cond, m.visibility, m.ctx);
}
}
@@ -415,8 +386,8 @@ static bool err_is_unknown_type_or_field(const std::string& err)
void rule_loader::compiler::compile_rule_infos(
configuration& cfg,
const collector& col,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& macros,
indexed_vector<list_info>& lists,
indexed_vector<macro_info>& macros,
indexed_vector<falco_rule>& out) const
{
std::string err, condition;
@@ -430,6 +401,12 @@ void rule_loader::compiler::compile_rule_infos(
continue;
}
// skip the rule if below the minimum priority
if (r.priority > cfg.min_priority)
{
continue;
}
// note: this should not be nullptr if the source is not unknown
auto source = cfg.sources.at(r.source);
THROW(!source,
@@ -446,12 +423,12 @@ void rule_loader::compiler::compile_rule_infos(
build_rule_exception_infos(
r.exceptions, rule.exception_fields, condition);
}
rule.condition = parse_condition(condition, lists, r.cond_ctx);
resolve_macros(col.macros(), macros, rule.condition, condition, MAX_VISIBILITY, r.ctx);
auto ast = parse_condition(condition, lists, r.cond_ctx);
resolve_macros(macros, ast, condition, MAX_VISIBILITY, r.ctx);
// check for warnings in the filtering condition
warn_codes.clear();
if (warn_resolver.run(rule.condition.get(), warn_codes))
if (warn_resolver.run(ast.get(), warn_codes))
{
for (auto &w : warn_codes)
{
@@ -466,11 +443,8 @@ void rule_loader::compiler::compile_rule_infos(
apply_output_substitutions(cfg, rule.output);
}
// validate the rule's output
if(!is_format_valid(*cfg.sources.at(r.source), rule.output, err))
{
// skip the rule silently if skip_if_unknown_filter is true and
// we encountered some specific kind of errors
if (err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter)
{
cfg.res->add_warning(
@@ -485,18 +459,30 @@ void rule_loader::compiler::compile_rule_infos(
r.output_ctx);
}
// validate the rule's condition: we compile it into a sinsp filter
// on-the-fly and we throw an exception with details on failure
sinsp_filter_compiler compiler(cfg.sources.at(r.source)->filter_factory, rule.condition.get());
try
{
std::shared_ptr<sinsp_filter> sfPtr(compiler.compile());
// construct rule definition and compile it to a filter
rule.name = r.name;
rule.source = r.source;
rule.description = r.desc;
rule.priority = r.priority;
rule.tags = r.tags;
auto rule_id = out.insert(rule, rule.name);
out.at(rule_id)->id = rule_id;
// This also compiles the filter, and might throw a
// falco_exception with details on the compilation
// failure.
sinsp_filter_compiler compiler(cfg.sources.at(r.source)->filter_factory, ast.get());
try {
std::shared_ptr<gen_event_filter> filter(compiler.compile());
source->ruleset->add(*out.at(rule_id), filter, ast);
}
catch (const sinsp_exception& e)
{
// skip the rule silently if skip_if_unknown_filter is true and
// we encountered some specific kind of errors
// Allow errors containing "nonexistent field" if
// skip_if_unknown_filter is true
std::string err = e.what();
if (err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter)
{
cfg.res->add_warning(
@@ -505,6 +491,7 @@ void rule_loader::compiler::compile_rule_infos(
r.cond_ctx);
continue;
}
rule_loader::context ctx(compiler.get_pos(), condition, r.cond_ctx);
throw rule_loader::rule_load_exception(
falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION,
@@ -512,10 +499,20 @@ void rule_loader::compiler::compile_rule_infos(
ctx);
}
// populate set of event types and emit an special warning
if(r.source == falco_common::syscall_source)
// By default rules are enabled/disabled for the default ruleset
if(r.enabled)
{
auto evttypes = libsinsp::filter::ast::ppm_event_codes(rule.condition.get());
source->ruleset->enable(rule.name, true, cfg.default_ruleset_id);
}
else
{
source->ruleset->disable(rule.name, true, cfg.default_ruleset_id);
}
// populate set of event types and emit an special warning
if(rule.source == falco_common::syscall_source)
{
auto evttypes = libsinsp::filter::ast::ppm_event_codes(ast.get());
if ((evttypes.empty() || evttypes.size() > 100) && r.warn_evttypes)
{
cfg.res->add_warning(
@@ -524,29 +521,23 @@ void rule_loader::compiler::compile_rule_infos(
r.ctx);
}
}
// finalize the rule definition and add it to output
rule.name = r.name;
rule.source = r.source;
rule.description = r.desc;
rule.priority = r.priority;
rule.tags = r.tags;
auto rule_id = out.insert(rule, rule.name);
out.at(rule_id)->id = rule_id;
}
}
void rule_loader::compiler::compile(
configuration& cfg,
const collector& col,
compile_output& out) const
indexed_vector<falco_rule>& out) const
{
indexed_vector<list_info> lists;
indexed_vector<macro_info> macros;
// expand all lists, macros, and rules
try
{
compile_list_infos(cfg, col, out.lists);
compile_macros_infos(cfg, col, out.lists, out.macros);
compile_rule_infos(cfg, col, out.lists, out.macros, out.rules);
compile_list_infos(cfg, col, lists);
compile_macros_infos(cfg, col, lists, macros);
compile_rule_infos(cfg, col, lists, macros, out);
}
catch(rule_load_exception &e)
{
@@ -555,24 +546,24 @@ void rule_loader::compiler::compile(
}
// print info on any dangling lists or macros that were not used anywhere
for (auto &m : out.macros)
for (auto &m : macros)
{
if (!m.used)
{
cfg.res->add_warning(
falco::load_result::load_result::LOAD_UNUSED_MACRO,
"Macro not referred to by any other rule/macro",
macro_info_from_name(col, m.name)->ctx);
m.ctx);
}
}
for (auto &l : out.lists)
for (auto &l : lists)
{
if (!l.used)
{
cfg.res->add_warning(
falco::load_result::LOAD_UNUSED_LIST,
"List not referred to by any other rule/macro",
list_info_from_name(col, l.name)->ctx);
l.ctx);
}
}
}

View File

@@ -31,23 +31,6 @@ namespace rule_loader
class compiler
{
public:
/*!
\brief The output of a compilation.
*/
struct compile_output
{
compile_output() = default;
virtual ~compile_output() = default;
compile_output(compile_output&&) = default;
compile_output& operator = (compile_output&&) = default;
compile_output(const compile_output&) = default;
compile_output& operator = (const compile_output&) = default;
indexed_vector<falco_list> lists;
indexed_vector<falco_macro> macros;
indexed_vector<falco_rule> rules;
};
compiler() = default;
virtual ~compiler() = default;
compiler(compiler&&) = default;
@@ -61,25 +44,25 @@ public:
virtual void compile(
configuration& cfg,
const collector& col,
compile_output& out) const;
indexed_vector<falco_rule>& out) const;
private:
void compile_list_infos(
configuration& cfg,
const collector& col,
indexed_vector<falco_list>& out) const;
indexed_vector<list_info>& out) const;
void compile_macros_infos(
configuration& cfg,
const collector& col,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& out) const;
indexed_vector<list_info>& lists,
indexed_vector<macro_info>& out) const;
void compile_rule_infos(
configuration& cfg,
const collector& col,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& macros,
indexed_vector<list_info>& lists,
indexed_vector<macro_info>& macros,
indexed_vector<falco_rule>& out) const;
};

View File

@@ -19,8 +19,6 @@ limitations under the License.
#include <vector>
#include "rule_loader_reader.h"
#include "falco_engine_version.h"
#include "logger.h"
#define THROW(cond, err, ctx) { if ((cond)) { throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_YAML_VALIDATE, (err), (ctx)); } }
@@ -257,27 +255,8 @@ static void read_item(
{
rule_loader::context ctx(item, rule_loader::context::REQUIRED_ENGINE_VERSION, "", parent);
rule_loader::engine_version_info v(ctx);
try
{
// Convert convert to an uint (more restrictive than converting to a string)
uint32_t ver;
decode_val(item, "required_engine_version", ver, ctx);
// Build proper semver representation
v.version = rule_loader::reader::get_implicit_engine_version(ver);
}
catch(std::exception& e)
{
// Convert to string
std::string ver;
decode_val(item, "required_engine_version", ver, ctx);
v.version = sinsp_version(ver);
THROW(!v.version.is_valid(), "Unable to parse engine version '" + ver + "' as a semver string. Expected \"x.y.z\" semver format.", ctx);
}
decode_val(item, "required_engine_version", v.version, ctx);
collector.define(cfg, v);
}
else if(item["required_plugin_versions"].IsDefined())

View File

@@ -19,9 +19,6 @@ limitations under the License.
#include "rule_loader.h"
#include "rule_loader_collector.h"
#include "logger.h"
#include "version.h"
#include "falco_engine_version.h"
namespace rule_loader
{
@@ -44,19 +41,6 @@ public:
thew new definitions
*/
virtual bool read(configuration& cfg, collector& loader);
/*!
\brief Engine version used to be represented as a simple progressive
number. With the new semver schema, the number now represents
the semver minor number. This function converts the legacy version
number to the new semver schema.
*/
static inline sinsp_version get_implicit_engine_version(uint32_t minor)
{
return sinsp_version(std::to_string(FALCO_ENGINE_VERSION_MAJOR) + "."
+ std::to_string(minor) + "."
+ std::to_string(FALCO_ENGINE_VERSION_PATCH));
}
};
}; // namespace rule_loader

View File

@@ -26,6 +26,7 @@ set(
app/actions/pidfile.cpp
app/actions/init_falco_engine.cpp
app/actions/init_inspectors.cpp
app/actions/init_clients.cpp
app/actions/init_outputs.cpp
app/actions/list_fields.cpp
app/actions/list_plugins.cpp
@@ -52,7 +53,9 @@ set(
logger.cpp
falco_outputs.cpp
outputs_file.cpp
outputs_program.cpp
outputs_stdout.cpp
outputs_syslog.cpp
event_drops.cpp
stats_writer.cpp
versions_info.cpp
@@ -87,14 +90,6 @@ if(USE_BUNDLED_DEPS)
list(APPEND FALCO_DEPENDENCIES yamlcpp)
endif()
if(NOT WIN32)
list(
APPEND FALCO_SOURCES
outputs_program.cpp
outputs_syslog.cpp
)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
list(
APPEND FALCO_SOURCES
@@ -219,16 +214,12 @@ if(MUSL_OPTIMIZED_BUILD AND CMAKE_BUILD_TYPE STREQUAL "release")
)
endif()
if (EMSCRIPTEN)
install(FILES
"$<TARGET_FILE_DIR:falco>/falco.js"
"$<TARGET_FILE_DIR:falco>/falco.wasm"
DESTINATION ${FALCO_BIN_DIR}
COMPONENT "${FALCO_COMPONENT_NAME}")
elseif (WIN32)
install(TARGETS falco
DESTINATION bin
COMPONENT "${FALCO_COMPONENT_NAME}")
if (NOT EMSCRIPTEN)
install(TARGETS falco RUNTIME DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}")
else()
install(TARGETS falco RUNTIME DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}")
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

@@ -30,6 +30,7 @@ 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_signal_handlers(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_falco_engine(falco::app::state& s);
falco::app::run_result init_inspectors(falco::app::state& s);
falco::app::run_result init_outputs(falco::app::state& s);

View File

@@ -69,7 +69,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
auto rules_names = libsinsp::events::sc_set_to_event_names(rules_sc_set);
if (!rules_sc_set.empty())
{
falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(rules_names.size())
falco_logger::log(LOG_DEBUG, "(" + std::to_string(rules_names.size())
+ ") syscalls in rules: " + concat_set_in_order(rules_names) + "\n");
}
@@ -100,14 +100,14 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
// we re-transform from sc_set to names to make
// sure that bad user inputs are ignored
falco_logger::log(falco_logger::level::DEBUG, "+(" + std::to_string(user_positive_sc_set_names.size())
falco_logger::log(LOG_DEBUG, "+(" + std::to_string(user_positive_sc_set_names.size())
+ ") syscalls added (base_syscalls override): "
+ concat_set_in_order(user_positive_sc_set_names) + "\n");
}
auto invalid_positive_sc_set_names = unordered_set_difference(user_positive_names, user_positive_sc_set_names);
if (!invalid_positive_sc_set_names.empty())
{
falco_logger::log(falco_logger::level::WARNING, "Invalid (positive) syscall names: warning (base_syscalls override): "
falco_logger::log(LOG_WARNING, "Invalid (positive) syscall names: warning (base_syscalls override): "
+ concat_set_in_order(invalid_positive_sc_set_names));
}
@@ -136,14 +136,14 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
// we re-transform from sc_set to names to make
// sure that bad user inputs are ignored
falco_logger::log(falco_logger::level::DEBUG, "-(" + std::to_string(user_negative_sc_set_names.size())
falco_logger::log(LOG_DEBUG, "-(" + std::to_string(user_negative_sc_set_names.size())
+ ") syscalls removed (base_syscalls override): "
+ concat_set_in_order(user_negative_sc_set_names) + "\n");
}
auto invalid_negative_sc_set_names = unordered_set_difference(user_negative_names, user_negative_sc_set_names);
if (!invalid_negative_sc_set_names.empty())
{
falco_logger::log(falco_logger::level::WARNING, "Invalid (negative) syscall names: warning (base_syscalls override): "
falco_logger::log(LOG_WARNING, "Invalid (negative) syscall names: warning (base_syscalls override): "
+ concat_set_in_order(invalid_negative_sc_set_names));
}
@@ -154,7 +154,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
if (!non_rules_sc_set.empty() && user_positive_sc_set.empty())
{
auto non_rules_sc_set_names = libsinsp::events::sc_set_to_event_names(non_rules_sc_set);
falco_logger::log(falco_logger::level::DEBUG, "+(" + std::to_string(non_rules_sc_set_names.size())
falco_logger::log(LOG_DEBUG, "+(" + std::to_string(non_rules_sc_set_names.size())
+ ") syscalls (Falco's state engine set of syscalls): "
+ concat_set_in_order(non_rules_sc_set_names) + "\n");
}
@@ -172,7 +172,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
if (!erased_sc_set.empty())
{
auto erased_sc_set_names = libsinsp::events::sc_set_to_event_names(erased_sc_set);
falco_logger::log(falco_logger::level::DEBUG, "-(" + std::to_string(erased_sc_set_names.size())
falco_logger::log(LOG_DEBUG, "-(" + std::to_string(erased_sc_set_names.size())
+ ") ignored syscalls (-> activate via `-A` flag): "
+ concat_set_in_order(erased_sc_set_names) + "\n");
}
@@ -192,7 +192,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
if (!repaired_sc_set.empty())
{
auto repaired_sc_set_names = libsinsp::events::sc_set_to_event_names(repaired_sc_set);
falco_logger::log(falco_logger::level::INFO, "+(" + std::to_string(repaired_sc_set_names.size())
falco_logger::log(LOG_INFO, "+(" + std::to_string(repaired_sc_set_names.size())
+ ") repaired syscalls: " + concat_set_in_order(repaired_sc_set_names) + "\n");
}
}
@@ -207,7 +207,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
if (!s.selected_sc_set.empty())
{
auto selected_sc_set_names = libsinsp::events::sc_set_to_event_names(s.selected_sc_set);
falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(selected_sc_set_names.size())
falco_logger::log(LOG_DEBUG, "(" + std::to_string(selected_sc_set_names.size())
+ ") syscalls selected in total (final set): "
+ concat_set_in_order(selected_sc_set_names) + "\n");
}

View File

@@ -23,7 +23,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco::app::state& s)
{
#ifdef __linux__
if(!s.is_modern_ebpf())
if(!s.options.modern_bpf)
{
return run_result::ok();
}
@@ -34,10 +34,10 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco::
return run_result::fatal("cannot get the number of online CPUs from the system\n");
}
if(s.config->m_modern_ebpf.m_cpus_for_each_buffer > online_cpus)
if(s.config->m_cpus_for_each_syscall_buffer > online_cpus)
{
falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n");
s.config->m_modern_ebpf.m_cpus_for_each_buffer = online_cpus;
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;
}
#endif
return run_result::ok();

View File

@@ -28,15 +28,21 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco::app::state& s)
{
#ifdef __linux__
auto index = s.driver_buf_size_preset();
if (index == -1)
/* 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.
*/
if(s.is_capture_mode()
|| !s.is_source_enabled(falco_common::syscall_source)
|| s.is_gvisor_enabled()
|| s.options.nodriver)
{
// Chosen driver kind does not support this option.
return run_result::ok();
}
uint16_t index = s.config->m_syscall_buf_size_preset;
if(index < MIN_INDEX || index > MAX_INDEX)
{
return run_result::fatal("The 'buf_size_preset' value must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n");
return run_result::fatal("The 'syscall_buf_size_preset' value must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n");
}
/* Sizes from `1 MB` to `512 MB`. The index `0` is reserved, users cannot use it! */
@@ -49,24 +55,24 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco:
if(page_size <= 0)
{
s.syscall_buffer_bytes_size = DEFAULT_BYTE_SIZE;
falco_logger::log(falco_logger::level::WARNING, "Unable to get the system page size through 'getpagesize()'. Try to use the default syscall buffer dimension: " + std::to_string(DEFAULT_BYTE_SIZE) + " bytes\n");
falco_logger::log(LOG_WARNING, "Unable to get the system page size through 'getpagesize()'. Try to use the default syscall buffer dimension: " + std::to_string(DEFAULT_BYTE_SIZE) + " bytes\n");
return run_result::ok();
}
/* Check if the chosen size is a multiple of the page size. */
if(chosen_size % page_size != 0)
{
return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not a multiple of your system page size '" + std::to_string(page_size) + "'. Please configure a greater 'buf_size_preset' value in the Falco configuration file\n");
return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not a multiple of your system page size '" + std::to_string(page_size) + "'. Please configure a greater 'syscall_buf_size_preset' value in the Falco configuration file\n");
}
/* Check if the chosen size is greater than `2 * page_size`. */
if((chosen_size / page_size) <= 2)
{
return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not greater than '2 * " + std::to_string(page_size) + "' where '" + std::to_string(page_size) + "' is your system page size. Please configure a greater 'buf_size_preset' value in the Falco configuration file\n");
return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not greater than '2 * " + std::to_string(page_size) + "' where '" + std::to_string(page_size) + "' is your system page size. Please configure a greater 'syscall_buf_size_preset' value in the Falco configuration file\n");
}
s.syscall_buffer_bytes_size = chosen_size;
falco_logger::log(falco_logger::level::INFO, "The chosen syscall buffer dimension is: " + std::to_string(chosen_size) + " bytes (" + std::to_string(chosen_size / (uint64_t)(1024 * 1024)) + " MBs)\n");
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();

View File

@@ -18,7 +18,6 @@ limitations under the License.
#include "actions.h"
#include "falco_utils.h"
#include <sys/stat.h>
#include <filesystem>
#ifndef CPPPATH_SEP
#ifdef _MSC_VER
@@ -35,14 +34,14 @@ static int create_dir(const std::string &path);
falco::app::run_result falco::app::actions::create_requested_paths(falco::app::state& s)
{
if(s.is_gvisor())
if(s.is_gvisor_enabled())
{
// This is bad: parsing gvisor config to get endpoint
// to be able to auto-create the path to the file for the user.
std::ifstream reader(s.config->m_gvisor.m_config);
std::ifstream reader(s.options.gvisor_config);
if (reader.fail())
{
return run_result::fatal(s.config->m_gvisor.m_config + ": cannot open file");
return run_result::fatal(s.options.gvisor_config + ": cannot open file");
}
nlohmann::json parsed_json;
@@ -53,7 +52,7 @@ falco::app::run_result falco::app::actions::create_requested_paths(falco::app::s
}
catch (const std::exception &e)
{
return run_result::fatal(s.config->m_gvisor.m_config + ": cannot parse JSON: " + e.what());
return run_result::fatal(s.options.gvisor_config + ": cannot parse JSON: " + e.what());
}
try
@@ -62,7 +61,7 @@ falco::app::run_result falco::app::actions::create_requested_paths(falco::app::s
}
catch (const std::exception &e)
{
return run_result::fatal(s.config->m_gvisor.m_config + ": failed to fetch config.endpoint: " + e.what());
return run_result::fatal(s.options.gvisor_config + ": failed to fetch config.endpoint: " + e.what());
}
int ret = create_dir(gvisor_socket);
@@ -92,19 +91,25 @@ falco::app::run_result falco::app::actions::create_requested_paths(falco::app::s
return run_result::ok();
}
// This function operates like `mkdir -p` excluding the last part of
// the path which we assume to be the filename.
static int create_dir(const std::string &path)
{
// Properly reset errno
errno = 0;
std::filesystem::path dirPath(path);
try {
std::filesystem::create_directories(dirPath.parent_path());
} catch (const std::exception& ex) {
return -1;
}
return 0;
std::istringstream f(path);
std::string path_until_token;
std::string s;
// Create all the subfolder stopping at last token (f.eof());
// Examples:
// "/tmp/foo/bar" -> "", "tmp", "foo" -> mkdir("/") + mkdir("/tmp/") + midir("/tmp/foo/")
// "tmp/foo/bar" -> "tmp", "foo" -> mkdir("tmp/") + midir("tmp/foo/")
while (getline(f, s, *CPPPATH_SEP) && !f.eof()) {
path_until_token += s + CPPPATH_SEP;
int ret = mkdir(path_until_token.c_str(), 0600);
if (ret != 0 && errno != EEXIST)
{
return ret;
}
}
return 0;
}

View File

@@ -76,7 +76,7 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s
#ifdef __linux__
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping signal handlers creation in dry-run\n");
falco_logger::log(LOG_DEBUG, "Skipping signal handlers creation in dry-run\n");
return run_result::ok();
}
@@ -88,7 +88,7 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s
|| !g_restart_signal.is_lock_free()
|| !g_reopen_outputs_signal.is_lock_free())
{
falco_logger::log(falco_logger::level::WARNING, "Bundled atomics implementation is not lock-free, signal handlers may be unstable\n");
falco_logger::log(LOG_WARNING, "Bundled atomics implementation is not lock-free, signal handlers may be unstable\n");
}
if(! create_handler(SIGINT, ::terminate_signal_handler, ret) ||
@@ -162,7 +162,7 @@ falco::app::run_result falco::app::actions::unregister_signal_handlers(falco::ap
#ifdef __linux__
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping unregistering signal handlers in dry-run\n");
falco_logger::log(LOG_DEBUG, "Skipping unregistering signal handlers in dry-run\n");
return run_result::ok();
}

View File

@@ -47,7 +47,7 @@ void falco::app::actions::print_enabled_event_sources(falco::app::state& s)
str += str.empty() ? "" : ", ";
str += src;
}
falco_logger::log(falco_logger::level::INFO, "Loaded event sources: " + str);
falco_logger::log(LOG_INFO, "Loaded event sources: " + str);
/* Print all enabled sources. */
str.clear();
@@ -56,7 +56,7 @@ void falco::app::actions::print_enabled_event_sources(falco::app::state& s)
str += str.empty() ? "" : ", ";
str += src;
}
falco_logger::log(falco_logger::level::INFO, "Enabled event sources: " + str);
falco_logger::log(LOG_INFO, "Enabled event sources: " + str);
// print some warnings to the user
for (const auto& src : s.enabled_sources)
@@ -75,18 +75,18 @@ void falco::app::actions::print_enabled_event_sources(falco::app::state& s)
}
else
{
if (src != falco_common::syscall_source || s.is_nodriver())
if (src != falco_common::syscall_source || s.options.nodriver)
{
falco_logger::log(falco_logger::level::WARNING, "Enabled event source '"
falco_logger::log(LOG_WARNING, "Enabled event source '"
+ src + "' can be opened with multiple loaded plugins, will use only '"
+ first_plugin->name() + "'");
}
}
}
}
if (!first_plugin && s.is_nodriver())
if (!first_plugin && s.options.nodriver)
{
falco_logger::log(falco_logger::level::WARNING, "Enabled event source '"
falco_logger::log(LOG_WARNING, "Enabled event source '"
+ src + "' will be opened with no driver, no event will be produced");
}
}
@@ -126,3 +126,4 @@ void falco::app::actions::format_plugin_info(std::shared_ptr<sinsp_plugin> p, st
os << " - Async Events" << std::endl;
}
}

View File

@@ -20,13 +20,11 @@ limitations under the License.
#include <fcntl.h>
#include <plugin_manager.h>
#include <configuration.h>
#include "helpers.h"
#ifdef _WIN32
#define PATH_MAX 260
#endif
/* DEPRECATED: we will remove it in Falco 0.34. */
#define FALCO_BPF_ENV_VARIABLE "FALCO_BPF_PROBE"
using namespace falco::app;
using namespace falco::app::actions;
@@ -35,13 +33,13 @@ falco::app::run_result falco::app::actions::open_offline_inspector(falco::app::s
{
try
{
s.offline_inspector->open_savefile(s.config->m_replay.m_capture_file);
falco_logger::log(falco_logger::level::INFO, "Replaying events from the capture file: " + s.config->m_replay.m_capture_file + "\n");
s.offline_inspector->open_savefile(s.options.trace_filename);
falco_logger::log(LOG_INFO, "Reading system call events from file: " + s.options.trace_filename + "\n");
return run_result::ok();
}
catch (sinsp_exception &e)
{
return run_result::fatal("Could not open trace filename " + s.config->m_replay.m_capture_file + " for reading: " + e.what());
return run_result::fatal("Could not open trace filename " + s.options.trace_filename + " for reading: " + e.what());
}
}
@@ -62,14 +60,14 @@ falco::app::run_result falco::app::actions::open_live_inspector(
if (p->caps() & CAP_SOURCING && p->id() != 0 && p->event_source() == source)
{
auto cfg = s.plugin_configs.at(p->name());
falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with plugin '" + cfg->m_name + "'");
inspector->open_plugin(p->name(), cfg->m_open_params);
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with plugin '" + cfg->m_name + "'");
inspector->open_plugin(cfg->m_name, cfg->m_open_params);
return run_result::ok();
}
}
return run_result::fatal("Can't find plugin for event source: " + source);
}
else if (s.is_nodriver()) /* nodriver engine. */
else if (s.options.nodriver) /* nodriver engine. */
{
// when opening a capture with no driver, Falco will first check
// if a plugin is capable of generating raw events from the libscap
@@ -80,28 +78,37 @@ falco::app::run_result falco::app::actions::open_live_inspector(
if (p->caps() & CAP_SOURCING && p->id() == 0)
{
auto cfg = s.plugin_configs.at(p->name());
falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with plugin '" + cfg->m_name + "'");
inspector->open_plugin(p->name(), cfg->m_open_params);
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with plugin '" + cfg->m_name + "'");
inspector->open_plugin(cfg->m_name, cfg->m_open_params);
return run_result::ok();
}
}
falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with no driver\n");
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with no driver\n");
inspector->open_nodriver();
}
else if(s.is_gvisor()) /* gvisor engine. */
else if (s.options.userspace) /* udig engine. */
{
falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.config->m_gvisor.m_config);
inspector->open_gvisor(s.config->m_gvisor.m_config, s.config->m_gvisor.m_root);
// open_udig() is the underlying method used in the capture code to parse userspace events from the kernel.
//
// Falco uses a ptrace(2) based userspace implementation.
// Regardless of the implementation, the underlying method remains the same.
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();
}
else if(s.is_modern_ebpf()) /* modern BPF engine. */
else if(s.is_gvisor_enabled()) /* gvisor engine. */
{
falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with modern BPF probe.");
falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_buffer) + "' CPUs.");
inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_modern_ebpf.m_cpus_for_each_buffer, true, s.selected_sc_set);
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.options.gvisor_config);
inspector->open_gvisor(s.options.gvisor_config, s.options.gvisor_root);
}
else if(s.is_ebpf()) /* BPF engine. */
else if(s.options.modern_bpf) /* modern BPF engine. */
{
const char *bpf_probe_path = s.config->m_ebpf.m_probe_path.c_str();
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with modern BPF probe.");
falco_logger::log(LOG_INFO, "One ring buffer every '" + std::to_string(s.config->m_cpus_for_each_syscall_buffer) + "' CPUs.");
inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_cpus_for_each_syscall_buffer, true, s.selected_sc_set);
}
else if(getenv(FALCO_BPF_ENV_VARIABLE) != NULL) /* BPF engine. */
{
const char *bpf_probe_path = std::getenv(FALCO_BPF_ENV_VARIABLE);
char full_path[PATH_MAX];
/* If the path is empty try to load the probe from the default path. */
if(strncmp(bpf_probe_path, "", 1) == 0)
@@ -114,23 +121,23 @@ falco::app::run_result falco::app::actions::open_live_inspector(
snprintf(full_path, PATH_MAX, "%s/%s", home, FALCO_PROBE_BPF_FILEPATH);
bpf_probe_path = full_path;
}
falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with BPF probe. BPF probe path: " + std::string(bpf_probe_path));
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with BPF probe. BPF probe path: " + std::string(bpf_probe_path));
inspector->open_bpf(bpf_probe_path, s.syscall_buffer_bytes_size, s.selected_sc_set);
}
else /* Kernel module (default). */
{
try
{
falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with Kernel module");
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with Kernel module");
inspector->open_kmod(s.syscall_buffer_bytes_size, s.selected_sc_set);
}
catch(sinsp_exception &e)
{
// Try to insert the Falco kernel module
falco_logger::log(falco_logger::level::INFO, "Trying to inject the Kernel module and opening the capture again...");
falco_logger::log(LOG_INFO, "Trying to inject the Kernel module and opening the capture again...");
if(system("modprobe " DRIVER_NAME " > /dev/null 2> /dev/null"))
{
falco_logger::log(falco_logger::level::ERR, "Unable to load the driver\n");
falco_logger::log(LOG_ERR, "Unable to load the driver\n");
}
inspector->open_kmod(s.syscall_buffer_bytes_size, s.selected_sc_set);
}

View File

@@ -0,0 +1,71 @@
// SPDX-License-Identifier: Apache-2.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 "actions.h"
using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::init_clients(falco::app::state& s)
{
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
// k8s is useful only if the syscall source is enabled
if (s.is_capture_mode() || !s.is_source_enabled(falco_common::syscall_source))
{
return run_result::ok();
}
auto inspector = s.source_infos.at(falco_common::syscall_source)->inspector;
falco_logger::log(LOG_DEBUG, "Setting metadata download max size to " + std::to_string(s.config->m_metadata_download_max_mb) + " MB\n");
falco_logger::log(LOG_DEBUG, "Setting metadata download chunk wait time to " + std::to_string(s.config->m_metadata_download_chunk_wait_us) + " μs\n");
falco_logger::log(LOG_DEBUG, "Setting metadata download watch frequency to " + std::to_string(s.config->m_metadata_download_watch_freq_sec) + " seconds\n");
inspector->set_metadata_download_params(s.config->m_metadata_download_max_mb * 1024 * 1024, s.config->m_metadata_download_chunk_wait_us, s.config->m_metadata_download_watch_freq_sec);
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping clients initialization in dry-run\n");
return run_result::ok();
}
//
// Run k8s, if required
//
char *k8s_api_env = NULL;
if(!s.options.k8s_api.empty() ||
(k8s_api_env = getenv("FALCO_K8S_API")))
{
// Create string pointers for some config vars
// and pass to inspector. The inspector then
// owns the pointers.
std::string *k8s_api_ptr = new std::string((!s.options.k8s_api.empty() ? s.options.k8s_api : k8s_api_env));
std::string *k8s_api_cert_ptr = new std::string(s.options.k8s_api_cert);
std::string *k8s_node_name_ptr = new std::string(s.options.k8s_node_name);
if(k8s_api_cert_ptr->empty())
{
if(char* k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
{
*k8s_api_cert_ptr = k8s_cert_env;
}
}
inspector->init_k8s_client(k8s_api_ptr, k8s_api_cert_ptr, k8s_node_name_ptr, s.options.verbose);
}
#endif
return run_result::ok();
}

View File

@@ -49,9 +49,9 @@ static void init_syscall_inspector(falco::app::state& s, std::shared_ptr<sinsp>
inspector->set_snaplen(s.options.snaplen);
}
if (s.is_driver_drop_failed_exit_enabled())
if (s.config->m_syscall_drop_failed_exit)
{
falco_logger::log(falco_logger::level::INFO, "Failed syscall exit events are dropped in the kernel driver\n");
falco_logger::log(LOG_INFO, "Failed syscall exit events are dropped in the kernel driver\n");
inspector->set_dropfailed(true);
}

View File

@@ -16,11 +16,7 @@ limitations under the License.
*/
#include <stdlib.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include "actions.h"
@@ -41,7 +37,7 @@ falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s)
if(env_hostname || (env_hostname = getenv("FALCO_GRPC_HOSTNAME")))
{
hostname = env_hostname;
falco_logger::log(falco_logger::level::INFO, "Hostname value has been overridden via environment variable to: " + hostname + "\n");
falco_logger::log(LOG_INFO, "Hostname value has been overridden via environment variable to: " + hostname + "\n");
}
else
{
@@ -56,7 +52,7 @@ falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s)
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping outputs initialization in dry-run\n");
falco_logger::log(LOG_DEBUG, "Skipping outputs initialization in dry-run\n");
return run_result::ok();
}

View File

@@ -17,124 +17,16 @@ limitations under the License.
#include "actions.h"
#include "falco_utils.h"
// USED just to include some shared macros, remove this include in Falco 0.38.0
#include "configuration.h"
/* DEPRECATED: we will remove it in Falco 0.38. */
#define FALCO_BPF_ENV_VARIABLE "FALCO_BPF_PROBE"
using namespace falco::app;
using namespace falco::app::actions;
// applies legacy/in-deprecation options to the current state
static falco::app::run_result apply_deprecated_options(falco::app::state& s)
// applies legacy/in-deprecation options to the current config
static void apply_deprecated_options(
const falco::app::options& opts,
const std::shared_ptr<falco_configuration>& cfg)
{
// Check that at most one command line option is provided
int open_modes = 0;
open_modes += !s.options.capture_file.empty();
open_modes += !s.options.gvisor_config.empty();
open_modes += s.options.modern_bpf;
open_modes += getenv(FALCO_BPF_ENV_VARIABLE) != NULL;
open_modes += s.options.nodriver;
if(open_modes > 1)
{
return run_result::fatal("You can not specify more than one of -e, -g (--gvisor-config), --modern-bpf, --nodriver, and the FALCO_BPF_PROBE env var");
}
// Please note: is not possible to mix command line options and configs to obtain a configuration
// we need to use only one method. For example, is not possible to set the gvisor-config through
// the command line and the gvisor-root through the config file. For this reason, if we detect
// at least one change in the default config we don't allow to use the command line options.
if(s.config->m_changes_in_engine_config)
{
// If a command line option is specified, print a warning because it will be ignored
if(open_modes == 1)
{
falco_logger::log(falco_logger::level::WARNING,
"Since the new 'engine' config key is being used, deprecated CLI options "
"[-e,-g,--gvisor-config,--nodriver,--modern-bpf] and 'FALCO_BPF_PROBE' environment variable will be ignored.\n");
}
// If these configs are specified, print a warning because they will be ignored
if(s.config->m_syscall_drop_failed_exit != DEFAULT_DROP_FAILED_EXIT)
{
falco_logger::log(falco_logger::level::WARNING,
"Since the new 'engine' config key is being used, deprecated config 'syscall_drop_failed_exit' will be ignored.\n");
}
if(s.config->m_syscall_buf_size_preset != DEFAULT_BUF_SIZE_PRESET)
{
falco_logger::log(falco_logger::level::WARNING,
"Since the new 'engine' config key is being used, deprecated config 'syscall_buf_size_preset' will be ignored.\n");
}
if(s.config->m_cpus_for_each_syscall_buffer != DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER)
{
falco_logger::log(falco_logger::level::WARNING,
"Since the new 'engine' config key is being used, deprecated config 'modern_bpf.cpus_for_each_syscall_buffer' will be ignored.\n");
}
return run_result::ok();
}
// These warnings are similar to the ones above, but in this case, the configs are not ignored
// they are just deprecated
if(s.config->m_syscall_drop_failed_exit != DEFAULT_DROP_FAILED_EXIT)
{
falco_logger::log(falco_logger::level::WARNING,
"DEPRECATION NOTICE: 'syscall_drop_failed_exit' config is deprecated and will be removed in Falco 0.38! Use `engine.<driver>.drop_failed_exit' config instead\n");
}
if(s.config->m_syscall_buf_size_preset != DEFAULT_BUF_SIZE_PRESET)
{
falco_logger::log(falco_logger::level::WARNING,
"DEPRECATION NOTICE: 'syscall_buf_size_preset' config is deprecated and will be removed in Falco 0.38! Use `engine.<driver>.buf_size_preset' config instead\n");
}
if(s.config->m_cpus_for_each_syscall_buffer != DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER)
{
falco_logger::log(falco_logger::level::WARNING,
"DEPRECATION NOTICE: 'modern_bpf.cpus_for_each_syscall_buffer' config is deprecated and will be removed in Falco 0.38! Use `engine.modern_ebpf.cpus_for_each_buffer' config instead\n");
}
// Replace the kmod default values in case the engine was open with the kmod.
// We don't have a command line option to open the kmod so we have to always enforce the
// default values.
s.config->m_kmod.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit;
s.config->m_kmod.m_buf_size_preset = s.config->m_syscall_buf_size_preset;
// If overridden from CLI options (soon to be removed),
// use the requested driver.
if (getenv(FALCO_BPF_ENV_VARIABLE))
{
falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the 'FALCO_BPF_PROBE' environment variable is deprecated and will be removed in Falco 0.38!\n");
s.config->m_engine_mode = engine_kind_t::EBPF;
s.config->m_ebpf.m_probe_path = getenv(FALCO_BPF_ENV_VARIABLE);
s.config->m_ebpf.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit;
s.config->m_ebpf.m_buf_size_preset = s.config->m_syscall_buf_size_preset;
}
else if (s.options.modern_bpf)
{
falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--modern-bpf' command line option is deprecated and will be removed in Falco 0.38!\n");
s.config->m_engine_mode = engine_kind_t::MODERN_EBPF;
s.config->m_modern_ebpf.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit;
s.config->m_modern_ebpf.m_buf_size_preset = s.config->m_syscall_buf_size_preset;
s.config->m_modern_ebpf.m_cpus_for_each_buffer = s.config->m_cpus_for_each_syscall_buffer;
}
if (!s.options.gvisor_config.empty())
{
falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-g,--gvisor-config' command line option is deprecated and will be removed in Falco 0.38!\n");
s.config->m_engine_mode = engine_kind_t::GVISOR;
s.config->m_gvisor.m_config = s.options.gvisor_config;
s.config->m_gvisor.m_root = s.options.gvisor_root;
}
if (s.options.nodriver)
{
falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--nodriver' command line option is deprecated and will be removed in Falco 0.38!\n");
s.config->m_engine_mode = engine_kind_t::NONE;
}
if (!s.options.capture_file.empty())
{
falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-e' command line option is deprecated and will be removed in Falco 0.38!\n");
s.config->m_engine_mode = engine_kind_t::REPLAY;
s.config->m_replay.m_capture_file = s.options.capture_file;
}
return run_result::ok();
// Keep for future use cases.
}
falco::app::run_result falco::app::actions::load_config(falco::app::state& s)
@@ -147,9 +39,6 @@ falco::app::run_result falco::app::actions::load_config(falco::app::state& s)
}
else
{
// Is possible to have an empty config file when we want to use some command line
// options like `--help`, `--version`, ...
// The configs used in `load_yaml` will be initialized to the default values.
s.config->init(s.options.cmdline_config_options);
}
}
@@ -160,19 +49,21 @@ falco::app::run_result falco::app::actions::load_config(falco::app::state& s)
// log after config init because config determines where logs go
falco_logger::set_time_format_iso_8601(s.config->m_time_format_iso_8601);
falco_logger::log(falco_logger::level::INFO, "Falco version: " + std::string(FALCO_VERSION) + " (" + std::string(FALCO_TARGET_ARCH) + ")\n");
falco_logger::log(LOG_INFO, "Falco version: " + std::string(FALCO_VERSION) + " (" + std::string(FALCO_TARGET_ARCH) + ")\n");
if (!s.cmdline.empty())
{
falco_logger::log(falco_logger::level::DEBUG, "CLI args: " + s.cmdline);
falco_logger::log(LOG_DEBUG, "CLI args: " + s.cmdline);
}
if (!s.options.conf_filename.empty())
{
falco_logger::log(falco_logger::level::INFO, "Falco initialized with configuration file: " + s.options.conf_filename + "\n");
falco_logger::log(LOG_INFO, "Falco initialized with configuration file: " + s.options.conf_filename + "\n");
}
s.config->m_buffered_outputs = !s.options.unbuffered_outputs;
return apply_deprecated_options(s);
apply_deprecated_options(s.options, s.config);
return run_result::ok();
}
falco::app::run_result falco::app::actions::require_config_file(falco::app::state& s)

View File

@@ -49,7 +49,7 @@ falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s)
// Load all the configured plugins
for(auto &p : s.config->m_plugins)
{
falco_logger::log(falco_logger::level::INFO, "Loading plugin '" + p.m_name + "' from file " + p.m_library_path + "\n");
falco_logger::log(LOG_INFO, "Loading plugin '" + p.m_name + "' from file " + p.m_library_path + "\n");
auto plugin = s.offline_inspector->register_plugin(p.m_library_path);
s.plugin_configs.insert(p, plugin->name());
if(plugin->caps() & CAP_SOURCING && plugin->id() != 0)

View File

@@ -39,10 +39,10 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
return run_result::fatal("You must specify at least one rules file/directory via -r or a rules_file entry in falco.yaml");
}
falco_logger::log(falco_logger::level::DEBUG, "Configured rules filenames:\n");
falco_logger::log(LOG_DEBUG, "Configured rules filenames:\n");
for (const auto& path : s.config->m_rules_filenames)
{
falco_logger::log(falco_logger::level::DEBUG, std::string(" ") + path + "\n");
falco_logger::log(LOG_DEBUG, std::string(" ") + path + "\n");
}
for (const auto &path : s.config->m_rules_filenames)
@@ -67,7 +67,7 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
std::string err = "";
for(auto &filename : s.config->m_loaded_rules_filenames)
{
falco_logger::log(falco_logger::level::INFO, "Loading rules from file " + filename + "\n");
falco_logger::log(LOG_INFO, "Loading rules from file " + filename + "\n");
std::unique_ptr<falco::load_result> res;
res = s.engine->load_rules(rc.at(filename), filename);
@@ -130,7 +130,7 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
for (const auto& substring : s.options.disabled_rule_substrings)
{
falco_logger::log(falco_logger::level::INFO, "Disabling rules matching substring: " + substring + "\n");
falco_logger::log(LOG_INFO, "Disabling rules matching substring: " + substring + "\n");
s.engine->enable_rule(substring, false);
}
@@ -138,7 +138,7 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
{
for(auto &tag : s.options.disabled_rule_tags)
{
falco_logger::log(falco_logger::level::INFO, "Disabling rules with tag: " + tag + "\n");
falco_logger::log(LOG_INFO, "Disabling rules with tag: " + tag + "\n");
}
s.engine->enable_rule_by_tag(s.options.disabled_rule_tags, false);
}
@@ -150,22 +150,20 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
s.engine->enable_rule(all_rules, false);
for(auto &tag : s.options.enabled_rule_tags)
{
falco_logger::log(falco_logger::level::INFO, "Enabling rules with tag: " + tag + "\n");
falco_logger::log(LOG_INFO, "Enabling rules with tag: " + tag + "\n");
}
s.engine->enable_rule_by_tag(s.options.enabled_rule_tags, true);
}
if (s.options.describe_all_rules)
{
const auto& plugins = s.offline_inspector->get_plugin_manager()->plugins();
s.engine->describe_rule(NULL, plugins, s.config->m_json_output);
s.engine->describe_rule(NULL, s.config->m_json_output);
return run_result::exit();
}
if (!s.options.describe_rule.empty())
{
const auto& plugins = s.offline_inspector->get_plugin_manager()->plugins();
s.engine->describe_rule(&(s.options.describe_rule), plugins, s.config->m_json_output);
s.engine->describe_rule(&(s.options.describe_rule), s.config->m_json_output);
return run_result::exit();
}

View File

@@ -28,7 +28,7 @@ falco::app::run_result falco::app::actions::pidfile(falco::app::state& s)
{
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping pidfile creation in dry-run\n");
falco_logger::log(LOG_DEBUG, "Skipping pidfile creation in dry-run\n");
return run_result::ok();
}
@@ -41,7 +41,7 @@ falco::app::run_result falco::app::actions::pidfile(falco::app::state& s)
if (!pidfile.good())
{
falco_logger::log(falco_logger::level::ERR, "Could not write pid to pidfile " + s.options.pidfilename + ". Exiting.\n");
falco_logger::log(LOG_ERR, "Could not write pid to pidfile " + s.options.pidfilename + ". Exiting.\n");
exit(-1);
}
pidfile << self_pid;

View File

@@ -16,9 +16,6 @@ limitations under the License.
*/
#include "actions.h"
#ifdef _WIN32
#include <windows.h>
#endif
using namespace falco::app;
using namespace falco::app::actions;
@@ -27,22 +24,14 @@ falco::app::run_result falco::app::actions::print_page_size(falco::app::state& s
{
if(s.options.print_page_size)
{
#ifndef _WIN32
long page_size = getpagesize();
#else
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
long page_size = sysInfo.dwPageSize;
#endif
if(page_size <= 0)
{
return run_result::fatal("\nUnable to get the system page size through 'getpagesize()'\n");
}
else
{
falco_logger::log(falco_logger::level::INFO, "Your system page size is: " + std::to_string(page_size) + " bytes\n");
falco_logger::log(LOG_INFO, "Your system page size is: " + std::to_string(page_size) + " bytes\n");
}
return run_result::exit();
}

View File

@@ -15,12 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _WIN32
#include <sys/utsname.h>
#else
#include <windows.h>
#endif
#include <iostream>
#include "actions.h"
#include "../../versions_info.h"
@@ -37,77 +32,28 @@ static std::string read_file(const std::string &filename)
return str;
}
#ifndef _WIN32
static int get_sysinfo(nlohmann::json &support)
{
struct utsname sysinfo;
if(uname(&sysinfo) != 0)
{
return -1;
}
support["system_info"]["sysname"] = sysinfo.sysname;
support["system_info"]["nodename"] = sysinfo.nodename;
support["system_info"]["release"] = sysinfo.release;
support["system_info"]["version"] = sysinfo.version;
support["system_info"]["machine"] = sysinfo.machine;
return 0;
}
#else
static int get_sysinfo(nlohmann::json &support)
{
OSVERSIONINFO osvi;
SYSTEM_INFO sysInfo;
TCHAR computerName[256];
DWORD size = sizeof(computerName);
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetSystemInfo(&sysInfo);
if(!GetVersionEx(&osvi) || !GetComputerName(computerName, &size))
{
return -1;
}
support["system_info"]["sysname"] = "Windows";
support["system_info"]["nodename"] = computerName;
support["system_info"]["release"] = osvi.dwMajorVersion;
support["system_info"]["version"] = osvi.dwMinorVersion;
switch (sysInfo.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_AMD64:
support["system_info"]["machine"] = "x86_64";
break;
case PROCESSOR_ARCHITECTURE_ARM:
support["system_info"]["machine"] = "ARM";
break;
case PROCESSOR_ARCHITECTURE_ARM64:
support["system_info"]["machine"] = "ARM64";
break;
case PROCESSOR_ARCHITECTURE_INTEL:
support["system_info"]["machine"] = "i386";
break;
default:
support["system_info"]["machine"] = "unknown";
}
return 0;
}
#endif
falco::app::run_result falco::app::actions::print_support(falco::app::state& s)
{
if(s.options.print_support)
{
nlohmann::json support;
struct utsname sysinfo;
std::string cmdline;
if(get_sysinfo(support) != 0)
if(uname(&sysinfo) != 0)
{
return run_result::fatal(std::string("Could not get system info: ") + strerror(errno));
return run_result::fatal(std::string("Could not uname() to find system info: ") + strerror(errno));
}
const falco::versions_info infos(s.offline_inspector);
support["version"] = infos.falco_version;
support["engine_info"] = infos.as_json();
support["system_info"]["sysname"] = sysinfo.sysname;
support["system_info"]["nodename"] = sysinfo.nodename;
support["system_info"]["release"] = sysinfo.release;
support["system_info"]["version"] = sysinfo.version;
support["system_info"]["machine"] = sysinfo.machine;
support["cmdline"] = s.cmdline;
support["config"] = read_file(s.options.conf_filename);
support["rules_files"] = nlohmann::json::array();

View File

@@ -25,6 +25,7 @@ limitations under the License.
#include <unordered_map>
#include "falco_utils.h"
#include "token_bucket.h"
#include "actions.h"
#include "helpers.h"
@@ -136,6 +137,8 @@ static falco::app::run_result do_inspect(
stats_writer::collector stats_collector(statsw);
uint64_t duration_start = 0;
uint32_t timeouts_since_last_success_or_msg = 0;
token_bucket rate_limiter;
const bool rate_limiter_enabled = s.config->m_notifications_rate > 0;
const bool is_capture_mode = source.empty();
size_t source_engine_idx = 0;
@@ -153,6 +156,14 @@ static falco::app::run_result do_inspect(
source_engine_idx = s.source_infos.at(source)->engine_idx;
}
// if enabled, init rate limiter
if (rate_limiter_enabled)
{
rate_limiter.init(
s.config->m_notifications_rate,
s.config->m_notifications_max_burst);
}
// reset event counter
num_evts = 0;
@@ -183,7 +194,7 @@ static falco::app::run_result do_inspect(
if (falco::app::g_reopen_outputs_signal.triggered())
{
falco::app::g_reopen_outputs_signal.handle([&s](){
falco_logger::log(falco_logger::level::INFO, "SIGUSR1 received, reopening outputs...\n");
falco_logger::log(LOG_INFO, "SIGUSR1 received, reopening outputs...\n");
if(s.outputs != nullptr)
{
s.outputs->reopen_outputs();
@@ -195,14 +206,14 @@ static falco::app::run_result do_inspect(
if(falco::app::g_terminate_signal.triggered())
{
falco::app::g_terminate_signal.handle([&](){
falco_logger::log(falco_logger::level::INFO, "SIGINT received, exiting...\n");
falco_logger::log(LOG_INFO, "SIGINT received, exiting...\n");
});
break;
}
else if(falco::app::g_restart_signal.triggered())
{
falco::app::g_restart_signal.handle([&s](){
falco_logger::log(falco_logger::level::INFO, "SIGHUP received, restarting...\n");
falco_logger::log(LOG_INFO, "SIGHUP received, restarting...\n");
s.restart.store(true);
});
break;
@@ -322,7 +333,14 @@ static falco::app::run_result do_inspect(
{
for(auto& rule_res : *res.get())
{
s.outputs->handle_event(rule_res.evt, rule_res.rule, rule_res.source, rule_res.priority_num, rule_res.format, rule_res.tags);
if (!rate_limiter_enabled || rate_limiter.claim())
{
s.outputs->handle_event(rule_res.evt, rule_res.rule, rule_res.source, rule_res.priority_num, rule_res.format, rule_res.tags);
}
else
{
falco_logger::log(LOG_DEBUG, "Skipping rate-limited notification for rule " + rule_res.rule + "\n");
}
}
}
@@ -348,7 +366,7 @@ static void process_inspector_events(
syscall_evt_drop_mgr sdropmgr;
bool is_capture_mode = source.empty();
bool check_drops_timeouts = is_capture_mode
|| (source == falco_common::syscall_source && !s.is_gvisor());
|| (source == falco_common::syscall_source && !s.is_gvisor_enabled());
duration = ((double)clock()) / CLOCKS_PER_SEC;
@@ -418,7 +436,7 @@ static falco::app::run_result init_stats_writer(
return falco::app::run_result::fatal("Metrics are enabled with no output configured. Please enable at least one output channel");
}
falco_logger::log(falco_logger::level::INFO, "Setting metrics interval to " + config->m_metrics_interval_str + ", equivalent to " + std::to_string(config->m_metrics_interval) + " (ms)\n");
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();
if (is_dry_run)
@@ -441,7 +459,7 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping event processing in dry-run\n");
falco_logger::log(LOG_DEBUG, "Skipping event processing in dry-run\n");
return res;
}
@@ -496,7 +514,7 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
try
{
falco_logger::log(falco_logger::level::DEBUG, "Opening event source '" + source + "'\n");
falco_logger::log(LOG_DEBUG, "Opening event source '" + source + "'\n");
termination_sem.acquire();
res = open_live_inspector(s, src_info->inspector, source);
if (!res.success)
@@ -542,7 +560,7 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
{
if (!res.success && !termination_forced)
{
falco_logger::log(falco_logger::level::INFO, "An error occurred in an event source, forcing termination...\n");
falco_logger::log(LOG_INFO, "An error occurred in an event source, forcing termination...\n");
falco::app::g_terminate_signal.trigger();
falco::app::g_terminate_signal.handle([&](){});
termination_forced = true;
@@ -573,7 +591,7 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
ctx.thread->join();
}
falco_logger::log(falco_logger::level::DEBUG, "Closing event source '" + ctx.source + "'\n");
falco_logger::log(LOG_DEBUG, "Closing event source '" + ctx.source + "'\n");
s.source_infos.at(ctx.source)->inspector->close();
res = run_result::merge(res, ctx.res);

View File

@@ -32,11 +32,11 @@ falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state&
{
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping starting gRPC server in dry-run\n");
falco_logger::log(LOG_DEBUG, "Skipping starting gRPC server in dry-run\n");
return run_result::ok();
}
falco_logger::log(falco_logger::level::INFO, "gRPC server threadiness equals to " + std::to_string(s.config->m_grpc_threadiness) + "\n");
falco_logger::log(LOG_INFO, "gRPC server threadiness equals to " + std::to_string(s.config->m_grpc_threadiness) + "\n");
// TODO(fntlnz,leodido): when we want to spawn multiple threads we need to have a queue per thread, or implement
// different queuing mechanisms, round robin, fanout? What we want to achieve?
s.grpc_server.init(
@@ -62,7 +62,7 @@ falco::app::run_result falco::app::actions::stop_grpc_server(falco::app::state&
{
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping stopping gRPC server in dry-run\n");
falco_logger::log(LOG_DEBUG, "Skipping stopping gRPC server in dry-run\n");
return run_result::ok();
}

View File

@@ -31,16 +31,14 @@ falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s
{
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping starting webserver in dry-run\n");
falco_logger::log(LOG_DEBUG, "Skipping starting webserver in dry-run\n");
return run_result::ok();
}
std::string ssl_option = (s.config->m_webserver_ssl_enabled ? " (SSL)" : "");
falco_logger::log(falco_logger::level::INFO, "Starting health webserver with threadiness "
falco_logger::log(LOG_INFO, "Starting health webserver with threadiness "
+ std::to_string(s.config->m_webserver_threadiness)
+ ", listening on "
+ s.config->m_webserver_listen_address
+ ":"
+ ", listening on port "
+ std::to_string(s.config->m_webserver_listen_port)
+ ssl_option + "\n");
@@ -48,7 +46,6 @@ falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s
s.offline_inspector,
s.config->m_webserver_threadiness,
s.config->m_webserver_listen_port,
s.config->m_webserver_listen_address,
s.config->m_webserver_k8s_healthz_endpoint,
s.config->m_webserver_ssl_certificate,
s.config->m_webserver_ssl_enabled);
@@ -64,7 +61,7 @@ falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& s)
{
if (s.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping stopping webserver in dry-run\n");
falco_logger::log(LOG_DEBUG, "Skipping stopping webserver in dry-run\n");
return run_result::ok();
}

View File

@@ -66,10 +66,10 @@ falco::app::run_result falco::app::actions::validate_rules_files(falco::app::sta
// printed when verbose is true.
std::string summary;
falco_logger::log(falco_logger::level::INFO, "Validating rules file(s):\n");
falco_logger::log(LOG_INFO, "Validating rules file(s):\n");
for(auto file : s.options.validate_rules_filenames)
{
falco_logger::log(falco_logger::level::INFO, " " + file + "\n");
falco_logger::log(LOG_INFO, " " + file + "\n");
}
// The json output encompasses all files so the

View File

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

View File

@@ -32,11 +32,15 @@ namespace app {
// initialize their linked variables.
options::options()
: event_buffer_format(sinsp_evt::PF_NORMAL),
gvisor_config(""),
list_fields(false),
list_plugins(false),
list_syscall_events(false),
markdown(false),
dry_run(false)
userspace(false),
modern_bpf(false),
dry_run(false),
nodriver(false)
{
}
@@ -134,13 +138,26 @@ bool options::parse(int argc, char **argv, std::string &errstr)
// You can't both disable and enable rules
if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) &&
!enabled_rule_tags.empty())
enabled_rule_tags.size() > 0)
{
errstr = std::string("You can not specify both disabled (-D/-T) and enabled (-t) rules");
return false;
}
list_fields = m_cmdline_parsed.count("list") > 0;
list_fields = m_cmdline_parsed.count("list") > 0 ? true : false;
int open_modes = 0;
open_modes += !trace_filename.empty();
open_modes += userspace;
open_modes += !gvisor_config.empty();
open_modes += modern_bpf;
open_modes += getenv("FALCO_BPF_PROBE") != NULL;
open_modes += nodriver;
if (open_modes > 1)
{
errstr = std::string("You can not specify more than one of -e, -u (--userspace), -g (--gvisor-config), --modern-bpf, --nodriver, and the FALCO_BPF_PROBE env var");
return false;
}
return true;
}
@@ -168,17 +185,22 @@ void options::define(cxxopts::Options& opts)
("disable-source", "Turn off a specific <event_source>. By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times, but turning off all event sources simultaneously is not permitted. This option can not be mixed with --enable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(disable_sources), "<event_source>")
("dry-run", "Run Falco without processing events. It can help check that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false"))
("D", "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>")
("e", "DEPRECATED. 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(capture_file), "<events_file>")
("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
("g,gvisor-config", "DEPRECATED. 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>")
("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 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", "DEPRECATED. 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>")
("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
#ifdef HAS_MODERN_BPF
("modern-bpf", "DEPRECATED. Use the BPF modern probe driver to instrument the kernel and observe 'syscall' events.", 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
("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"))
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
("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 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", "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
("L", "Show the name and description of all rules and exit. If json_output is set to true, it prints details about all rules, macros, and lists in JSON format.", cxxopts::value(describe_all_rules)->default_value("false"))
("l", "Show the name and description of the rule specified <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 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>")
@@ -187,7 +209,7 @@ void options::define(cxxopts::Options& opts)
("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-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", "DEPRECATED. 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"))
("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>")
@@ -198,6 +220,9 @@ void options::define(cxxopts::Options& opts)
("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
("V,validate", "Read the contents of the specified <rules_file> file(s), validate the loaded rules, and exit. This option can be passed multiple times to validate multiple files.", cxxopts::value(validate_rules_filenames), "<rules_file>")
("v", "Enable verbose output.", cxxopts::value(verbose)->default_value("false"))
("version", "Print version information and exit.", cxxopts::value(print_version_info)->default_value("false"))

View File

@@ -47,7 +47,13 @@ public:
std::vector<std::string> disable_sources;
std::vector<std::string> disabled_rule_substrings;
std::vector<std::string> enable_sources;
std::string trace_filename;
std::string gvisor_config;
std::string gvisor_generate_config_with_socket;
std::string gvisor_root;
std::string k8s_api;
std::string k8s_api_cert;
std::string k8s_node_name;
bool describe_all_rules;
std::string describe_rule;
bool print_ignored_events;
@@ -69,19 +75,14 @@ public:
std::set<std::string> disabled_rule_tags;
std::set<std::string> enabled_rule_tags;
bool unbuffered_outputs;
bool userspace;
std::vector<std::string> validate_rules_filenames;
bool verbose;
bool print_version_info;
bool print_page_size;
bool modern_bpf;
bool dry_run;
// todo!: remove them in Falco 0.38.0 since they are deprecated
std::string capture_file = "";
std::string gvisor_config = "";
std::string gvisor_root = "";
bool modern_bpf = false;
bool nodriver = false;
bool nodriver;
bool parse(int argc, char **argv, std::string &errstr);

View File

@@ -21,15 +21,9 @@ limitations under the License.
#include <string.h>
#include <fcntl.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#ifdef __linux__
#include <sys/inotify.h>
#include <sys/select.h>
#endif
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30
#include <sys/syscall.h>
@@ -66,7 +60,7 @@ bool falco::app::restart_handler::start(std::string& err)
err = "could not watch file: " + f;
return false;
}
falco_logger::log(falco_logger::level::DEBUG, "Watching file '" + f +"'\n");
falco_logger::log(LOG_DEBUG, "Watching file '" + f +"'\n");
}
for (const auto &f : m_watched_dirs)
@@ -77,7 +71,7 @@ bool falco::app::restart_handler::start(std::string& err)
err = "could not watch directory: " + f;
return false;
}
falco_logger::log(falco_logger::level::DEBUG, "Watching directory '" + f +"'\n");
falco_logger::log(LOG_DEBUG, "Watching directory '" + f +"'\n");
}
// launch the watcher thread
@@ -99,12 +93,11 @@ void falco::app::restart_handler::stop()
void falco::app::restart_handler::watcher_loop() noexcept
{
#ifdef __linux__
if (fcntl(m_inotify_fd, F_SETOWN, gettid()) < 0)
{
// an error occurred, we can't recover
// todo(jasondellaluce): should we terminate the process?
falco_logger::log(falco_logger::level::ERR, "Failed owning inotify handler, shutting down watcher...");
falco_logger::log(LOG_ERR, "Failed owning inotify handler, shutting down watcher...");
return;
}
@@ -129,7 +122,7 @@ void falco::app::restart_handler::watcher_loop() noexcept
{
// an error occurred, we can't recover
// todo(jasondellaluce): should we terminate the process?
falco_logger::log(falco_logger::level::ERR, "Failed select with inotify handler, shutting down watcher...");
falco_logger::log(LOG_ERR, "Failed select with inotify handler, shutting down watcher...");
return;
}
@@ -190,7 +183,7 @@ void falco::app::restart_handler::watcher_loop() noexcept
{
// an error occurred, we can't recover
// todo(jasondellaluce): should we terminate the process?
falco_logger::log(falco_logger::level::ERR, "Failed read with inotify handler, shutting down watcher...");
falco_logger::log(LOG_ERR, "Failed read with inotify handler, shutting down watcher...");
return;
}
// this is an odd case, but if we got here with
@@ -214,5 +207,4 @@ void falco::app::restart_handler::watcher_loop() noexcept
// next timeout.
should_check = true;
}
#endif
}

View File

@@ -147,75 +147,18 @@ struct state
inline bool is_capture_mode() const
{
return config->m_engine_mode == engine_kind_t::REPLAY;
return !options.trace_filename.empty();
}
inline bool is_gvisor() const
inline bool is_gvisor_enabled() const
{
return config->m_engine_mode == engine_kind_t::GVISOR;
return !options.gvisor_config.empty();
}
inline bool is_ebpf() const
{
return config->m_engine_mode == engine_kind_t::EBPF;
}
inline bool is_modern_ebpf() const
{
return config->m_engine_mode == engine_kind_t::MODERN_EBPF;
}
inline bool is_nodriver() const
{
return config->m_engine_mode == engine_kind_t::NONE;
}
inline bool is_source_enabled(const std::string& src) const
{
return enabled_sources.find(falco_common::syscall_source) != enabled_sources.end();
}
inline bool is_driver_drop_failed_exit_enabled() const
{
bool drop_failed;
switch (config->m_engine_mode)
{
case engine_kind_t::KMOD:
drop_failed = config->m_kmod.m_drop_failed_exit;
break;
case engine_kind_t::EBPF:
drop_failed = config->m_ebpf.m_drop_failed_exit;
break;
case engine_kind_t::MODERN_EBPF:
drop_failed = config->m_modern_ebpf.m_drop_failed_exit;
break;
default:
drop_failed = false;
break;
}
return drop_failed;
}
inline int16_t driver_buf_size_preset() const
{
int16_t index;
switch (config->m_engine_mode) {
case engine_kind_t::KMOD:
index = config->m_kmod.m_buf_size_preset;
break;
case engine_kind_t::EBPF:
index = config->m_ebpf.m_buf_size_preset;
break;
case engine_kind_t::MODERN_EBPF:
index = config->m_modern_ebpf.m_buf_size_preset;
break;
default:
// unsupported
index = - 1;
break;
}
return index;
}
};
}; // namespace app

View File

@@ -22,28 +22,22 @@ limitations under the License.
#include <string>
#include <unordered_set>
#include <filesystem>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "falco_utils.h"
#include "configuration.h"
#include "logger.h"
#include <re2/re2.h>
namespace fs = std::filesystem;
// Reference: https://digitalfortress.tech/tips/top-15-commonly-used-regex/
static re2::RE2 ip_address_re("((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))");
#include "banned.h" // This raises a compilation error when certain functions are used
falco_configuration::falco_configuration():
m_json_output(false),
m_json_include_output_property(true),
m_json_include_tags_property(true),
m_notifications_rate(0),
m_notifications_max_burst(1000),
m_rule_matching(falco_common::rule_matching::FIRST),
m_watch_config_files(true),
m_buffered_outputs(false),
@@ -55,7 +49,6 @@ falco_configuration::falco_configuration():
m_webserver_enabled(false),
m_webserver_threadiness(0),
m_webserver_listen_port(8765),
m_webserver_listen_address("0.0.0.0"),
m_webserver_k8s_healthz_endpoint("/healthz"),
m_webserver_ssl_enabled(false),
m_syscall_evt_drop_threshold(.1),
@@ -63,6 +56,12 @@ falco_configuration::falco_configuration():
m_syscall_evt_drop_max_burst(1),
m_syscall_evt_simulate_drops(false),
m_syscall_evt_timeout_max_consecutives(1000),
m_metadata_download_max_mb(100),
m_metadata_download_chunk_wait_us(1000),
m_metadata_download_watch_freq_sec(1),
m_syscall_buf_size_preset(4),
m_cpus_for_each_syscall_buffer(2),
m_syscall_drop_failed_exit(false),
m_base_syscalls_repair(false),
m_metrics_enabled(false),
m_metrics_interval_str("5000"),
@@ -75,6 +74,7 @@ falco_configuration::falco_configuration():
m_metrics_convert_memory_to_mb(true),
m_metrics_include_empty_values(false)
{
init({});
}
void falco_configuration::init(const std::vector<std::string>& cmdline_options)
@@ -102,94 +102,8 @@ void falco_configuration::init(const std::string& conf_filename, const std::vect
load_yaml(conf_filename, config);
}
void falco_configuration::load_engine_config(const std::string& config_name, const yaml_helper& config)
{
// Set driver mode if not already set.
const std::unordered_map<std::string, engine_kind_t> engine_mode_lut = {
{"kmod",engine_kind_t::KMOD},
{"ebpf",engine_kind_t::EBPF},
{"modern_ebpf",engine_kind_t::MODERN_EBPF},
{"replay",engine_kind_t::REPLAY},
{"gvisor",engine_kind_t::GVISOR},
{"none",engine_kind_t::NONE},
};
auto driver_mode_str = config.get_scalar<std::string>("engine.kind", "kmod");
if (engine_mode_lut.find(driver_mode_str) != engine_mode_lut.end())
{
m_engine_mode = engine_mode_lut.at(driver_mode_str);
}
else
{
throw std::logic_error("Error reading config file (" + config_name + "): engine.kind '"+ driver_mode_str + "' is not a valid kind.");
}
// Catch deprecated values from the config, to use them with the command line if needed
m_syscall_buf_size_preset = config.get_scalar<int16_t>("syscall_buf_size_preset", DEFAULT_BUF_SIZE_PRESET);
m_cpus_for_each_syscall_buffer = config.get_scalar<uint16_t>("modern_bpf.cpus_for_each_syscall_buffer", DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER);
m_syscall_drop_failed_exit = config.get_scalar<bool>("syscall_drop_failed_exit", DEFAULT_DROP_FAILED_EXIT);
switch (m_engine_mode)
{
case engine_kind_t::KMOD:
m_kmod.m_buf_size_preset = config.get_scalar<int16_t>("engine.kmod.buf_size_preset", DEFAULT_BUF_SIZE_PRESET);
m_kmod.m_drop_failed_exit = config.get_scalar<bool>("engine.kmod.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT);
if(m_kmod.m_buf_size_preset == DEFAULT_BUF_SIZE_PRESET && m_kmod.m_drop_failed_exit==DEFAULT_DROP_FAILED_EXIT)
{
// This could happen in 2 cases:
// 1. The user doesn't use the new config (it could also have commented it)
// 2. The user uses the new config unchanged.
// In these 2 cases the users are allowed to use the command line arguments to open an engine
m_changes_in_engine_config = false;
return;
}
break;
case engine_kind_t::EBPF:
// TODO: default value for `probe` should be $HOME/FALCO_PROBE_BPF_FILEPATH,
// to be done once we drop the CLI option otherwise we would need to make the check twice,
// once here, and once when we merge the CLI options in the config file.
m_ebpf.m_probe_path = config.get_scalar<std::string>("engine.ebpf.probe", "");
m_ebpf.m_buf_size_preset = config.get_scalar<int16_t>("engine.ebpf.buf_size_preset", DEFAULT_BUF_SIZE_PRESET);
m_ebpf.m_drop_failed_exit = config.get_scalar<bool>("engine.ebpf.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT);
break;
case engine_kind_t::MODERN_EBPF:
m_modern_ebpf.m_cpus_for_each_buffer = config.get_scalar<uint16_t>("engine.modern_ebpf.cpus_for_each_buffer", DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER);
m_modern_ebpf.m_buf_size_preset = config.get_scalar<int16_t>("engine.modern_ebpf.buf_size_preset", DEFAULT_BUF_SIZE_PRESET);
m_modern_ebpf.m_drop_failed_exit = config.get_scalar<bool>("engine.modern_ebpf.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT);
break;
case engine_kind_t::REPLAY:
m_replay.m_capture_file = config.get_scalar<std::string>("engine.replay.capture_file", "");
if (m_replay.m_capture_file.empty())
{
throw std::logic_error("Error reading config file (" + config_name + "): engine.kind is 'replay' but no engine.replay.capture_file specified.");
}
break;
case engine_kind_t::GVISOR:
m_gvisor.m_config = config.get_scalar<std::string>("engine.gvisor.config", "");
if (m_gvisor.m_config.empty())
{
throw std::logic_error("Error reading config file (" + config_name + "): engine.kind is 'gvisor' but no engine.gvisor.config specified.");
}
m_gvisor.m_root = config.get_scalar<std::string>("engine.gvisor.root", "");
break;
case engine_kind_t::NONE:
default:
break;
}
// If we arrive here it means we have at least one change in the `engine` config.
// Please note that `load_config` could be called more than one time during initialization
// so the last time wins, the load config phase should be idempotent
m_changes_in_engine_config = true;
}
void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config)
{
load_engine_config(config_name, config);
m_log_level = config.get_scalar<std::string>("log_level", "info");
std::list<std::string> rules_files;
config.get_sequence<std::list<std::string>>(rules_files, std::string("rules_file"));
@@ -349,6 +263,13 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
m_output_timeout = config.get_scalar<uint32_t>("output_timeout", 2000);
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);
std::string rule_matching = config.get_scalar<std::string>("rule_matching", "first");
if (!falco_common::parse_rule_matching(rule_matching, m_rule_matching))
{
@@ -374,12 +295,6 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
m_webserver_enabled = config.get_scalar<bool>("webserver.enabled", false);
m_webserver_threadiness = config.get_scalar<uint32_t>("webserver.threadiness", 0);
m_webserver_listen_port = config.get_scalar<uint32_t>("webserver.listen_port", 8765);
m_webserver_listen_address = config.get_scalar<std::string>("webserver.listen_address", "0.0.0.0");
if(!re2::RE2::FullMatch(m_webserver_listen_address, ip_address_re))
{
throw std::logic_error("Error reading config file (" + config_name + "): webserver listen address \"" + m_webserver_listen_address + "\" is not a valid IP address");
}
m_webserver_k8s_healthz_endpoint = config.get_scalar<std::string>("webserver.k8s_healthz_endpoint", "/healthz");
m_webserver_ssl_enabled = config.get_scalar<bool>("webserver.ssl_enabled", false);
m_webserver_ssl_certificate = config.get_scalar<std::string>("webserver.ssl_certificate", "/etc/falco/falco.pem");
@@ -396,11 +311,11 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
{
if(act == "ignore")
{
m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::DISREGARD);
m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::IGNORE);
}
else if(act == "log")
{
if(m_syscall_evt_drop_actions.count(syscall_evt_drop_action::DISREGARD))
if(m_syscall_evt_drop_actions.count(syscall_evt_drop_action::IGNORE))
{
throw std::logic_error("Error reading config file (" + config_name + "): syscall event drop action \"" + act + "\" does not make sense with the \"ignore\" action");
}
@@ -408,7 +323,7 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
}
else if(act == "alert")
{
if(m_syscall_evt_drop_actions.count(syscall_evt_drop_action::DISREGARD))
if(m_syscall_evt_drop_actions.count(syscall_evt_drop_action::IGNORE))
{
throw std::logic_error("Error reading config file (" + config_name + "): syscall event drop action \"" + act + "\" does not make sense with the \"ignore\" action");
}
@@ -426,7 +341,7 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
if(m_syscall_evt_drop_actions.empty())
{
m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::DISREGARD);
m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::IGNORE);
}
m_syscall_evt_drop_threshold = config.get_scalar<double>("syscall_event_drops.threshold", .1);
@@ -444,6 +359,27 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
throw std::logic_error("Error reading config file(" + config_name + "): the maximum consecutive timeouts without an event must be an unsigned integer > 0");
}
m_metadata_download_max_mb = config.get_scalar<uint32_t>("metadata_download.max_mb", 100);
if(m_metadata_download_max_mb > 1024)
{
throw std::logic_error("Error reading config file(" + config_name + "): metadata download maximum size should be < 1024 Mb");
}
m_metadata_download_chunk_wait_us = config.get_scalar<uint32_t>("metadata_download.chunk_wait_us", 1000);
m_metadata_download_watch_freq_sec = config.get_scalar<uint32_t>("metadata_download.watch_freq_sec", 1);
if(m_metadata_download_watch_freq_sec == 0)
{
throw std::logic_error("Error reading config file(" + config_name + "): metadata download watch frequency seconds must be an unsigned integer > 0");
}
/* We put this value in the configuration file because in this way we can change the dimension at every reload.
* The default value is `4` -> 8 MB.
*/
m_syscall_buf_size_preset = config.get_scalar<uint16_t>("syscall_buf_size_preset", 4);
m_cpus_for_each_syscall_buffer = config.get_scalar<uint16_t>("modern_bpf.cpus_for_each_syscall_buffer", 2);
m_syscall_drop_failed_exit = config.get_scalar<bool>("syscall_drop_failed_exit", false);
m_base_syscalls_custom_set.clear();
config.get_sequence<std::unordered_set<std::string>>(m_base_syscalls_custom_set, std::string("base_syscalls.custom_set"));
m_base_syscalls_repair = config.get_scalar<bool>("base_syscalls.repair", false);
@@ -462,6 +398,7 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
std::vector<std::string> load_plugins;
bool load_plugins_node_defined = config.is_defined("load_plugins");
config.get_sequence<std::vector<std::string>>(load_plugins, "load_plugins");
std::list<falco_configuration::plugin_config> plugins;
@@ -514,9 +451,17 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
void falco_configuration::read_rules_file_directory(const std::string &path, std::list<std::string> &rules_filenames, std::list<std::string> &rules_folders)
{
fs::path rules_path = std::string(path);
struct stat st;
if(fs::is_directory(rules_path))
int rc = stat(path.c_str(), &st);
if(rc != 0)
{
std::cerr << "Could not get info on rules file " << path << ": " << strerror(errno) << std::endl;
exit(-1);
}
if(st.st_mode & S_IFDIR)
{
rules_folders.push_back(path);
@@ -525,17 +470,34 @@ void falco_configuration::read_rules_file_directory(const std::string &path, std
// rules_filenames
std::vector<std::string> dir_filenames;
const auto it_options = fs::directory_options::follow_directory_symlink
| fs::directory_options::follow_directory_symlink;
DIR *dir = opendir(path.c_str());
for (auto const& dir_entry : fs::directory_iterator(rules_path, it_options))
if(!dir)
{
if(std::filesystem::is_regular_file(dir_entry.path()))
std::cerr << "Could not get read contents of directory " << path << ": " << strerror(errno) << std::endl;
exit(-1);
}
for(struct dirent *ent = readdir(dir); ent; ent = readdir(dir))
{
std::string efile = path + "/" + ent->d_name;
rc = stat(efile.c_str(), &st);
if(rc != 0)
{
dir_filenames.push_back(dir_entry.path().string());
std::cerr << "Could not get info on rules file " << efile << ": " << strerror(errno) << std::endl;
exit(-1);
}
if(st.st_mode & S_IFREG)
{
dir_filenames.push_back(efile);
}
}
closedir(dir);
std::sort(dir_filenames.begin(),
dir_filenames.end());

View File

@@ -19,11 +19,7 @@ limitations under the License.
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include <yaml-cpp/yaml.h>
#include <string>
#include <vector>
@@ -37,21 +33,6 @@ limitations under the License.
#include "event_drops.h"
#include "falco_outputs.h"
// todo!: remove them in Falco 0.38.0
#define DEFAULT_BUF_SIZE_PRESET 4
#define DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER 2
#define DEFAULT_DROP_FAILED_EXIT false
enum class engine_kind_t : uint8_t
{
KMOD,
EBPF,
MODERN_EBPF,
REPLAY,
GVISOR,
NONE
};
class falco_configuration
{
public:
@@ -64,37 +45,6 @@ public:
std::string m_open_params;
} plugin_config;
typedef struct {
public:
int16_t m_buf_size_preset;
bool m_drop_failed_exit;
} kmod_config;
typedef struct {
public:
std::string m_probe_path;
int16_t m_buf_size_preset;
bool m_drop_failed_exit;
} ebpf_config;
typedef struct {
public:
uint16_t m_cpus_for_each_buffer;
int16_t m_buf_size_preset;
bool m_drop_failed_exit;
} modern_ebpf_config;
typedef struct {
public:
std::string m_capture_file;
} replay_config;
typedef struct {
public:
std::string m_config;
std::string m_root;
} gvisor_config;
falco_configuration();
virtual ~falco_configuration() = default;
@@ -109,11 +59,14 @@ public:
std::list<std::string> m_loaded_rules_filenames;
// List of loaded rule folders
std::list<std::string> m_loaded_rules_folders;
bool m_json_output;
bool m_json_include_output_property;
bool m_json_include_tags_property;
std::string m_log_level;
std::vector<falco::outputs::config> m_outputs;
uint32_t m_notifications_rate;
uint32_t m_notifications_max_burst;
falco_common::priority_type m_min_priority;
falco_common::rule_matching m_rule_matching;
@@ -134,7 +87,6 @@ public:
bool m_webserver_enabled;
uint32_t m_webserver_threadiness;
uint32_t m_webserver_listen_port;
std::string m_webserver_listen_address;
std::string m_webserver_k8s_healthz_endpoint;
bool m_webserver_ssl_enabled;
std::string m_webserver_ssl_certificate;
@@ -148,6 +100,18 @@ public:
uint32_t m_syscall_evt_timeout_max_consecutives;
uint32_t m_metadata_download_max_mb;
uint32_t m_metadata_download_chunk_wait_us;
uint32_t m_metadata_download_watch_freq_sec;
// Index corresponding to the syscall buffer dimension.
uint16_t m_syscall_buf_size_preset;
// Number of CPUs associated with a single ring buffer.
uint16_t m_cpus_for_each_syscall_buffer;
bool m_syscall_drop_failed_exit;
// User supplied base_syscalls, overrides any Falco state engine enforcement.
std::unordered_set<std::string> m_base_syscalls_custom_set;
bool m_base_syscalls_repair;
@@ -163,30 +127,12 @@ public:
bool m_metrics_libbpf_stats_enabled;
bool m_metrics_convert_memory_to_mb;
bool m_metrics_include_empty_values;
std::vector<plugin_config> m_plugins;
// Falco engine
engine_kind_t m_engine_mode = engine_kind_t::KMOD;
kmod_config m_kmod = {};
ebpf_config m_ebpf = {};
modern_ebpf_config m_modern_ebpf = {};
replay_config m_replay = {};
gvisor_config m_gvisor = {};
// todo!: to remove in Falco 0.38.0
// used to keep track if the `engine` config is used.
bool m_changes_in_engine_config = false;
// Index corresponding to the syscall buffer dimension.
uint16_t m_syscall_buf_size_preset = DEFAULT_BUF_SIZE_PRESET;
// Number of CPUs associated with a single ring buffer.
uint16_t m_cpus_for_each_syscall_buffer = DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER;
bool m_syscall_drop_failed_exit = DEFAULT_DROP_FAILED_EXIT;
private:
void load_yaml(const std::string& config_name, const yaml_helper& config);
void load_engine_config(const std::string& config_name, const yaml_helper& config);
void init_cmdline_options(yaml_helper& config, const std::vector<std::string>& cmdline_options);
/**

View File

@@ -17,6 +17,7 @@ limitations under the License.
#include "event_drops.h"
#include "falco_common.h"
#include "banned.h" // This raises a compilation error when certain functions are used
syscall_evt_drop_mgr::syscall_evt_drop_mgr():
m_num_syscall_evt_drops(0),
@@ -99,7 +100,7 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr<sinsp> inspector, sinsp
if(m_simulate_drops)
{
falco_logger::log(falco_logger::level::INFO, "Simulating syscall event drop");
falco_logger::log(LOG_INFO, "Simulating syscall event drop");
delta.n_drops++;
}
@@ -124,7 +125,7 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr<sinsp> inspector, sinsp
}
else
{
falco_logger::log(falco_logger::level::DEBUG, "Syscall event drop but token bucket depleted, skipping actions");
falco_logger::log(LOG_DEBUG, "Syscall event drop but token bucket depleted, skipping actions");
}
}
}
@@ -149,11 +150,11 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, scap_stats &delta, bool
{
switch(act)
{
case syscall_evt_drop_action::DISREGARD:
case syscall_evt_drop_action::IGNORE:
return true;
case syscall_evt_drop_action::LOG:
falco_logger::log(falco_logger::level::DEBUG, std::move(msg));
falco_logger::log(LOG_DEBUG, std::move(msg));
return true;
case syscall_evt_drop_action::ALERT:
@@ -195,12 +196,12 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, scap_stats &delta, bool
return true;
}
case syscall_evt_drop_action::EXIT:
falco_logger::log(falco_logger::level::CRIT, std::move(msg));
falco_logger::log(falco_logger::level::CRIT, "Exiting.");
falco_logger::log(LOG_CRIT, std::move(msg));
falco_logger::log(LOG_CRIT, "Exiting.");
return false;
default:
falco_logger::log(falco_logger::level::ERR, "Ignoring unknown action " + std::to_string(int(act)));
falco_logger::log(LOG_ERR, "Ignoring unknown action " + std::to_string(int(act)));
return true;
}
}

View File

@@ -29,7 +29,7 @@ limitations under the License.
// detecting a syscall event drop.
enum class syscall_evt_drop_action : uint8_t
{
DISREGARD = 0,
IGNORE = 0,
LOG,
ALERT,
EXIT

View File

@@ -22,6 +22,7 @@ limitations under the License.
#include "app/app.h"
#include "logger.h"
#include "banned.h" // This raises a compilation error when certain functions are used
static void display_fatal_err(const std::string &&msg)
{
@@ -33,7 +34,7 @@ static void display_fatal_err(const std::string &&msg)
std::cerr << msg;
}
falco_logger::log(falco_logger::level::ERR, std::move(msg));
falco_logger::log(LOG_ERR, std::move(msg));
}
//

View File

@@ -27,16 +27,16 @@ limitations under the License.
#include "watchdog.h"
#include "outputs_file.h"
#include "outputs_stdout.h"
#if !defined(_WIN32)
#include "outputs_program.h"
#include "outputs_stdout.h"
#include "outputs_syslog.h"
#endif
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "outputs_http.h"
#include "outputs_grpc.h"
#endif
#include "banned.h" // This raises a compilation error when certain functions are used
static const char* s_internal_source = "internal";
falco_outputs::falco_outputs(
@@ -92,22 +92,18 @@ void falco_outputs::add_output(falco::outputs::config oc)
{
oo = new falco::outputs::output_file();
}
#ifndef _WIN32
else if(oc.name == "program")
{
oo = new falco::outputs::output_program();
}
#endif
else if(oc.name == "stdout")
{
oo = new falco::outputs::output_stdout();
}
#ifndef _WIN32
else if(oc.name == "syslog")
{
oo = new falco::outputs::output_syslog();
}
#endif
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
else if(oc.name == "http")
{
@@ -130,7 +126,7 @@ void falco_outputs::add_output(falco::outputs::config oc)
}
else
{
falco_logger::log(falco_logger::level::ERR, "Failed to init output: " + init_err);
falco_logger::log(LOG_ERR, "Failed to init output: " + init_err);
delete(oo);
}
}
@@ -262,7 +258,7 @@ void falco_outputs::stop_worker()
{
watchdog<void *> wd;
wd.start([&](void *) -> void {
falco_logger::log(falco_logger::level::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();
#endif
@@ -291,7 +287,7 @@ inline void falco_outputs::push(const ctrl_msg& cmsg)
{
if(m_outputs_queue_num_drops.load() == 0)
{
falco_logger::log(falco_logger::level::ERR, "Outputs queue out of memory. Drop event and continue on ...");
falco_logger::log(LOG_ERR, "Outputs queue out of memory. Drop event and continue on ...");
}
m_outputs_queue_num_drops++;
}
@@ -310,7 +306,7 @@ void falco_outputs::worker() noexcept
{
watchdog<std::string> wd;
wd.start([&](const std::string& payload) -> void {
falco_logger::log(falco_logger::level::CRIT, "\"" + payload + "\" output timeout, all output channels are blocked\n");
falco_logger::log(LOG_CRIT, "\"" + payload + "\" output timeout, all output channels are blocked\n");
});
auto timeout = m_timeout;
@@ -332,7 +328,7 @@ void falco_outputs::worker() noexcept
}
catch(const std::exception &e)
{
falco_logger::log(falco_logger::level::ERR, o->get_name() + ": " + std::string(e.what()) + "\n");
falco_logger::log(LOG_ERR, o->get_name() + ": " + std::string(e.what()) + "\n");
}
}
wd.cancel_timeout();
@@ -354,7 +350,7 @@ inline void falco_outputs::process_msg(falco::outputs::abstract_output* o, const
o->reopen();
break;
default:
falco_logger::log(falco_logger::level::DEBUG, "Outputs worker received an unknown message type\n");
falco_logger::log(LOG_DEBUG, "Outputs worker received an unknown message type\n");
}
}

View File

@@ -18,6 +18,7 @@ limitations under the License.
#include <sstream>
#include "grpc_context.h"
#include "banned.h" // This raises a compilation error when certain functions are used
falco::grpc::context::context(::grpc::ServerContext* ctx):
m_ctx(ctx)

View File

@@ -25,6 +25,7 @@ limitations under the License.
#include "grpc_server.h"
#include "grpc_request_context.h"
#include "falco_utils.h"
#include "banned.h" // This raises a compilation error when certain functions are used
#define REGISTER_STREAM(req, res, svc, rpc, impl, num) \
std::vector<request_stream_context<svc, req, res>> rpc##_contexts(num); \
@@ -55,17 +56,17 @@ limitations under the License.
static void gpr_log_dispatcher_func(gpr_log_func_args* args)
{
falco_logger::level priority;
int priority;
switch(args->severity)
{
case GPR_LOG_SEVERITY_ERROR:
priority = falco_logger::level::ERR;
priority = LOG_ERR;
break;
case GPR_LOG_SEVERITY_DEBUG:
priority = falco_logger::level::DEBUG;
priority = LOG_DEBUG;
break;
default:
priority = falco_logger::level::INFO;
priority = LOG_INFO;
break;
}
@@ -199,10 +200,10 @@ void falco::grpc::server::run()
m_server = m_server_builder.BuildAndStart();
if(m_server == nullptr)
{
falco_logger::log(falco_logger::level::EMERG, "Error starting gRPC server\n");
falco_logger::log(LOG_EMERG, "Error starting gRPC server\n");
return;
}
falco_logger::log(falco_logger::level::INFO, "Starting gRPC server at " + m_server_addr + "\n");
falco_logger::log(LOG_INFO, "Starting gRPC server at " + m_server_addr + "\n");
// The number of contexts is multiple of the number of threads
// This defines the number of simultaneous completion queue requests of the same type (service::AsyncService::Request##RPC)
@@ -229,10 +230,10 @@ void falco::grpc::server::run()
void falco::grpc::server::stop()
{
falco_logger::log(falco_logger::level::INFO, "Shutting down gRPC server. Waiting until external connections are closed by clients\n");
falco_logger::log(LOG_INFO, "Shutting down gRPC server. Waiting until external connections are closed by clients\n");
m_completion_queue->Shutdown();
falco_logger::log(falco_logger::level::INFO, "Waiting for the gRPC threads to complete\n");
falco_logger::log(LOG_INFO, "Waiting for the gRPC threads to complete\n");
for(std::thread& t : m_threads)
{
if(t.joinable())
@@ -242,7 +243,7 @@ void falco::grpc::server::stop()
}
m_threads.clear();
falco_logger::log(falco_logger::level::INFO, "Draining all the remaining gRPC events\n");
falco_logger::log(LOG_INFO, "Draining all the remaining gRPC events\n");
// Ignore remaining events
void* ignore_tag = nullptr;
bool ignore_ok = false;
@@ -250,5 +251,5 @@ void falco::grpc::server::stop()
{
}
falco_logger::log(falco_logger::level::INFO, "Shutting down gRPC server complete\n");
falco_logger::log(LOG_INFO, "Shutting down gRPC server complete\n");
}

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